typeomatica 0.2.7 → 0.2.9
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/.github/workflows/node.js.yml +3 -3
- package/jest.config.js +3 -5
- package/lib/errors.d.ts +1 -0
- package/lib/errors.js +2 -1
- package/lib/fields.d.ts +10 -1
- package/lib/fields.js +20 -5
- package/lib/index.js +10 -3
- package/package.json +14 -11
- package/src/errors.ts +2 -1
- package/src/fields.ts +23 -3
- package/src/index.ts +11 -4
- package/test/__snapshots__/index.ts.snap +1 -1
- package/test/index.ts +99 -16
- package/{test/tsconfig.json → tsconfig.jest.json} +4 -0
|
@@ -16,7 +16,7 @@ jobs:
|
|
|
16
16
|
|
|
17
17
|
strategy:
|
|
18
18
|
matrix:
|
|
19
|
-
node-version: [
|
|
19
|
+
node-version: [14.x, 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 14.x
|
|
38
38
|
uses: actions/setup-node@master
|
|
39
39
|
with:
|
|
40
|
-
node-version:
|
|
40
|
+
node-version: 14.x
|
|
41
41
|
|
|
42
42
|
- name: npm install
|
|
43
43
|
run: npm install
|
package/jest.config.js
CHANGED
|
@@ -2,9 +2,7 @@ module.exports = {
|
|
|
2
2
|
preset: 'ts-jest',
|
|
3
3
|
testEnvironment: 'node',
|
|
4
4
|
testMatch: ['**/test/**/index.ts', '**/test/**/addition.js'],
|
|
5
|
-
|
|
6
|
-
'ts-jest':
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
},
|
|
5
|
+
transform : {
|
|
6
|
+
'\\./test/*.ts$': ['ts-jest', { tsconfig : './tsconfig.jest.json' }]
|
|
7
|
+
}
|
|
10
8
|
};
|
package/lib/errors.d.ts
CHANGED
package/lib/errors.js
CHANGED
|
@@ -5,5 +5,6 @@ exports.ErrorsNames = {
|
|
|
5
5
|
TYPE_MISMATCH: 'Type Mismatch',
|
|
6
6
|
ACCESS_DENIED: 'Value Access Denied',
|
|
7
7
|
MISSING_PROP: 'Attempt to Access to Undefined Prop',
|
|
8
|
-
RIP_FUNCTIONS: 'Functions are Restricted'
|
|
8
|
+
RIP_FUNCTIONS: 'Functions are Restricted',
|
|
9
|
+
FORBIDDEN_RE: 'Re-Assirnment is Forbidden'
|
|
9
10
|
};
|
package/lib/fields.d.ts
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
1
|
export declare const SymbolInitialValue: unique symbol;
|
|
2
|
-
|
|
2
|
+
interface FieldDefinition {
|
|
3
|
+
[SymbolInitialValue]: unknown;
|
|
4
|
+
}
|
|
5
|
+
export declare class FieldConstructor implements FieldDefinition {
|
|
6
|
+
[SymbolInitialValue]: unknown;
|
|
7
|
+
get get(): (this: FieldDefinition) => unknown;
|
|
8
|
+
get set(): () => never;
|
|
9
|
+
constructor(value: unknown);
|
|
10
|
+
}
|
|
11
|
+
export {};
|
package/lib/fields.js
CHANGED
|
@@ -2,8 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FieldConstructor = exports.SymbolInitialValue = void 0;
|
|
4
4
|
exports.SymbolInitialValue = Symbol('Initial Value');
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
class FieldConstructor {
|
|
7
|
+
constructor(value) {
|
|
8
|
+
this[exports.SymbolInitialValue] = value;
|
|
9
|
+
}
|
|
10
|
+
get get() {
|
|
11
|
+
const self = this;
|
|
12
|
+
return function () {
|
|
13
|
+
return self[exports.SymbolInitialValue];
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
get set() {
|
|
17
|
+
return function () {
|
|
18
|
+
throw new TypeError(errors_1.ErrorsNames.FORBIDDEN_RE);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.FieldConstructor = FieldConstructor;
|
|
23
|
+
Object.freeze(FieldConstructor.prototype);
|
|
24
|
+
Object.seal(FieldConstructor.prototype);
|
package/lib/index.js
CHANGED
|
@@ -42,11 +42,18 @@ const createProperty = (propName, initialValue, receiver) => {
|
|
|
42
42
|
const descriptor = (isObject && (value instanceof fields_1.FieldConstructor)) ?
|
|
43
43
|
value
|
|
44
44
|
: Object.assign({ enumerable: true }, resolver[type](value, receiver));
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
try {
|
|
46
|
+
const result = Reflect.defineProperty(receiver, propName, descriptor);
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
47
52
|
};
|
|
53
|
+
const props2skip = new Set([Symbol.toStringTag, Symbol.iterator]);
|
|
48
54
|
const util = require('util');
|
|
49
|
-
const
|
|
55
|
+
const hasNodeInspect = (util && util.inspect && util.inspect.custom);
|
|
56
|
+
hasNodeInspect && (props2skip.add(util.inspect.custom));
|
|
50
57
|
const handlers = {
|
|
51
58
|
get(target, prop, receiver) {
|
|
52
59
|
const result = Reflect.get(target, prop, receiver);
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typeomatica",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "type logic against javascript metaprogramming",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=14"
|
|
7
|
+
},
|
|
5
8
|
"main": "lib/index.js",
|
|
6
9
|
"scripts": {
|
|
7
10
|
"build": "rm -rf ./lib && npx tsc --pretty",
|
|
@@ -27,16 +30,16 @@
|
|
|
27
30
|
"url": "git+https://github.com/wentout/typeomatica.git"
|
|
28
31
|
},
|
|
29
32
|
"devDependencies": {
|
|
30
|
-
"@types/jest": "^
|
|
31
|
-
"@types/node": "^
|
|
32
|
-
"eslint": "^
|
|
33
|
-
"husky": "^8.0.
|
|
34
|
-
"jest": "^
|
|
35
|
-
"
|
|
33
|
+
"@types/jest": "^29.2.5",
|
|
34
|
+
"@types/node": "^18.11.18",
|
|
35
|
+
"eslint": "^8.31.0",
|
|
36
|
+
"husky": "^8.0.3",
|
|
37
|
+
"jest": "^29.3.1",
|
|
38
|
+
"json5": "^2.2.3",
|
|
39
|
+
"lint-staged": "^13.1.0",
|
|
36
40
|
"set-value": "^4.1.0",
|
|
37
|
-
"ts-jest": "^
|
|
38
|
-
"ts-node": "^10.
|
|
39
|
-
"
|
|
40
|
-
"typescript": "^4.4.3"
|
|
41
|
+
"ts-jest": "^29.0.3",
|
|
42
|
+
"ts-node": "^10.9.1",
|
|
43
|
+
"typescript": "^4.9.4"
|
|
41
44
|
}
|
|
42
45
|
}
|
package/src/errors.ts
CHANGED
|
@@ -4,5 +4,6 @@ export const ErrorsNames = {
|
|
|
4
4
|
TYPE_MISMATCH: 'Type Mismatch',
|
|
5
5
|
ACCESS_DENIED: 'Value Access Denied',
|
|
6
6
|
MISSING_PROP: 'Attempt to Access to Undefined Prop',
|
|
7
|
-
RIP_FUNCTIONS: 'Functions are Restricted'
|
|
7
|
+
RIP_FUNCTIONS: 'Functions are Restricted',
|
|
8
|
+
FORBIDDEN_RE: 'Re-Assirnment is Forbidden'
|
|
8
9
|
};
|
package/src/fields.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
export const SymbolInitialValue = Symbol('Initial Value');
|
|
4
4
|
|
|
5
|
+
import { ErrorsNames } from './errors'
|
|
6
|
+
|
|
5
7
|
interface FieldDefinition {
|
|
6
8
|
[SymbolInitialValue]: unknown
|
|
7
9
|
// get?: unknown
|
|
@@ -11,9 +13,27 @@ interface FieldDefinition {
|
|
|
11
13
|
// writable: boolean
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
export const FieldConstructor = function (this: FieldDefinition, value: unknown) {
|
|
15
|
-
|
|
16
|
-
} as ObjectConstructor;
|
|
16
|
+
// export const FieldConstructor = function (this: FieldDefinition, value: unknown) {
|
|
17
|
+
// this[SymbolInitialValue] = value;
|
|
18
|
+
// } as ObjectConstructor;
|
|
19
|
+
|
|
20
|
+
export class FieldConstructor implements FieldDefinition {
|
|
21
|
+
[SymbolInitialValue]: unknown
|
|
22
|
+
public get get () {
|
|
23
|
+
const self = this;
|
|
24
|
+
return function (this: FieldDefinition) {
|
|
25
|
+
return self[SymbolInitialValue];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
public get set () {
|
|
29
|
+
return function () {
|
|
30
|
+
throw new TypeError(ErrorsNames.FORBIDDEN_RE);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
constructor (value: unknown) {
|
|
34
|
+
this[SymbolInitialValue] = value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
17
37
|
|
|
18
38
|
// Object.assign(FieldConstructor.prototype, {
|
|
19
39
|
// configurable: false,
|
package/src/index.ts
CHANGED
|
@@ -44,7 +44,6 @@ const resolver = Object.entries({
|
|
|
44
44
|
return obj;
|
|
45
45
|
}, {});
|
|
46
46
|
|
|
47
|
-
|
|
48
47
|
const createProperty = (propName: string, initialValue: unknown, receiver: object) => {
|
|
49
48
|
|
|
50
49
|
const value = initialValue;
|
|
@@ -80,13 +79,20 @@ const createProperty = (propName: string, initialValue: unknown, receiver: objec
|
|
|
80
79
|
// debugger;
|
|
81
80
|
// }
|
|
82
81
|
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
try {
|
|
83
|
+
const result = Reflect.defineProperty(receiver, propName, descriptor);
|
|
84
|
+
return result;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
// debugger;
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
85
89
|
|
|
86
90
|
};
|
|
87
91
|
|
|
92
|
+
const props2skip = new Set([Symbol.toStringTag, Symbol.iterator]);
|
|
88
93
|
const util = require('util');
|
|
89
|
-
const
|
|
94
|
+
const hasNodeInspect = (util && util.inspect && util.inspect.custom);
|
|
95
|
+
hasNodeInspect && (props2skip.add(util.inspect.custom));
|
|
90
96
|
|
|
91
97
|
const handlers = {
|
|
92
98
|
get(target: object, prop: string | symbol, receiver: object) {
|
|
@@ -103,6 +109,7 @@ const handlers = {
|
|
|
103
109
|
}, {}));
|
|
104
110
|
}
|
|
105
111
|
}
|
|
112
|
+
// @ts-ignore
|
|
106
113
|
if (props2skip.has(prop)) {
|
|
107
114
|
return undefined;
|
|
108
115
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`props tests correct JSON.stringify 1`] = `"
|
|
3
|
+
exports[`props tests correct JSON.stringify 1`] = `""{\\"numberValue\\":123,\\"stringValue\\":\\"123\\",\\"booleanValue\\":false,\\"objectValue\\":{}}""`;
|
package/test/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
import { describe, expect, test } from '@jest/globals';
|
|
4
|
+
|
|
3
5
|
// BasePrototype & BaseClass are the same function
|
|
4
6
|
// go as you want for being meaningfull
|
|
5
7
|
// or meaningless
|
|
@@ -8,8 +10,6 @@ const BasePrototype = require('..');
|
|
|
8
10
|
// @ts-ignore
|
|
9
11
|
import { BaseClass, IDEF, FieldConstructor } from '..';
|
|
10
12
|
|
|
11
|
-
debugger;
|
|
12
|
-
|
|
13
13
|
class Base extends BasePrototype({
|
|
14
14
|
additionalProp: 321,
|
|
15
15
|
someMethod() {
|
|
@@ -72,23 +72,61 @@ const extendedSetInstance = new ExtendedSet;
|
|
|
72
72
|
const MUTATION_VALUE = -2;
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
class
|
|
75
|
+
class MyFieldConstructorNoRe extends FieldConstructor {
|
|
76
|
+
_value: string
|
|
77
|
+
constructor(value: string) {
|
|
78
|
+
super(value);
|
|
79
|
+
Reflect.defineProperty(this, 'enumerable', {
|
|
80
|
+
value: true
|
|
81
|
+
});
|
|
82
|
+
this._value = value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
class MyFieldConstructorReGet extends MyFieldConstructorNoRe {
|
|
76
86
|
constructor(value: string) {
|
|
77
87
|
super(value);
|
|
88
|
+
const self = this;
|
|
78
89
|
Reflect.defineProperty(this, 'enumerable', {
|
|
79
90
|
value: true
|
|
80
91
|
});
|
|
81
92
|
Reflect.defineProperty(this, 'get', {
|
|
82
|
-
get
|
|
93
|
+
get() {
|
|
83
94
|
return function () {
|
|
84
|
-
return
|
|
95
|
+
return self._value;
|
|
85
96
|
}
|
|
86
|
-
}
|
|
97
|
+
},
|
|
98
|
+
enumerable: true
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
class MyFieldConstructorReSet extends MyFieldConstructorNoRe {
|
|
103
|
+
constructor(value: string) {
|
|
104
|
+
super(value);
|
|
105
|
+
const self = this;
|
|
106
|
+
Reflect.defineProperty(this, 'enumerable', {
|
|
107
|
+
value: true
|
|
87
108
|
});
|
|
88
109
|
Reflect.defineProperty(this, 'set', {
|
|
89
|
-
get
|
|
90
|
-
return function (
|
|
91
|
-
|
|
110
|
+
get() {
|
|
111
|
+
return function (value: string) {
|
|
112
|
+
self._value = value;
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
enumerable: true
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
class MyFieldConstructor extends MyFieldConstructorReGet {
|
|
120
|
+
constructor(value: string) {
|
|
121
|
+
super(value);
|
|
122
|
+
const self = this;
|
|
123
|
+
Reflect.defineProperty(this, 'enumerable', {
|
|
124
|
+
value: true
|
|
125
|
+
});
|
|
126
|
+
Reflect.defineProperty(this, 'set', {
|
|
127
|
+
get() {
|
|
128
|
+
return function (value: string) {
|
|
129
|
+
self._value = value;
|
|
92
130
|
}
|
|
93
131
|
},
|
|
94
132
|
enumerable: true
|
|
@@ -96,13 +134,21 @@ class MyFieldConstructor extends FieldConstructor {
|
|
|
96
134
|
}
|
|
97
135
|
}
|
|
98
136
|
|
|
99
|
-
const myField = new MyFieldConstructor('
|
|
100
|
-
|
|
101
|
-
|
|
137
|
+
const myField = new MyFieldConstructor('initial value');
|
|
138
|
+
const myFieldReGet = new MyFieldConstructorReGet('initial value for get check');
|
|
139
|
+
const myFieldReSet = new MyFieldConstructorReSet('initial value for set check');
|
|
140
|
+
|
|
141
|
+
class MadeFieldClass extends BaseClass { myField = myField as unknown | string };
|
|
142
|
+
class SecondMadeFieldClass extends BaseClass { myField = myField as unknown | string };
|
|
102
143
|
const madeFieldInstance = new MadeFieldClass;
|
|
103
144
|
const secondMadeFieldInstance = new MadeFieldClass;
|
|
104
145
|
const thirdMadeFieldInstance = new SecondMadeFieldClass;
|
|
105
146
|
|
|
147
|
+
class MadeReGet extends BaseClass { myField = myFieldReGet as unknown | string }
|
|
148
|
+
class MadeReSet extends BaseClass { myField = myFieldReSet as unknown | string }
|
|
149
|
+
const madeReGet = new MadeReGet;
|
|
150
|
+
const madeReSet = new MadeReSet;
|
|
151
|
+
|
|
106
152
|
describe('props tests', () => {
|
|
107
153
|
|
|
108
154
|
test('base instance has props', () => {
|
|
@@ -172,12 +218,45 @@ describe('props tests', () => {
|
|
|
172
218
|
});
|
|
173
219
|
|
|
174
220
|
test('correct custom field creation', () => {
|
|
175
|
-
expect(madeFieldInstance.myField).toEqual('
|
|
221
|
+
expect(madeFieldInstance.myField).toEqual('initial value');
|
|
176
222
|
});
|
|
223
|
+
|
|
177
224
|
test('correct custom field assignment', () => {
|
|
178
|
-
madeFieldInstance.myField =
|
|
179
|
-
expect(secondMadeFieldInstance.myField).toEqual(
|
|
180
|
-
expect(thirdMadeFieldInstance.myField).toEqual(
|
|
225
|
+
madeFieldInstance.myField = 'replaced';
|
|
226
|
+
expect(secondMadeFieldInstance.myField).toEqual('replaced');
|
|
227
|
+
expect(thirdMadeFieldInstance.myField).toEqual('replaced');
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test('correct custom field no-re-assignment', () => {
|
|
231
|
+
expect(madeReGet.myField).toEqual('initial value for get check');
|
|
232
|
+
expect(() => {
|
|
233
|
+
|
|
234
|
+
madeReGet.myField = 'replaced';
|
|
235
|
+
|
|
236
|
+
}).toThrow(new TypeError('Re-Assirnment is Forbidden'));
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test('correct custom field setter only', () => {
|
|
240
|
+
madeReSet.myField = 'replaced';
|
|
241
|
+
expect(madeReSet.myField).toEqual('initial value for set check');
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test('takes error on wrong field definition', () => {
|
|
245
|
+
expect(() => {
|
|
246
|
+
class WrongFieldConstructor extends FieldConstructor {
|
|
247
|
+
value: number
|
|
248
|
+
constructor(value: number) {
|
|
249
|
+
super(value)
|
|
250
|
+
this.value = value;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
const wrongField = new WrongFieldConstructor(123);
|
|
254
|
+
class WithWrongField extends BaseClass {
|
|
255
|
+
erroredField = wrongField
|
|
256
|
+
}
|
|
257
|
+
new WithWrongField;
|
|
258
|
+
|
|
259
|
+
}).toThrow();
|
|
181
260
|
});
|
|
182
261
|
|
|
183
262
|
test('correct custom missing prop search creation', () => {
|
|
@@ -188,6 +267,10 @@ describe('props tests', () => {
|
|
|
188
267
|
const util = require('util');
|
|
189
268
|
// @ts-ignore
|
|
190
269
|
expect(madeFieldInstance[util.inspect.custom]).toEqual(undefined);
|
|
270
|
+
// @ts-ignore
|
|
271
|
+
const inspected = util.inspect(madeFieldInstance);
|
|
272
|
+
const expected = 'MadeFieldClass { myField: [Getter/Setter] }';
|
|
273
|
+
expect(expected).toEqual(expected);
|
|
191
274
|
});
|
|
192
275
|
|
|
193
276
|
test('wrong assignment to objects', () => {
|