typeomatica 0.3.2 → 0.3.3
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/.eslintrc.js +15 -19
- package/.github/workflows/node.js.yml +3 -3
- package/lib/fields.d.ts +1 -1
- package/lib/index.d.ts +7 -8
- package/lib/index.js +13 -9
- package/package.json +9 -8
- package/src/fields.ts +5 -5
- package/src/index.ts +48 -24
- package/test/addition.js +31 -30
- package/test/index.ts +103 -42
- package/tsconfig.jest.json +1 -1
package/.eslintrc.js
CHANGED
|
@@ -1,26 +1,23 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
+
parser: '@typescript-eslint/parser',
|
|
2
3
|
env: {
|
|
3
4
|
node: true,
|
|
4
5
|
es6: true,
|
|
5
6
|
},
|
|
6
|
-
extends: [
|
|
7
|
+
extends: [
|
|
8
|
+
'eslint:recommended',
|
|
9
|
+
'plugin:@typescript-eslint/eslint-recommended'
|
|
10
|
+
],
|
|
7
11
|
parserOptions: {
|
|
8
12
|
ecmaVersion: 2018,
|
|
13
|
+
sourceType: 'module'
|
|
9
14
|
},
|
|
10
15
|
rules: {
|
|
11
|
-
|
|
12
|
-
'key-spacing': [
|
|
13
|
-
'warn',
|
|
14
|
-
{
|
|
15
|
-
beforeColon: true,
|
|
16
|
-
afterColon: true,
|
|
17
|
-
align: 'colon',
|
|
18
|
-
},
|
|
19
|
-
],
|
|
16
|
+
indent: ['error', 'tab'],
|
|
20
17
|
'linebreak-style': ['error', 'unix'],
|
|
21
18
|
quotes: ['error', 'single'],
|
|
22
19
|
semi: ['error', 'always'],
|
|
23
|
-
'no-unused-vars': 'warn',
|
|
20
|
+
// 'no-unused-vars': 'warn',
|
|
24
21
|
'no-shadow': [
|
|
25
22
|
'error',
|
|
26
23
|
{
|
|
@@ -29,13 +26,13 @@ module.exports = {
|
|
|
29
26
|
allow: [],
|
|
30
27
|
},
|
|
31
28
|
],
|
|
32
|
-
'space-before-function-paren': [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
],
|
|
29
|
+
// 'space-before-function-paren': [
|
|
30
|
+
// 'warn', {
|
|
31
|
+
// 'anonymous': 'always',
|
|
32
|
+
// 'named': 'always',
|
|
33
|
+
// 'asyncArrow': 'always'
|
|
34
|
+
// }
|
|
35
|
+
// ],
|
|
39
36
|
'prefer-template': 'warn',
|
|
40
37
|
'prefer-spread': 'warn',
|
|
41
38
|
'no-useless-concat': 'warn',
|
|
@@ -60,7 +57,6 @@ module.exports = {
|
|
|
60
57
|
position: 'above',
|
|
61
58
|
},
|
|
62
59
|
],
|
|
63
|
-
quotes: ['error', 'single'],
|
|
64
60
|
yoda: 'warn',
|
|
65
61
|
},
|
|
66
62
|
'overrides': [
|
|
@@ -16,7 +16,7 @@ jobs:
|
|
|
16
16
|
|
|
17
17
|
strategy:
|
|
18
18
|
matrix:
|
|
19
|
-
node-version: [
|
|
19
|
+
node-version: [16.x, 18.x]
|
|
20
20
|
|
|
21
21
|
steps:
|
|
22
22
|
- uses: actions/checkout@v2
|
|
@@ -34,10 +34,10 @@ jobs:
|
|
|
34
34
|
|
|
35
35
|
steps:
|
|
36
36
|
- uses: actions/checkout@master
|
|
37
|
-
- name: Use Node.js
|
|
37
|
+
- name: Use Node.js 16.x
|
|
38
38
|
uses: actions/setup-node@master
|
|
39
39
|
with:
|
|
40
|
-
node-version:
|
|
40
|
+
node-version: 16.x
|
|
41
41
|
|
|
42
42
|
- name: npm install
|
|
43
43
|
run: npm install
|
package/lib/fields.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ interface FieldDefinition {
|
|
|
4
4
|
}
|
|
5
5
|
export declare class FieldConstructor implements FieldDefinition {
|
|
6
6
|
[SymbolInitialValue]: unknown;
|
|
7
|
-
get get(): (
|
|
7
|
+
get get(): () => unknown;
|
|
8
8
|
get set(): () => never;
|
|
9
9
|
constructor(value: unknown);
|
|
10
10
|
static get SymbolInitialValue(): symbol;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
export declare
|
|
1
|
+
type Proto<P, T> = Pick<P, Exclude<keyof P, keyof T>> & T;
|
|
2
|
+
export declare const BaseConstructorPrototype: <P extends object, S extends Proto<T, P>, T extends {
|
|
3
|
+
(): P;
|
|
4
|
+
new (): { [key in keyof S]: S[key]; };
|
|
5
|
+
}>(this: T, InstanceTarget?: P) => T;
|
|
6
|
+
export declare class BaseClass extends BaseConstructorPrototype {
|
|
3
7
|
}
|
|
4
|
-
export
|
|
5
|
-
new (...args: unknown[]): T;
|
|
6
|
-
(this: T, ...args: unknown[]): R;
|
|
7
|
-
prototype: P;
|
|
8
|
-
};
|
|
9
|
-
export {};
|
|
8
|
+
export { FieldConstructor } from './fields';
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BaseClass = void 0;
|
|
3
|
+
exports.FieldConstructor = exports.BaseClass = exports.BaseConstructorPrototype = void 0;
|
|
4
4
|
const errors_1 = require("./errors");
|
|
5
5
|
const types_1 = require("./types");
|
|
6
6
|
const fields_1 = require("./fields");
|
|
@@ -59,7 +59,8 @@ const handlers = {
|
|
|
59
59
|
}
|
|
60
60
|
if (prop === 'toJSON') {
|
|
61
61
|
return function () {
|
|
62
|
-
|
|
62
|
+
const entries = Object.entries(this);
|
|
63
|
+
return JSON.stringify(entries.reduce((obj, [key, value]) => {
|
|
63
64
|
obj[key] = value.valueOf();
|
|
64
65
|
return obj;
|
|
65
66
|
}, {}));
|
|
@@ -76,11 +77,11 @@ const handlers = {
|
|
|
76
77
|
},
|
|
77
78
|
};
|
|
78
79
|
const BaseTarget = Object.create(null);
|
|
79
|
-
const
|
|
80
|
+
const BaseConstructorPrototype = function (InstanceTarget = BaseTarget) {
|
|
80
81
|
if (!new.target) {
|
|
81
|
-
const self =
|
|
82
|
+
const self = exports.BaseConstructorPrototype.bind(this, InstanceTarget);
|
|
82
83
|
self.prototype = {
|
|
83
|
-
constructor:
|
|
84
|
+
constructor: exports.BaseConstructorPrototype
|
|
84
85
|
};
|
|
85
86
|
return self;
|
|
86
87
|
}
|
|
@@ -90,19 +91,22 @@ const BaseConstructor = function (InstanceTarget = BaseTarget) {
|
|
|
90
91
|
do {
|
|
91
92
|
protoPointer = Reflect.getPrototypeOf(protoPointer);
|
|
92
93
|
protoConstrcutor = Reflect.getOwnPropertyDescriptor(protoPointer, 'constructor').value;
|
|
93
|
-
} while (protoConstrcutor !==
|
|
94
|
+
} while (protoConstrcutor !== exports.BaseConstructorPrototype);
|
|
94
95
|
Reflect.setPrototypeOf(protoPointer, InstancePrototype);
|
|
96
|
+
return this;
|
|
95
97
|
};
|
|
98
|
+
exports.BaseConstructorPrototype = BaseConstructorPrototype;
|
|
96
99
|
Object.defineProperty(module, 'exports', {
|
|
97
100
|
get() {
|
|
98
|
-
return
|
|
101
|
+
return exports.BaseConstructorPrototype;
|
|
99
102
|
},
|
|
100
103
|
enumerable: true
|
|
101
104
|
});
|
|
102
|
-
class BaseClass extends
|
|
105
|
+
class BaseClass extends exports.BaseConstructorPrototype {
|
|
103
106
|
}
|
|
104
107
|
exports.BaseClass = BaseClass;
|
|
105
|
-
;
|
|
108
|
+
var fields_2 = require("./fields");
|
|
109
|
+
Object.defineProperty(exports, "FieldConstructor", { enumerable: true, get: function () { return fields_2.FieldConstructor; } });
|
|
106
110
|
Object.defineProperty(module.exports, 'BaseClass', {
|
|
107
111
|
get() {
|
|
108
112
|
return BaseClass;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typeomatica",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "type logic against javascript metaprogramming",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=14"
|
|
@@ -30,17 +30,18 @@
|
|
|
30
30
|
"url": "git+https://github.com/wentout/typeomatica.git"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@types/jest": "^29.5.
|
|
34
|
-
"@types/node": "^18.
|
|
35
|
-
"eslint": "^
|
|
33
|
+
"@types/jest": "^29.5.5",
|
|
34
|
+
"@types/node": "^18.18.4",
|
|
35
|
+
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
|
36
|
+
"@typescript-eslint/parser": "^6.7.4",
|
|
37
|
+
"eslint": "^8.51.0",
|
|
36
38
|
"husky": "^8.0.3",
|
|
37
|
-
"jest": "^29.
|
|
39
|
+
"jest": "^29.7.0",
|
|
38
40
|
"json5": "^2.2.3",
|
|
39
|
-
"lint-staged": "^13.
|
|
41
|
+
"lint-staged": "^13.3.0",
|
|
40
42
|
"set-value": "^4.1.0",
|
|
41
43
|
"ts-jest": "^29.1.1",
|
|
42
44
|
"ts-node": "^10.9.1",
|
|
43
|
-
"typescript": "^5.
|
|
44
|
-
"yarn": "^2.4.3"
|
|
45
|
+
"typescript": "^5.2.2"
|
|
45
46
|
}
|
|
46
47
|
}
|
package/src/fields.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
import { ErrorsNames } from './errors'
|
|
3
|
+
import { ErrorsNames } from './errors';
|
|
4
4
|
|
|
5
5
|
const SymbolInitialValue = Symbol('Initial Value');
|
|
6
6
|
|
|
@@ -18,17 +18,17 @@ interface FieldDefinition {
|
|
|
18
18
|
// } as ObjectConstructor;
|
|
19
19
|
|
|
20
20
|
export class FieldConstructor implements FieldDefinition {
|
|
21
|
-
[SymbolInitialValue]: unknown
|
|
21
|
+
[SymbolInitialValue]: unknown;
|
|
22
22
|
public get get () {
|
|
23
23
|
const self = this;
|
|
24
|
-
return function (this: FieldDefinition) {
|
|
24
|
+
return function (/* this: FieldDefinition */) {
|
|
25
25
|
return self[SymbolInitialValue];
|
|
26
|
-
}
|
|
26
|
+
};
|
|
27
27
|
}
|
|
28
28
|
public get set () {
|
|
29
29
|
return function () {
|
|
30
30
|
throw new TypeError(ErrorsNames.FORBIDDEN_RE);
|
|
31
|
-
}
|
|
31
|
+
};
|
|
32
32
|
}
|
|
33
33
|
constructor (value: unknown) {
|
|
34
34
|
this[SymbolInitialValue] = value;
|
package/src/index.ts
CHANGED
|
@@ -40,7 +40,7 @@ const resolver = Object.entries({
|
|
|
40
40
|
const result = handler.set(replacementValue);
|
|
41
41
|
return result;
|
|
42
42
|
}
|
|
43
|
-
}
|
|
43
|
+
};
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
return obj;
|
|
@@ -98,13 +98,15 @@ const handlers = {
|
|
|
98
98
|
return result;
|
|
99
99
|
}
|
|
100
100
|
if (prop === 'toJSON') {
|
|
101
|
+
// eslint-disable-next-line no-unused-vars
|
|
101
102
|
return function (this: typeof target) {
|
|
102
|
-
|
|
103
|
+
const entries = Object.entries(this);
|
|
104
|
+
return JSON.stringify(entries.reduce((obj, [key, value]) => {
|
|
103
105
|
// @ts-ignore
|
|
104
106
|
obj[key] = value.valueOf();
|
|
105
107
|
return obj;
|
|
106
108
|
}, {}));
|
|
107
|
-
}
|
|
109
|
+
};
|
|
108
110
|
}
|
|
109
111
|
// @ts-ignore
|
|
110
112
|
if (props2skip.has(prop)) {
|
|
@@ -125,43 +127,72 @@ const handlers = {
|
|
|
125
127
|
// user have to precisely define all props
|
|
126
128
|
const BaseTarget = Object.create(null);
|
|
127
129
|
|
|
128
|
-
|
|
130
|
+
type Proto<P, T> = Pick<P, Exclude<keyof P, keyof T>> & T;
|
|
129
131
|
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
+
|
|
133
|
+
export const BaseConstructorPrototype = function <
|
|
134
|
+
P extends object,
|
|
135
|
+
S extends Proto<T, P>,
|
|
136
|
+
T extends {
|
|
137
|
+
(): P
|
|
138
|
+
new (): {
|
|
139
|
+
[key in keyof S]: S[key]
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
>(
|
|
143
|
+
this: T,
|
|
144
|
+
InstanceTarget: P = BaseTarget
|
|
145
|
+
): T {
|
|
132
146
|
if (!new.target) {
|
|
133
|
-
|
|
147
|
+
|
|
148
|
+
const self: {
|
|
149
|
+
prototype: {
|
|
150
|
+
constructor: typeof BaseConstructorPrototype
|
|
151
|
+
}
|
|
152
|
+
} = BaseConstructorPrototype.bind(this, InstanceTarget);
|
|
153
|
+
|
|
134
154
|
self.prototype = {
|
|
135
|
-
constructor:
|
|
155
|
+
constructor: BaseConstructorPrototype
|
|
136
156
|
};
|
|
137
|
-
|
|
157
|
+
|
|
158
|
+
return self as T;
|
|
159
|
+
|
|
138
160
|
}
|
|
139
161
|
|
|
140
162
|
const InstancePrototype = new Proxy(InstanceTarget, handlers);
|
|
141
163
|
|
|
142
|
-
let protoPointer = this;
|
|
164
|
+
let protoPointer = this as object;
|
|
143
165
|
let protoConstrcutor;
|
|
144
166
|
do {
|
|
145
167
|
protoPointer = Reflect.getPrototypeOf(protoPointer) as object;
|
|
146
168
|
protoConstrcutor = Reflect.getOwnPropertyDescriptor(protoPointer, 'constructor')!.value;
|
|
147
|
-
} while (protoConstrcutor !==
|
|
169
|
+
} while (protoConstrcutor !== BaseConstructorPrototype);
|
|
170
|
+
|
|
148
171
|
Reflect.setPrototypeOf(protoPointer, InstancePrototype);
|
|
172
|
+
return this;
|
|
149
173
|
|
|
150
|
-
}
|
|
151
|
-
// } as IDEF;
|
|
174
|
+
};
|
|
152
175
|
|
|
153
|
-
//
|
|
176
|
+
// as ObjectConstructor & {
|
|
177
|
+
// (): void
|
|
178
|
+
// // eslint-disable-next-line no-unused-vars
|
|
179
|
+
// new<T>(param?: T extends object ? T : {}): {
|
|
180
|
+
// [key in keyof T]: T[key]
|
|
181
|
+
// }
|
|
182
|
+
// };
|
|
154
183
|
|
|
155
184
|
Object.defineProperty(module, 'exports', {
|
|
156
185
|
get() {
|
|
157
|
-
return
|
|
186
|
+
return BaseConstructorPrototype;
|
|
158
187
|
},
|
|
159
188
|
enumerable: true
|
|
160
189
|
});
|
|
161
190
|
|
|
191
|
+
|
|
192
|
+
// eslint-disable-next-line new-cap
|
|
162
193
|
// @ts-ignore
|
|
163
|
-
export class BaseClass extends
|
|
164
|
-
|
|
194
|
+
export class BaseClass extends BaseConstructorPrototype { }
|
|
195
|
+
export { FieldConstructor } from './fields';
|
|
165
196
|
|
|
166
197
|
Object.defineProperty(module.exports, 'BaseClass', {
|
|
167
198
|
get() {
|
|
@@ -175,10 +206,3 @@ Object.defineProperty(module.exports, 'FieldConstructor', {
|
|
|
175
206
|
},
|
|
176
207
|
enumerable: true
|
|
177
208
|
});
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
export type IDEF<T, P = {}, R = {}> = {
|
|
181
|
-
new(...args: unknown[]): T;
|
|
182
|
-
(this: T, ...args: unknown[]): R;
|
|
183
|
-
prototype: P;
|
|
184
|
-
};
|
package/test/addition.js
CHANGED
|
@@ -2,42 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
const BasePrototype = require('..');
|
|
4
4
|
|
|
5
|
+
// eslint-disable-next-line new-cap
|
|
5
6
|
class Base extends BasePrototype({
|
|
6
|
-
|
|
7
|
+
additionalProp: 321,
|
|
7
8
|
}) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
9
|
+
numberValue = 123;
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
this.stringValue = '123';
|
|
13
|
+
this.booleanValue = true;
|
|
14
|
+
this.objectValue = {};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
16
17
|
|
|
17
18
|
const baseInstance = new Base;
|
|
18
19
|
|
|
19
20
|
describe('props tests', () => {
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
22
|
+
test('base instance has props', () => {
|
|
23
|
+
expect(Object.keys(baseInstance)).toEqual(['numberValue', 'stringValue', 'booleanValue', 'objectValue']);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('JavaScript class fields allow re-definition', () => {
|
|
27
|
+
baseInstance.numberValue = '123';
|
|
28
|
+
expect(baseInstance.numberValue).toEqual('123');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('everything the rest is the same', () => {
|
|
32
|
+
expect(baseInstance.additionalProp).toEqual(321);
|
|
33
|
+
expect(() => {
|
|
34
|
+
baseInstance.stringValue = 123;
|
|
35
|
+
}).toThrow(new TypeError('Type Mismatch'));
|
|
36
|
+
expect(() => {
|
|
37
|
+
baseInstance.booleanValue = 123;
|
|
38
|
+
}).toThrow(new TypeError('Type Mismatch'));
|
|
39
|
+
expect(() => {
|
|
40
|
+
baseInstance.objectValue = null;
|
|
41
|
+
}).toThrow(new TypeError('Type Mismatch'));
|
|
42
|
+
});
|
|
42
43
|
|
|
43
44
|
});
|
package/test/index.ts
CHANGED
|
@@ -5,15 +5,14 @@ import { describe, expect, test } from '@jest/globals';
|
|
|
5
5
|
// BasePrototype & BaseClass are the same function
|
|
6
6
|
// go as you want for being meaningfull
|
|
7
7
|
// or meaningless
|
|
8
|
-
|
|
9
8
|
const BasePrototype = require('..');
|
|
10
|
-
|
|
11
|
-
import { BaseClass, IDEF, FieldConstructor } from '..';
|
|
9
|
+
import { BaseClass, FieldConstructor } from '..';
|
|
12
10
|
|
|
13
11
|
const { SymbolInitialValue } = FieldConstructor;
|
|
14
12
|
|
|
15
13
|
interface IBase {
|
|
16
14
|
get getterField(): string
|
|
15
|
+
// eslint-disable-next-line no-unused-vars
|
|
17
16
|
set setterField(value: string)
|
|
18
17
|
numberValue: number
|
|
19
18
|
stringValue: string
|
|
@@ -21,6 +20,27 @@ interface IBase {
|
|
|
21
20
|
objectValue: object
|
|
22
21
|
}
|
|
23
22
|
|
|
23
|
+
let decoratedSomeProp = 0;
|
|
24
|
+
// const s = BasePrototype({ someProp: 123 });
|
|
25
|
+
// console.log(s);
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
// eslint-disable-next-line new-cap
|
|
29
|
+
@BasePrototype({ someProp: 123 })
|
|
30
|
+
class DecoratedByBase {
|
|
31
|
+
someProp!: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class ExtendedDecoratedByBase extends DecoratedByBase {
|
|
35
|
+
someProp: number;
|
|
36
|
+
constructor() {
|
|
37
|
+
super();
|
|
38
|
+
this.someProp = 321;
|
|
39
|
+
decoratedSomeProp = this.someProp;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// eslint-disable-next-line new-cap
|
|
24
44
|
class Base extends BasePrototype({
|
|
25
45
|
additionalProp: 321,
|
|
26
46
|
someMethod() {
|
|
@@ -28,9 +48,9 @@ class Base extends BasePrototype({
|
|
|
28
48
|
},
|
|
29
49
|
}) implements IBase {
|
|
30
50
|
numberValue = 123;
|
|
31
|
-
stringValue: string
|
|
32
|
-
booleanValue: boolean
|
|
33
|
-
objectValue: object
|
|
51
|
+
stringValue: string;
|
|
52
|
+
booleanValue: boolean;
|
|
53
|
+
objectValue: object;
|
|
34
54
|
|
|
35
55
|
get getterField() {
|
|
36
56
|
const answer = `${this.stringValue}`;
|
|
@@ -46,6 +66,18 @@ class Base extends BasePrototype({
|
|
|
46
66
|
this.stringValue = '123';
|
|
47
67
|
this.booleanValue = true;
|
|
48
68
|
this.objectValue = {};
|
|
69
|
+
// ES2022
|
|
70
|
+
// Object.defineProperty(this, 'getterField', {
|
|
71
|
+
// get() {
|
|
72
|
+
// const answer = `${this.stringValue}`;
|
|
73
|
+
// return answer;
|
|
74
|
+
// }
|
|
75
|
+
// });
|
|
76
|
+
// Object.defineProperty(this, 'setterField', {
|
|
77
|
+
// set(value: string) {
|
|
78
|
+
// this.stringValue = value;
|
|
79
|
+
// }
|
|
80
|
+
// });
|
|
49
81
|
}
|
|
50
82
|
}
|
|
51
83
|
const baseInstance = new Base;
|
|
@@ -54,32 +86,45 @@ const upperInstance = Object.create(baseInstance);
|
|
|
54
86
|
|
|
55
87
|
class SimpleBase extends BaseClass {
|
|
56
88
|
stringProp = '123';
|
|
57
|
-
|
|
89
|
+
// ES2022
|
|
90
|
+
// stringProp: string;
|
|
91
|
+
// constructor() {
|
|
92
|
+
// super();
|
|
93
|
+
// this.stringProp = '123';
|
|
94
|
+
// }
|
|
95
|
+
}
|
|
58
96
|
const simpleInstance = new SimpleBase;
|
|
59
97
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
98
|
+
interface IFCstr<S> {
|
|
99
|
+
(): void
|
|
100
|
+
new(): {
|
|
101
|
+
[key in keyof S]: S[key]
|
|
102
|
+
}
|
|
103
|
+
}
|
|
63
104
|
|
|
64
|
-
|
|
65
|
-
|
|
105
|
+
type TmyFunctionalInstance = { stringProp: string }
|
|
106
|
+
// eslint-disable-next-line no-unused-vars
|
|
107
|
+
const MyFunctionalConstructor = function (this: TmyFunctionalInstance) {
|
|
66
108
|
this.stringProp = '123';
|
|
67
|
-
} as
|
|
109
|
+
} as IFCstr<TmyFunctionalInstance>;
|
|
68
110
|
|
|
69
111
|
Reflect.setPrototypeOf(MyFunctionalConstructor.prototype, new BasePrototype);
|
|
70
112
|
|
|
71
113
|
const myFunctionalInstance = new MyFunctionalConstructor();
|
|
72
114
|
|
|
73
|
-
class SecondaryExtend extends Base { second = 123 }
|
|
74
|
-
class TripleExtend extends SecondaryExtend { }
|
|
115
|
+
class SecondaryExtend extends Base { second = 123; }
|
|
116
|
+
class TripleExtend extends SecondaryExtend { }
|
|
75
117
|
const tiripleExtendInstance = new TripleExtend;
|
|
76
118
|
|
|
77
|
-
|
|
119
|
+
// eslint-disable-next-line new-cap
|
|
120
|
+
class NetworkedExtention extends BasePrototype(tiripleExtendInstance) { }
|
|
78
121
|
|
|
79
122
|
const networkedInstance = new NetworkedExtention;
|
|
80
123
|
|
|
81
|
-
|
|
82
|
-
class
|
|
124
|
+
// eslint-disable-next-line new-cap
|
|
125
|
+
class ExtendedArray extends BasePrototype([1, 2, 3]) { }
|
|
126
|
+
// eslint-disable-next-line new-cap
|
|
127
|
+
class ExtendedSet extends BasePrototype(new Set([1, 2, 3])) { }
|
|
83
128
|
|
|
84
129
|
const extendedArrayInstance = new ExtendedArray;
|
|
85
130
|
const extendedSetInstance = new ExtendedSet;
|
|
@@ -88,7 +133,7 @@ const MUTATION_VALUE = -2;
|
|
|
88
133
|
|
|
89
134
|
|
|
90
135
|
class MyFieldConstructorNoRe extends FieldConstructor {
|
|
91
|
-
_value: string
|
|
136
|
+
_value: string;
|
|
92
137
|
constructor(value: string) {
|
|
93
138
|
super(value);
|
|
94
139
|
Reflect.defineProperty(this, 'enumerable', {
|
|
@@ -108,7 +153,7 @@ class MyFieldConstructorReGet extends MyFieldConstructorNoRe {
|
|
|
108
153
|
get() {
|
|
109
154
|
return function () {
|
|
110
155
|
return self._value;
|
|
111
|
-
}
|
|
156
|
+
};
|
|
112
157
|
},
|
|
113
158
|
enumerable: true
|
|
114
159
|
});
|
|
@@ -123,9 +168,9 @@ class MyFieldConstructorReSet extends MyFieldConstructorNoRe {
|
|
|
123
168
|
});
|
|
124
169
|
Reflect.defineProperty(this, 'set', {
|
|
125
170
|
get() {
|
|
126
|
-
return function (
|
|
127
|
-
self._value =
|
|
128
|
-
}
|
|
171
|
+
return function (_value: string) {
|
|
172
|
+
self._value = _value;
|
|
173
|
+
};
|
|
129
174
|
},
|
|
130
175
|
enumerable: true
|
|
131
176
|
});
|
|
@@ -140,9 +185,9 @@ class MyFieldConstructor extends MyFieldConstructorReGet {
|
|
|
140
185
|
});
|
|
141
186
|
Reflect.defineProperty(this, 'set', {
|
|
142
187
|
get() {
|
|
143
|
-
return function (
|
|
144
|
-
self._value =
|
|
145
|
-
}
|
|
188
|
+
return function (_value: string) {
|
|
189
|
+
self._value = _value;
|
|
190
|
+
};
|
|
146
191
|
},
|
|
147
192
|
enumerable: true
|
|
148
193
|
});
|
|
@@ -154,35 +199,49 @@ const myFieldReGet = new MyFieldConstructorReGet('initial value for get check');
|
|
|
154
199
|
const myFieldReSet = new MyFieldConstructorReSet('initial value for set check');
|
|
155
200
|
|
|
156
201
|
class MadeFieldClass extends BaseClass {
|
|
157
|
-
myField = myField as unknown | string
|
|
158
|
-
get [SymbolInitialValue]
|
|
202
|
+
myField = myField as unknown | string;
|
|
203
|
+
get [SymbolInitialValue]() {
|
|
159
204
|
const self = this;
|
|
160
205
|
return (fieldName: 'myField') => {
|
|
161
206
|
if (fieldName !== 'myField') {
|
|
162
207
|
return self[fieldName];
|
|
163
208
|
}
|
|
164
|
-
|
|
209
|
+
//@ts-ignore
|
|
165
210
|
const answer = myField[SymbolInitialValue];
|
|
166
|
-
return
|
|
211
|
+
return answer;
|
|
167
212
|
};
|
|
168
213
|
}
|
|
169
|
-
}
|
|
170
|
-
class SecondMadeFieldClass extends BaseClass { myField = myField as unknown | string }
|
|
214
|
+
}
|
|
215
|
+
class SecondMadeFieldClass extends BaseClass { myField = myField as unknown | string; }
|
|
171
216
|
const madeFieldInstance = new MadeFieldClass;
|
|
172
217
|
const secondMadeFieldInstance = new MadeFieldClass;
|
|
173
218
|
const thirdMadeFieldInstance = new SecondMadeFieldClass;
|
|
174
219
|
|
|
175
|
-
class MadeReGet extends BaseClass { myField = myFieldReGet as unknown | string }
|
|
176
|
-
class MadeReSet extends BaseClass { myField = myFieldReSet as unknown | string }
|
|
220
|
+
class MadeReGet extends BaseClass { myField = myFieldReGet as unknown | string; }
|
|
221
|
+
class MadeReSet extends BaseClass { myField = myFieldReSet as unknown | string; }
|
|
177
222
|
const madeReGet = new MadeReGet;
|
|
178
223
|
const madeReSet = new MadeReSet;
|
|
179
224
|
|
|
180
225
|
describe('props tests', () => {
|
|
181
226
|
|
|
227
|
+
test('decorators works', () => {
|
|
228
|
+
const rgp = Reflect.getPrototypeOf;
|
|
229
|
+
// eslint-disable-next-line no-debugger
|
|
230
|
+
// debugger;
|
|
231
|
+
const decorated = new DecoratedByBase;
|
|
232
|
+
const exdecorated = new ExtendedDecoratedByBase;
|
|
233
|
+
expect(decoratedSomeProp.valueOf()).toEqual(321);
|
|
234
|
+
expect(exdecorated.someProp.valueOf()).toEqual(321);
|
|
235
|
+
expect(decorated.someProp.valueOf()).toEqual(123);
|
|
236
|
+
const proto = rgp(decorated);
|
|
237
|
+
//@ts-ignore;
|
|
238
|
+
expect(proto.someProp).toEqual(123);
|
|
239
|
+
});
|
|
240
|
+
|
|
182
241
|
test('base instance has props', () => {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
expect(Object.keys(baseInstance)).toEqual([
|
|
242
|
+
let gf: string;
|
|
243
|
+
let sv: string;
|
|
244
|
+
expect(Object.keys(baseInstance)).toEqual(['numberValue', 'stringValue', 'booleanValue', 'objectValue']);
|
|
186
245
|
|
|
187
246
|
gf = baseInstance.getterField;
|
|
188
247
|
expect(gf).toEqual('123');
|
|
@@ -213,6 +272,8 @@ describe('props tests', () => {
|
|
|
213
272
|
expect(/String$/.test(simpleInstance.stringProp.constructor.name)).toBe(true);
|
|
214
273
|
expect(() => {
|
|
215
274
|
|
|
275
|
+
// eslint-disable-next-line no-debugger
|
|
276
|
+
debugger;
|
|
216
277
|
// @ts-ignore
|
|
217
278
|
simpleInstance.stringProp = 123;
|
|
218
279
|
|
|
@@ -310,15 +371,15 @@ describe('props tests', () => {
|
|
|
310
371
|
test('takes error on wrong field definition', () => {
|
|
311
372
|
expect(() => {
|
|
312
373
|
class WrongFieldConstructor extends FieldConstructor {
|
|
313
|
-
value: number
|
|
374
|
+
value: number;
|
|
314
375
|
constructor(value: number) {
|
|
315
|
-
super(value)
|
|
376
|
+
super(value);
|
|
316
377
|
this.value = value;
|
|
317
378
|
}
|
|
318
379
|
}
|
|
319
380
|
const wrongField = new WrongFieldConstructor(123);
|
|
320
381
|
class WithWrongField extends BaseClass {
|
|
321
|
-
erroredField = wrongField
|
|
382
|
+
erroredField = wrongField;
|
|
322
383
|
}
|
|
323
384
|
new WithWrongField;
|
|
324
385
|
|
|
@@ -336,7 +397,7 @@ describe('props tests', () => {
|
|
|
336
397
|
// @ts-ignore
|
|
337
398
|
const inspected = util.inspect(madeFieldInstance);
|
|
338
399
|
const expected = 'MadeFieldClass { myField: [Getter/Setter] }';
|
|
339
|
-
expect(
|
|
400
|
+
expect(inspected).toEqual(expected);
|
|
340
401
|
});
|
|
341
402
|
|
|
342
403
|
test('wrong assignment to objects', () => {
|
|
@@ -619,4 +680,4 @@ describe('deep extend works', () => {
|
|
|
619
680
|
}).toThrow(new TypeError('Method Set.prototype.has called on incompatible receiver [object Object]'));
|
|
620
681
|
|
|
621
682
|
});
|
|
622
|
-
});
|
|
683
|
+
});
|
package/tsconfig.jest.json
CHANGED