(...args: unknown[]): T;
10 | };
11 | export declare const Strict: StrictRuntime;
12 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.Strict = exports.FieldConstructor = exports.BaseClass = exports.BaseConstructorPrototype = void 0;
4 | const errors_1 = require("./errors");
5 | const types_1 = require("./types");
6 | const fields_1 = require("./fields");
7 | const resolver = Object.entries({
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
13 | }).reduce((obj, [key, _handler]) => {
14 | obj[key] = function (initialValue, receiver) {
15 | const handler = _handler(initialValue);
16 | return {
17 | get() {
18 | const invocationThis = this;
19 | if (invocationThis !== receiver) {
20 | throw new ReferenceError(errors_1.ErrorsNames.ACCESS_DENIED);
21 | }
22 | const result = handler.get();
23 | return result;
24 | },
25 | set(replacementValue) {
26 | const invocationThis = this;
27 | if (invocationThis !== receiver) {
28 | throw new ReferenceError(errors_1.ErrorsNames.ACCESS_DENIED);
29 | }
30 | const result = handler.set(replacementValue);
31 | return result;
32 | }
33 | };
34 | };
35 | return obj;
36 | }, {});
37 | const createProperty = (propName, initialValue, receiver) => {
38 | const value = initialValue;
39 | const valueIsPrimitive = (0, types_1.isPrimitive)(initialValue);
40 | const isObject = typeof initialValue === 'object';
41 | const isFunction = initialValue instanceof Function;
42 | const isNull = initialValue === null;
43 | const type = valueIsPrimitive ? 'primitives' : (isObject ? (isNull ? 'nullish' : 'objects') : (isFunction ? 'functions' : 'special'));
44 | const descriptor = (isObject && (value instanceof fields_1.FieldConstructor)) ?
45 | value
46 | : Object.assign({ enumerable: true }, resolver[type](value, receiver));
47 | const result = Reflect.defineProperty(receiver, propName, descriptor);
48 | return result;
49 | };
50 | const props2skip = new Set([Symbol.toStringTag, Symbol.iterator]);
51 | const util = require('util');
52 | const hasNodeInspect = (util && util.inspect && util.inspect.custom);
53 | hasNodeInspect && (props2skip.add(util.inspect.custom));
54 | const handlers = {
55 | get(target, prop, receiver) {
56 | const result = Reflect.get(target, prop, receiver);
57 | if (result !== undefined) {
58 | return result;
59 | }
60 | if (prop === 'toJSON') {
61 | return function () {
62 | const entries = Object.entries(this);
63 | return JSON.stringify(entries.reduce((obj, [key, value]) => {
64 | obj[key] = value.valueOf();
65 | return obj;
66 | }, {}));
67 | };
68 | }
69 | if (props2skip.has(prop)) {
70 | return undefined;
71 | }
72 | throw new Error(`${errors_1.ErrorsNames.MISSING_PROP}: [ ${String(prop).valueOf()} ] of ${receiver.constructor.name}`);
73 | },
74 | set(_, prop, value, receiver) {
75 | const result = createProperty(prop, value, receiver);
76 | return result;
77 | },
78 | };
79 | const BaseTarget = Object.create(null);
80 | exports.BaseConstructorPrototype = function (InstanceTarget = BaseTarget) {
81 | if (!new.target) {
82 | const self = exports.BaseConstructorPrototype.bind(this, InstanceTarget);
83 | self.prototype = {
84 | constructor: exports.BaseConstructorPrototype
85 | };
86 | return self;
87 | }
88 | const InstancePrototype = new Proxy(InstanceTarget, handlers);
89 | let protoPointer = this;
90 | let protoConstrcutor;
91 | do {
92 | protoPointer = Reflect.getPrototypeOf(protoPointer);
93 | protoConstrcutor = Reflect.getOwnPropertyDescriptor(protoPointer, 'constructor').value;
94 | } while (protoConstrcutor !== exports.BaseConstructorPrototype);
95 | Reflect.setPrototypeOf(protoPointer, InstancePrototype);
96 | return this;
97 | };
98 | Object.defineProperty(module, 'exports', {
99 | get() {
100 | return exports.BaseConstructorPrototype;
101 | },
102 | enumerable: true
103 | });
104 | class BaseClass extends exports.BaseConstructorPrototype {
105 | }
106 | exports.BaseClass = BaseClass;
107 | var fields_2 = require("./fields");
108 | Object.defineProperty(exports, "FieldConstructor", { enumerable: true, get: function () { return fields_2.FieldConstructor; } });
109 | exports.Strict = {
110 | Strict: exports.BaseConstructorPrototype,
111 | }.Strict;
112 | Object.defineProperty(module.exports, 'BaseClass', {
113 | get() {
114 | return BaseClass;
115 | },
116 | enumerable: true
117 | });
118 | Object.defineProperty(module.exports, 'FieldConstructor', {
119 | get() {
120 | return fields_1.FieldConstructor;
121 | },
122 | enumerable: true
123 | });
124 | Object.defineProperty(module.exports, 'Strict', {
125 | get() {
126 | return function (prototypeTarget) {
127 | const decorator = function (Target) {
128 | const Targeted = exports.BaseConstructorPrototype.call(Target, prototypeTarget);
129 | const MyProxyClass = new Proxy(Targeted, {
130 | construct(target, argumentsList, newTarget) {
131 | const result = Reflect.construct(target, argumentsList, newTarget);
132 | debugger;
133 | return result;
134 | },
135 | });
136 | return MyProxyClass;
137 | };
138 | return decorator;
139 | };
140 | },
141 | enumerable: true
142 | });
143 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/lib/types/functions.d.ts:
--------------------------------------------------------------------------------
1 | export declare const functions: () => never;
2 |
--------------------------------------------------------------------------------
/lib/types/functions.js:
--------------------------------------------------------------------------------
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;
9 | //# sourceMappingURL=functions.js.map
--------------------------------------------------------------------------------
/lib/types/functions.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"functions.js","sourceRoot":"","sources":["../../src/types/functions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,sCAAwC;AAEjC,MAAM,SAAS,GAAG,GAAG,EAAE;IAC7B,MAAM,IAAI,SAAS,CAAC,oBAAW,CAAC,aAAa,CAAC,CAAC;AAChD,CAAC,CAAC;AAFW,QAAA,SAAS,aAEpB"}
--------------------------------------------------------------------------------
/lib/types/index.d.ts:
--------------------------------------------------------------------------------
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;
7 |
--------------------------------------------------------------------------------
/lib/types/index.js:
--------------------------------------------------------------------------------
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;
23 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/lib/types/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAClB,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAChB,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAChB,2CAA0C;AAAjC,wGAAA,UAAU,OAAA;AACnB,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAEhB,MAAM,eAAe,GAAG;IACvB,QAAQ;IACR,QAAQ;IACR,SAAS;CACT,CAAC;AAEK,MAAM,WAAW,GAAG,CAAC,KAAc,EAAE,EAAE;IAC7C,OAAO,eAAe,CAAC,QAAQ,CAAC,OAAO,KAAK,CAAC,CAAC;AAC/C,CAAC,CAAC;AAFW,QAAA,WAAW,eAEtB"}
--------------------------------------------------------------------------------
/lib/types/nullish.d.ts:
--------------------------------------------------------------------------------
1 | export declare const nullish: (value: object) => {
2 | get(): object;
3 | set(): never;
4 | };
5 |
--------------------------------------------------------------------------------
/lib/types/nullish.js:
--------------------------------------------------------------------------------
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;
17 | //# sourceMappingURL=nullish.js.map
--------------------------------------------------------------------------------
/lib/types/nullish.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"nullish.js","sourceRoot":"","sources":["../../src/types/nullish.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,sCAAwC;AAEjC,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,EAAE;IACxC,OAAO;QACN,GAAG;YACF,OAAO,KAAK,CAAC;QACd,CAAC;QACD,GAAG;YACF,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,oBAAW,CAAC,aAAa,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACb,CAAC;KACD,CAAA;AACF,CAAC,CAAC;AAVW,QAAA,OAAO,WAUlB"}
--------------------------------------------------------------------------------
/lib/types/objects.d.ts:
--------------------------------------------------------------------------------
1 | export declare const objects: (value: object) => {
2 | get(): object;
3 | set(replacementValue: unknown): object;
4 | };
5 |
--------------------------------------------------------------------------------
/lib/types/objects.js:
--------------------------------------------------------------------------------
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;
21 | //# sourceMappingURL=objects.js.map
--------------------------------------------------------------------------------
/lib/types/objects.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"objects.js","sourceRoot":"","sources":["../../src/types/objects.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,sCAAwC;AAEjC,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,EAAE;IACxC,OAAO;QACN,GAAG;YACF,OAAO,KAAK,CAAC;QACd,CAAC;QACD,GAAG,CAAC,gBAAyB;YAC5B,IAAI,gBAAgB,YAAY,MAAM,IAAI,gBAAgB,CAAC,WAAW,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC;gBAC9F,KAAK,GAAG,gBAAgB,CAAC;gBACzB,OAAO,KAAK,CAAC;YACd,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,oBAAW,CAAC,aAAa,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACb,CAAC;KACD,CAAA;AACF,CAAC,CAAC;AAdW,QAAA,OAAO,WAclB"}
--------------------------------------------------------------------------------
/lib/types/primitives.d.ts:
--------------------------------------------------------------------------------
1 | export declare const primitives: (initialValue: object) => {
2 | get(): any;
3 | set(replacementValue: unknown): any;
4 | };
5 |
--------------------------------------------------------------------------------
/lib/types/primitives.js:
--------------------------------------------------------------------------------
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 | const answer = value[prop];
29 | return answer;
30 | }
31 | });
32 | return proxyAsValue;
33 | },
34 | set(replacementValue) {
35 | if (replacementValue instanceof value.constructor) {
36 | value = replacementValue;
37 | return value;
38 | }
39 | const prevalue = Object(replacementValue);
40 | if (prevalue instanceof value.constructor) {
41 | value = prevalue;
42 | return value;
43 | }
44 | const error = new TypeError(errors_1.ErrorsNames.TYPE_MISMATCH);
45 | throw error;
46 | }
47 | };
48 | };
49 | exports.primitives = primitives;
50 | //# sourceMappingURL=primitives.js.map
--------------------------------------------------------------------------------
/lib/types/primitives.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../src/types/primitives.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,sCAAwC;AAEjC,MAAM,UAAU,GAAG,CAAC,YAAoB,EAAE,EAAE;IAClD,IAAI,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACjC,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC;IAExC,OAAO;QACN,GAAG;YACF,MAAM,YAAY,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE;gBAErC,GAAG,CAAC,CAAC,EAAE,IAAI;oBACV,IAAI,IAAI,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC;wBACjC,OAAO,UAAU,IAAY;4BAC5B,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gCAC1B,MAAM,IAAI,cAAc,CAAC,oBAAW,CAAC,aAAa,CAAC,CAAC;4BACrD,CAAC;4BACD,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC;wBACxB,CAAC,CAAA;oBACF,CAAC;oBAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;wBACxB,OAAO;4BACN,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC;wBACxB,CAAC,CAAA;oBACF,CAAC;oBAGD,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;wBACrC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAChC,CAAC;oBAED,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC3B,OAAO,MAAM,CAAC;gBACf,CAAC;aACD,CAAC,CAAC;YACH,OAAO,YAAY,CAAC;QACrB,CAAC;QAaD,GAAG,CAAC,gBAAyB;YAC5B,IAAI,gBAAgB,YAAY,KAAK,CAAC,WAAW,EAAE,CAAC;gBACnD,KAAK,GAAG,gBAAgB,CAAC;gBACzB,OAAO,KAAK,CAAC;YACd,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;YAE1C,IAAI,QAAQ,YAAY,KAAK,CAAC,WAAW,EAAE,CAAC;gBAC3C,KAAK,GAAG,QAAQ,CAAC;gBACjB,OAAO,KAAK,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,oBAAW,CAAC,aAAa,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACb,CAAC;KACD,CAAC;AACH,CAAC,CAAC;AAhEW,QAAA,UAAU,cAgErB"}
--------------------------------------------------------------------------------
/lib/types/special.d.ts:
--------------------------------------------------------------------------------
1 | export declare const special: (value: object) => {
2 | get(): object;
3 | set(replacementValue: object): object;
4 | };
5 |
--------------------------------------------------------------------------------
/lib/types/special.js:
--------------------------------------------------------------------------------
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;
21 | //# sourceMappingURL=special.js.map
--------------------------------------------------------------------------------
/lib/types/special.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"special.js","sourceRoot":"","sources":["../../src/types/special.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,sCAAwC;AAEjC,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,EAAE;IACxC,OAAO;QACN,GAAG;YACF,OAAO,KAAK,CAAC;QACd,CAAC;QACD,GAAG,CAAC,gBAAwB;YAC3B,IAAI,OAAO,gBAAgB,KAAK,OAAO,KAAK,EAAE,CAAC;gBAC9C,KAAK,GAAG,gBAAgB,CAAC;gBACzB,OAAO,KAAK,CAAC;YACd,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,oBAAW,CAAC,aAAa,CAAC,CAAC;YACvD,MAAM,KAAK,CAAC;QACb,CAAC;KACD,CAAA;AACF,CAAC,CAAC;AAdW,QAAA,OAAO,WAclB"}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "typeomatica",
3 | "version": "0.3.38",
4 | "description": "type logic against javascript metaprogramming",
5 | "engines": {
6 | "node": ">=16"
7 | },
8 | "main": "lib/index.js",
9 | "scripts": {
10 | "build": "rm -rf ./lib && npx tsc --pretty",
11 | "buildlint": "rm -rf ./lib && npx tsc --pretty && npm run lint",
12 | "lint": "npx eslint --fix --ignore-pattern ./lib",
13 | "test": "npx jest",
14 | "test:cov": "npx jest --collectCoverage",
15 | "test:addition": "npm run build && node --test --experimental-test-coverage ./test/addition.js",
16 | "debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand",
17 | "debug:old": "npx --node-options=--inspect-brk jest",
18 | "prepare": "husky install"
19 | },
20 | "keywords": [
21 | "strict",
22 | "types",
23 | "runtime",
24 | "javascript",
25 | "metaprogramming"
26 | ],
27 | "author": "went.out@gmail.com",
28 | "license": "MIT",
29 | "repository": {
30 | "type": "git",
31 | "url": "git+https://github.com/wentout/typeomatica.git"
32 | },
33 | "devDependencies": {
34 | "@types/jest": "^29.5.14",
35 | "@types/node": "^18.19.67",
36 | "@typescript-eslint/eslint-plugin": "^6.21.0",
37 | "@typescript-eslint/parser": "^6.21.0",
38 | "eslint": "^8.57.1",
39 | "husky": "^8.0.3",
40 | "jest": "^29.7.0",
41 | "json5": "^2.2.3",
42 | "lint-staged": "^13.3.0",
43 | "set-value": "^4.1.0",
44 | "ts-node": "^10.9.2",
45 | "typescript": "^5.7.2"
46 | },
47 | "dependencies": {
48 | "ts-jest": "^29.2.5"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/errors.ts:
--------------------------------------------------------------------------------
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 | FORBIDDEN_RE: 'Re-Assirnment is Forbidden'
9 | };
--------------------------------------------------------------------------------
/src/fields.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { ErrorsNames } from './errors';
4 |
5 | const SymbolInitialValue = Symbol('Initial Value');
6 |
7 | interface FieldDefinition {
8 | [SymbolInitialValue]: unknown
9 | // get?: unknown
10 | // set?: unknown
11 | // configurable: boolean,
12 | // enumerable: boolean,
13 | // writable: boolean
14 | }
15 |
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 | static get SymbolInitialValue () {
37 | return SymbolInitialValue;
38 | }
39 | }
40 |
41 | // Object.assign(FieldConstructor.prototype, {
42 | // configurable: false,
43 | // enumerable: false,
44 | // // writable: false
45 | // })
46 |
47 | // Object.defineProperty(FieldConstructor.prototype, 'get', {
48 | // get() {
49 | // return this[symbolValue];
50 | // },
51 | // // @ts-ignore
52 | // set(value: unknown) {
53 | // throw new Error('broken behaviour: assignment to getter');
54 | // },
55 | // configurable: false,
56 | // enumerable: true,
57 | // // writable: false
58 | // });
59 |
60 | // Object.defineProperty(FieldConstructor.prototype, 'set', {
61 | // get() {
62 | // return function (this: FieldDefinition, value: unknown) {
63 | // this[symbolValue] = value;
64 | // }
65 | // },
66 | // // @ts-ignore
67 | // set(value: unknown) {
68 | // throw new Error('broken behaviour: assignment to setter');
69 | // },
70 | // configurable: false,
71 | // enumerable: true,
72 | // // writable: false
73 | // });
74 |
75 | Object.freeze(FieldConstructor.prototype);
76 | Object.seal(FieldConstructor.prototype);
77 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { ErrorsNames } from './errors';
4 |
5 | import {
6 | functions,
7 | nullish,
8 | objects,
9 | primitives,
10 | special,
11 | isPrimitive
12 | } from './types';
13 |
14 | import { FieldConstructor } from './fields';
15 |
16 | const resolver = Object.entries({
17 | primitives,
18 | special,
19 | nullish,
20 | objects,
21 | functions
22 | }).reduce((obj: object, [key, _handler]) => {
23 | // @ts-ignore
24 | obj[key] = function (initialValue: object, receiver: object) {
25 | const handler = _handler(initialValue);
26 | return {
27 | get() {
28 | const invocationThis = this;
29 | if (invocationThis !== receiver) {
30 | throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
31 | }
32 | const result = handler.get();
33 | return result;
34 | },
35 | set(replacementValue: unknown) {
36 | const invocationThis = this;
37 | if (invocationThis !== receiver) {
38 | throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
39 | }
40 | const result = handler.set(replacementValue);
41 | return result;
42 | }
43 | };
44 | };
45 |
46 | return obj;
47 | }, {});
48 |
49 | const createProperty = (propName: string, initialValue: unknown, receiver: object) => {
50 |
51 | const value = initialValue;
52 | const valueIsPrimitive = isPrimitive(initialValue);
53 | const isObject = typeof initialValue === 'object';
54 | const isFunction = initialValue instanceof Function;
55 | const isNull = initialValue === null;
56 |
57 | /**
58 | * special: undefined or BigInt or Symbol
59 | * or other non constructible type
60 | */
61 |
62 | const type = valueIsPrimitive ? 'primitives' : (
63 | isObject ? (
64 | isNull ? 'nullish' : 'objects'
65 | ) : (
66 | isFunction ? 'functions' : 'special'
67 | )
68 | );
69 |
70 | const descriptor = (isObject && (value instanceof FieldConstructor)) ?
71 | value
72 | :
73 | {
74 | enumerable: true,
75 | // @ts-ignore
76 | ...resolver[type](value, receiver),
77 | };
78 |
79 | // if (value instanceof FieldConstructor) {
80 | // descriptor;
81 | // debugger;
82 | // }
83 |
84 | const result = Reflect.defineProperty(receiver, propName, descriptor);
85 | return result;
86 |
87 | };
88 |
89 | const props2skip = new Set([Symbol.toStringTag, Symbol.iterator]);
90 | const util = require('util');
91 | const hasNodeInspect = (util && util.inspect && util.inspect.custom);
92 | hasNodeInspect && (props2skip.add(util.inspect.custom));
93 |
94 | const handlers = {
95 | get(target: object, prop: string | symbol, receiver: object) {
96 | const result = Reflect.get(target, prop, receiver);
97 | if (result !== undefined) {
98 | return result;
99 | }
100 | if (prop === 'toJSON') {
101 | // eslint-disable-next-line no-unused-vars
102 | return function (this: typeof target) {
103 | const entries = Object.entries(this);
104 | return JSON.stringify(entries.reduce((obj, [key, value]) => {
105 | // @ts-ignore
106 | obj[key] = value.valueOf();
107 | return obj;
108 | }, {}));
109 | };
110 | }
111 | // @ts-ignore
112 | if (props2skip.has(prop)) {
113 | return undefined;
114 | }
115 | throw new Error(`${ErrorsNames.MISSING_PROP}: [ ${String(prop).valueOf()} ] of ${receiver.constructor.name}`);
116 | },
117 | set(_: object, prop: string, value: unknown, receiver: object) {
118 | const result = createProperty(prop, value, receiver);
119 | return result;
120 | },
121 | // defineProperty(target: object, key: string, descriptor: object) {
122 | // debugger;
123 | // Reflect.defineProperty(target, key, descriptor);
124 | // return true;
125 | // }
126 | };
127 |
128 | // user have to precisely define all props
129 | const BaseTarget = Object.create(null);
130 |
131 | type Proto = Pick
> & T;
132 |
133 |
134 | export const BaseConstructorPrototype = function <
135 | P extends object,
136 | S extends Proto,
137 | T extends {
138 | (): P
139 | new(): {
140 | [key in keyof S]: S[key]
141 | }
142 | },
143 | >(
144 | this: T,
145 | InstanceTarget: P = BaseTarget
146 | ): T {
147 | if (!new.target) {
148 |
149 | const self: {
150 | prototype: {
151 | constructor: typeof BaseConstructorPrototype
152 | }
153 | //@ts-ignore
154 | } = BaseConstructorPrototype.bind(this, InstanceTarget);
155 |
156 | self.prototype = {
157 | constructor: BaseConstructorPrototype
158 | };
159 |
160 | return self as T;
161 |
162 | }
163 |
164 | const InstancePrototype = new Proxy(InstanceTarget, handlers);
165 |
166 | let protoPointer = this as object;
167 | let protoConstrcutor;
168 | do {
169 | protoPointer = Reflect.getPrototypeOf(protoPointer) as object;
170 | protoConstrcutor = Reflect.getOwnPropertyDescriptor(protoPointer, 'constructor')!.value;
171 | } while (protoConstrcutor !== BaseConstructorPrototype);
172 |
173 | Reflect.setPrototypeOf(protoPointer, InstancePrototype);
174 | return this;
175 |
176 | } as {
177 | new(): unknown
178 | (): void
179 | };
180 |
181 | // const BaseConstructorProtoProxy = new Proxy(BaseConstructorPrototype, {
182 | // construct (target: Function, argumentsList: unknown[], newTarget: Function) {
183 | // debugger;
184 | // console.log('.construct invocation');
185 | // const result = Reflect.construct(target, argumentsList, newTarget);
186 | // debugger;
187 | // return result;
188 | // },
189 | // get (target: object, prop: string | symbol, receiver: object) {
190 | // debugger;
191 | // const result = Reflect.get(target, prop, receiver);
192 | // debugger;
193 | // return result;
194 | // },
195 | // set(_: object, prop: string, value: unknown, receiver: object) {
196 | // debugger;
197 | // const result = createProperty(prop, value, receiver);
198 | // return result;
199 | // },
200 | // defineProperty(target: object, key: string, descriptor: object) {
201 | // debugger;
202 | // Reflect.defineProperty(target, key, descriptor);
203 | // return true;
204 | // },
205 | // getPrototypeOf(target: object) {
206 | // debugger;
207 | // const result = Reflect.getPrototypeOf(target);
208 | // return result;
209 | // },
210 | // setPrototypeOf(target, prototype) {
211 | // debugger;
212 | // Reflect.setPrototypeOf(target, prototype);
213 | // return true;
214 | // },
215 | // });
216 |
217 | // as ObjectConstructor & {
218 | // (): void
219 | // // eslint-disable-next-line no-unused-vars
220 | // new(param?: T extends object ? T : {}): {
221 | // [key in keyof T]: T[key]
222 | // }
223 | // };
224 |
225 | Object.defineProperty(module, 'exports', {
226 | get() {
227 | // return BaseConstructorProtoProxy;
228 | return BaseConstructorPrototype;
229 | },
230 | enumerable: true
231 | });
232 |
233 |
234 | // export class BaseClass extends BaseConstructorProtoProxy { }
235 | // eslint-disable-next-line new-cap
236 | // @ts-ignore
237 | export class BaseClass extends BaseConstructorPrototype { }
238 | export { FieldConstructor } from './fields';
239 |
240 | type StrictRuntime = {
241 | // eslint-disable-next-line no-unused-vars
242 | (...args: unknown[]): T
243 | }
244 |
245 | // export const { StrictPrototype, Strict } = {
246 | export const { Strict } = {
247 | // Strict: BaseConstructorProtoProxy,
248 | Strict: BaseConstructorPrototype,
249 | } as {
250 | // StrictPrototype: StrictRuntime
251 | Strict: StrictRuntime
252 | };
253 |
254 | Object.defineProperty(module.exports, 'BaseClass', {
255 | get() {
256 | return BaseClass;
257 | },
258 | enumerable: true
259 | });
260 | Object.defineProperty(module.exports, 'FieldConstructor', {
261 | get() {
262 | return FieldConstructor;
263 | },
264 | enumerable: true
265 | });
266 | Object.defineProperty(module.exports, 'Strict', {
267 | get() {
268 | return function (prototypeTarget: object) {
269 | const decorator = function (
270 | this: object,
271 | Target: {
272 | new(): unknown
273 | (): void
274 | },
275 | ) {
276 | //@ts-ignore
277 | const Targeted = BaseConstructorPrototype.call(Target, prototypeTarget);
278 | //@ts-ignore
279 | const MyProxyClass = new Proxy(Targeted, {
280 | construct(target, argumentsList, newTarget) {
281 | //@ts-ignore
282 | const result = Reflect.construct(target, argumentsList, newTarget);
283 | debugger;
284 | return result;
285 | },
286 | });
287 | return MyProxyClass;
288 | };
289 |
290 | return decorator;
291 |
292 | };
293 | // return BaseConstructorProtoProxy;
294 | // return BaseConstructorPrototype;
295 | },
296 | enumerable: true
297 | });
298 |
--------------------------------------------------------------------------------
/src/types/functions.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { ErrorsNames } from '../errors';
4 |
5 | export const functions = () => {
6 | throw new TypeError(ErrorsNames.RIP_FUNCTIONS);
7 | };
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
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 | };
18 |
--------------------------------------------------------------------------------
/src/types/nullish.ts:
--------------------------------------------------------------------------------
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 | };
--------------------------------------------------------------------------------
/src/types/objects.ts:
--------------------------------------------------------------------------------
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 | };
--------------------------------------------------------------------------------
/src/types/primitives.ts:
--------------------------------------------------------------------------------
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 | const answer = value[prop];
35 | return answer;
36 | }
37 | });
38 | return proxyAsValue;
39 | },
40 | // get() {
41 | // const preparedValue = {
42 | // [Symbol.toPrimitive]() {
43 | // return function () {
44 | // throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
45 | // };
46 | // }
47 | // };
48 | // Reflect.setPrototypeOf(preparedValue, value);
49 | // debugger;
50 | // return preparedValue;
51 | // },
52 | set(replacementValue: unknown) {
53 | if (replacementValue instanceof value.constructor) {
54 | value = replacementValue;
55 | return value;
56 | }
57 |
58 | const prevalue = Object(replacementValue);
59 |
60 | if (prevalue instanceof value.constructor) {
61 | value = prevalue;
62 | return value;
63 | }
64 |
65 | const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
66 | throw error;
67 | }
68 | };
69 | };
--------------------------------------------------------------------------------
/src/types/special.ts:
--------------------------------------------------------------------------------
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 | };
--------------------------------------------------------------------------------
/test/__snapshots__/index.ts.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`props tests correct JSON.stringify 1`] = `""{\\"numberValue\\":123,\\"stringValue\\":\\"123\\",\\"booleanValue\\":false,\\"objectValue\\":{}}""`;
4 |
--------------------------------------------------------------------------------
/test/addition.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { describe, test } = require('node:test');
4 | const assert = require('node:assert').strict;
5 |
6 | const BasePrototype = require('..');
7 |
8 | // eslint-disable-next-line new-cap
9 | class Base extends BasePrototype({
10 | additionalProp: 321,
11 | }) {
12 | numberValue = 123;
13 | constructor() {
14 | super();
15 | this.stringValue = '123';
16 | this.booleanValue = true;
17 | this.objectValue = {};
18 | }
19 | }
20 |
21 | const baseInstance = new Base;
22 |
23 | describe('props tests', () => {
24 |
25 | test('base instance has props', () => {
26 | const realKeys = Object.keys(baseInstance);
27 | const needKeys = ['numberValue', 'stringValue', 'booleanValue', 'objectValue'];
28 | assert.deepEqual(realKeys, needKeys);
29 | });
30 |
31 | test('JavaScript class fields allow re-definition', () => {
32 | baseInstance.numberValue = '123';
33 | assert.equal(baseInstance.numberValue, '123');
34 | });
35 |
36 | test('everything the rest is the same', () => {
37 | assert.equal(baseInstance.additionalProp, 321);
38 | assert.throws(() => {
39 | baseInstance.stringValue = 123;
40 | }, new TypeError('Type Mismatch'));
41 | assert.throws(() => {
42 | baseInstance.booleanValue = 123;
43 | }, new TypeError('Type Mismatch'));
44 | assert.throws(() => {
45 | baseInstance.objectValue = null;
46 | }, new TypeError('Type Mismatch'));
47 | });
48 |
49 | });
50 |
--------------------------------------------------------------------------------
/test/index.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { describe, expect, test } from '@jest/globals';
4 |
5 | // BasePrototype & BaseClass are the same function
6 | // go as you want for being meaningfull
7 | // or meaningless
8 | const BasePrototype = require('..');
9 | import { BaseClass, FieldConstructor, Strict } from '..';
10 |
11 | const { SymbolInitialValue } = FieldConstructor;
12 |
13 | interface IBase {
14 | get getterField(): string
15 | // eslint-disable-next-line no-unused-vars
16 | set setterField(value: string)
17 | numberValue: number
18 | stringValue: string
19 | booleanValue: boolean
20 | objectValue: object
21 | }
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 | @Strict({ someProp: 123 })
30 | class DecoratedByBase {
31 | someProp!: number;
32 | }
33 |
34 | // @Strict({ someProp: 123 })
35 | class ExtendedDecoratedByBase extends DecoratedByBase {
36 | someProp: number;
37 | constructor() {
38 | super();
39 | this.someProp = 321;
40 | decoratedSomeProp = this.someProp;
41 | }
42 | }
43 |
44 | // eslint-disable-next-line new-cap
45 | class Base extends BasePrototype({
46 | additionalProp: 321,
47 | someMethod() {
48 | return this.numberValue.valueOf();
49 | },
50 | }) implements IBase {
51 | numberValue = 123;
52 | stringValue: string;
53 | booleanValue: boolean;
54 | objectValue: object;
55 |
56 | get getterField() {
57 | const answer = `${this.stringValue}`;
58 | return answer;
59 | }
60 |
61 | set setterField(value: string) {
62 | this.stringValue = value;
63 | }
64 |
65 | constructor() {
66 | super();
67 | // debugger;
68 | this.stringValue = '123';
69 | this.booleanValue = true;
70 | this.objectValue = {};
71 | // ES2022
72 | // Object.defineProperty(this, 'getterField', {
73 | // get() {
74 | // const answer = `${this.stringValue}`;
75 | // return answer;
76 | // }
77 | // });
78 | // Object.defineProperty(this, 'setterField', {
79 | // set(value: string) {
80 | // this.stringValue = value;
81 | // }
82 | // });
83 | }
84 | }
85 | // debugger;
86 | const baseInstance = new Base;
87 | // debugger;
88 |
89 | const upperInstance = Object.create(baseInstance);
90 |
91 | class SimpleBase extends BaseClass {
92 | stringProp = '123';
93 | // ES2022
94 | // stringProp: string;
95 | // constructor() {
96 | // super();
97 | // this.stringProp = '123';
98 | // }
99 | }
100 | // debugger;
101 | const simpleInstance = new SimpleBase;
102 | // debugger;
103 |
104 | interface IFCstr {
105 | (): void
106 | new(): {
107 | [key in keyof S]: S[key]
108 | }
109 | }
110 |
111 | type TmyFunctionalInstance = { stringProp: string }
112 | // eslint-disable-next-line no-unused-vars
113 | const MyFunctionalConstructor = function (this: TmyFunctionalInstance) {
114 | this.stringProp = '123';
115 | } as IFCstr;
116 |
117 | Reflect.setPrototypeOf(MyFunctionalConstructor.prototype, new BasePrototype);
118 |
119 | const myFunctionalInstance = new MyFunctionalConstructor();
120 |
121 | class SecondaryExtend extends Base { second = 123; }
122 | class TripleExtend extends SecondaryExtend { }
123 | const tiripleExtendInstance = new TripleExtend;
124 |
125 | // eslint-disable-next-line new-cap
126 | class NetworkedExtention extends BasePrototype(tiripleExtendInstance) { }
127 |
128 | const networkedInstance = new NetworkedExtention;
129 |
130 | // eslint-disable-next-line new-cap
131 | class ExtendedArray extends BasePrototype([1, 2, 3]) { }
132 | // eslint-disable-next-line new-cap
133 | class ExtendedSet extends BasePrototype(new Set([1, 2, 3])) { }
134 |
135 | const extendedArrayInstance = new ExtendedArray;
136 | const extendedSetInstance = new ExtendedSet;
137 |
138 | const MUTATION_VALUE = -2;
139 |
140 |
141 | class MyFieldConstructorNoRe extends FieldConstructor {
142 | _value: string;
143 | constructor(value: string) {
144 | super(value);
145 | Reflect.defineProperty(this, 'enumerable', {
146 | value: true
147 | });
148 | this._value = value;
149 | }
150 | }
151 | class MyFieldConstructorReGet extends MyFieldConstructorNoRe {
152 | constructor(value: string) {
153 | super(value);
154 | const self = this;
155 | Reflect.defineProperty(this, 'enumerable', {
156 | value: true
157 | });
158 | Reflect.defineProperty(this, 'get', {
159 | get() {
160 | return function () {
161 | return self._value;
162 | };
163 | },
164 | enumerable: true
165 | });
166 | }
167 | }
168 | class MyFieldConstructorReSet extends MyFieldConstructorNoRe {
169 | constructor(value: string) {
170 | super(value);
171 | const self = this;
172 | Reflect.defineProperty(this, 'enumerable', {
173 | value: true
174 | });
175 | Reflect.defineProperty(this, 'set', {
176 | get() {
177 | return function (_value: string) {
178 | self._value = _value;
179 | };
180 | },
181 | enumerable: true
182 | });
183 | }
184 | }
185 | class MyFieldConstructor extends MyFieldConstructorReGet {
186 | constructor(value: string) {
187 | super(value);
188 | const self = this;
189 | Reflect.defineProperty(this, 'enumerable', {
190 | value: true
191 | });
192 | Reflect.defineProperty(this, 'set', {
193 | get() {
194 | return function (_value: string) {
195 | self._value = _value;
196 | };
197 | },
198 | enumerable: true
199 | });
200 | }
201 | }
202 |
203 | const myField = new MyFieldConstructor('initial value');
204 | const myFieldReGet = new MyFieldConstructorReGet('initial value for get check');
205 | const myFieldReSet = new MyFieldConstructorReSet('initial value for set check');
206 |
207 | class MadeFieldClass extends BaseClass {
208 | myField = myField as unknown | string;
209 | get [SymbolInitialValue]() {
210 | const self = this;
211 | return (fieldName: 'myField') => {
212 | if (fieldName !== 'myField') {
213 | return self[fieldName];
214 | }
215 | //@ts-ignore
216 | const answer = myField[SymbolInitialValue];
217 | return answer;
218 | };
219 | }
220 | }
221 | class SecondMadeFieldClass extends BaseClass { myField = myField as unknown | string; }
222 | const madeFieldInstance = new MadeFieldClass;
223 | const secondMadeFieldInstance = new MadeFieldClass;
224 | const thirdMadeFieldInstance = new SecondMadeFieldClass;
225 |
226 | class MadeReGet extends BaseClass { myField = myFieldReGet as unknown | string; }
227 | class MadeReSet extends BaseClass { myField = myFieldReSet as unknown | string; }
228 | const madeReGet = new MadeReGet;
229 | const madeReSet = new MadeReSet;
230 |
231 | describe('props tests', () => {
232 |
233 | test('decorators works', () => {
234 | const rgp = Reflect.getPrototypeOf;
235 | // eslint-disable-next-line no-debugger
236 | debugger;
237 | const decorated = new DecoratedByBase;
238 | debugger;
239 | const exdecorated = new ExtendedDecoratedByBase;
240 | debugger;
241 | expect(decoratedSomeProp.valueOf()).toEqual(321);
242 | expect(exdecorated.someProp.valueOf()).toEqual(321);
243 | expect(decorated.someProp.valueOf()).toEqual(123);
244 | const proto = rgp(decorated);
245 | //@ts-expect-error;
246 | expect(proto.someProp).toEqual(123);
247 | });
248 |
249 | test('base instance has props', () => {
250 | let gf: string;
251 | let sv: string;
252 | expect(Object.keys(baseInstance)).toEqual(['numberValue', 'stringValue', 'booleanValue', 'objectValue']);
253 |
254 | gf = baseInstance.getterField;
255 | expect(gf).toEqual('123');
256 | sv = baseInstance.stringValue;
257 | expect(sv.valueOf()).toEqual('123');
258 |
259 |
260 | baseInstance.setterField = '12345';
261 |
262 | gf = baseInstance.getterField;
263 | expect(gf).toEqual('12345');
264 | sv = baseInstance.stringValue;
265 | expect(sv.valueOf()).toEqual('12345');
266 |
267 | baseInstance.setterField = '123';
268 |
269 | gf = baseInstance.getterField;
270 | expect(gf).toEqual('123');
271 | sv = baseInstance.stringValue;
272 | expect(`${sv}`).toEqual('123');
273 | });
274 |
275 | test('simple instance works & strings too', () => {
276 | expect(simpleInstance.stringProp.toString()).toBe('123');
277 | expect(simpleInstance.stringProp.length).toBe(3);
278 |
279 |
280 | expect(/String$/.test(simpleInstance.stringProp.constructor.name)).toBe(true);
281 | expect(() => {
282 |
283 | // eslint-disable-next-line no-debugger
284 | debugger;
285 | // @ts-expect-error
286 | simpleInstance.stringProp = 123;
287 |
288 | }).toThrow(new TypeError('Type Mismatch'));
289 | });
290 |
291 | test('correct boolean comparison with type coercion', () => {
292 | expect(() => {
293 |
294 | const { booleanValue } = baseInstance;
295 | booleanValue != false;
296 |
297 | }).toThrow(new TypeError('Value Access Denied'));
298 | });
299 |
300 | test('fails boolean arithmetics', () => {
301 | expect(() => {
302 |
303 | // @ts-expect-error
304 | baseInstance.booleanValue + 5;
305 |
306 | }).toThrow(new ReferenceError('Value Access Denied'));
307 | });
308 |
309 | test('correct boolean assignment', () => {
310 |
311 | let { booleanValue } = baseInstance;
312 | expect(booleanValue.valueOf()).toEqual(true);
313 |
314 | // warning!
315 | // booleanValue does not rely on baseInstance anymore!
316 | // @ts-expect-error
317 | booleanValue = new Boolean(false);
318 |
319 | let value = baseInstance.booleanValue.valueOf();
320 | expect(value).toEqual(true);
321 |
322 | // @ts-expect-error
323 | baseInstance.booleanValue = new Boolean(false);
324 | value = baseInstance.booleanValue.valueOf();
325 | expect(value).toEqual(false);
326 |
327 | });
328 |
329 | test('correct JSON.stringify', () => {
330 | const stringifyResult = JSON.stringify(baseInstance);
331 | expect(stringifyResult).toMatchSnapshot();
332 | });
333 |
334 | test('correct boolean constructor', () => {
335 | expect(baseInstance.booleanValue).toBeInstanceOf(Boolean);
336 | });
337 |
338 | test('correct object assignment', () => {
339 | baseInstance.objectValue = { a: 123 };
340 | // @ts-expect-error
341 | expect(baseInstance.objectValue.a).toEqual(123);
342 | });
343 |
344 | test('correct custom field creation', () => {
345 | expect(madeFieldInstance.myField).toEqual('initial value');
346 | });
347 |
348 | test('correct custom field assignment', () => {
349 | madeFieldInstance.myField = 'replaced';
350 | //@ts-ignore
351 | const initialValue = madeFieldInstance[SymbolInitialValue]('myField');
352 | expect(initialValue).toEqual('initial value');
353 | expect(secondMadeFieldInstance.myField).toEqual('replaced');
354 | expect(thirdMadeFieldInstance.myField).toEqual('replaced');
355 |
356 | madeFieldInstance.myField = 'replaced secondary';
357 | expect(secondMadeFieldInstance.myField).toEqual('replaced secondary');
358 | expect(thirdMadeFieldInstance.myField).toEqual('replaced secondary');
359 |
360 | madeFieldInstance.myField = 'replaced';
361 | expect(secondMadeFieldInstance.myField).toEqual('replaced');
362 | expect(thirdMadeFieldInstance.myField).toEqual('replaced');
363 | });
364 |
365 | test('correct custom field no-re-assignment', () => {
366 | expect(madeReGet.myField).toEqual('initial value for get check');
367 | expect(() => {
368 |
369 | madeReGet.myField = 'replaced';
370 |
371 | }).toThrow(new TypeError('Re-Assirnment is Forbidden'));
372 | });
373 |
374 | test('correct custom field setter only', () => {
375 | madeReSet.myField = 'replaced';
376 | expect(madeReSet.myField).toEqual('initial value for set check');
377 | });
378 |
379 | test('takes error on wrong field definition', () => {
380 | expect(() => {
381 | class WrongFieldConstructor extends FieldConstructor {
382 | value: number;
383 | constructor(value: number) {
384 | super(value);
385 | this.value = value;
386 | }
387 | }
388 | const wrongField = new WrongFieldConstructor(123);
389 | class WithWrongField extends BaseClass {
390 | erroredField = wrongField;
391 | }
392 | new WithWrongField;
393 |
394 | }).toThrow();
395 | });
396 |
397 | test('correct custom missing prop search creation', () => {
398 | //@ts-ignore
399 | expect(madeFieldInstance[Symbol.toStringTag]).toEqual(undefined);
400 | //@ts-ignore
401 | expect(madeFieldInstance[Symbol.iterator]).toEqual(undefined);
402 | const util = require('util');
403 | //@ts-ignore
404 | expect(madeFieldInstance[util.inspect.custom]).toEqual(undefined);
405 | const inspected = util.inspect(madeFieldInstance);
406 | const expected = 'MadeFieldClass { myField: [Getter/Setter] }';
407 | expect(inspected).toEqual(expected);
408 | });
409 |
410 | test('wrong assignment to objects', () => {
411 |
412 | expect(() => {
413 | // @ts-expect-error
414 | baseInstance.objectValue = 123;
415 |
416 | }).toThrow(new TypeError('Type Mismatch'));
417 |
418 | expect(() => {
419 |
420 | baseInstance.objectValue = new Set();
421 |
422 | }).toThrow(new TypeError('Type Mismatch'));
423 |
424 | });
425 |
426 | test('fails number arithmetics', () => {
427 | expect(() => {
428 |
429 | baseInstance.numberValue + 5;
430 |
431 | }).toThrow();
432 | });
433 |
434 | test('correct number arithmetics using .valueOf()', () => {
435 |
436 | baseInstance.numberValue = MUTATION_VALUE;
437 |
438 | const result = baseInstance.numberValue.valueOf() + 5;
439 | expect(result).toStrictEqual(3);
440 |
441 | });
442 |
443 | test('correct number arithmetics using hinting for Symbol.toPrimitive (hint)', () => {
444 |
445 | const result = 3 + +baseInstance.numberValue;
446 | expect(result).toStrictEqual(1);
447 |
448 | });
449 |
450 | test('correct number value', () => {
451 | expect(baseInstance.numberValue.toString()).toStrictEqual(MUTATION_VALUE.toString());
452 | expect(/Number$/.test(baseInstance.numberValue.constructor.name)).toBe(true);
453 | });
454 |
455 |
456 | test('wrong assignment', () => {
457 | expect(() => {
458 | // @ts-expect-error
459 | baseInstance.booleanValue = 123;
460 |
461 | }).toThrow(new TypeError('Type Mismatch'));
462 | });
463 |
464 | test('correct null value', () => {
465 | baseInstance.nullValue = null;
466 | expect(baseInstance.nullValue).toEqual(null);
467 | });
468 |
469 | test('any assignment to null value', () => {
470 | expect(() => {
471 |
472 | baseInstance.nullValue = 123;
473 |
474 | }).toThrow(new TypeError('Type Mismatch'));
475 | });
476 |
477 |
478 | test('correct undefined value', () => {
479 | baseInstance.undefinedValue = undefined;
480 | expect(baseInstance.undefinedValue).toEqual(undefined);
481 | });
482 |
483 | test('wrong assignment to undefined value', () => {
484 | expect(() => {
485 |
486 | baseInstance.undefinedValue = 123;
487 |
488 | }).toThrow(new TypeError('Type Mismatch'));
489 | });
490 |
491 | test('correct BigInt value', () => {
492 | baseInstance.BigIntValue = BigInt(1);
493 | expect(baseInstance.BigIntValue).toEqual(BigInt(1));
494 | });
495 |
496 | test('correct assignment to BigInt value', () => {
497 | baseInstance.BigIntValue = BigInt(2);
498 | expect(baseInstance.BigIntValue).toEqual(BigInt(2));
499 | });
500 |
501 | test('wrong assignment to BigInt value', () => {
502 | expect(() => {
503 |
504 | baseInstance.BigIntValue = 123;
505 |
506 | }).toThrow(new TypeError('Type Mismatch'));
507 | });
508 |
509 | test('correct Symbol value', () => {
510 | baseInstance.SymbolValue = Symbol('test');
511 | expect(typeof baseInstance.SymbolValue).toEqual('symbol');
512 | });
513 |
514 | test('wrong assignment to BigInt value', () => {
515 | expect(() => {
516 |
517 | baseInstance.SymbolValue = 123;
518 |
519 | }).toThrow(new TypeError('Type Mismatch'));
520 | });
521 |
522 | test('correct prototype correction', () => {
523 | expect(baseInstance.additionalProp).toEqual(321);
524 | expect(baseInstance.toString).toBeInstanceOf(Function);
525 | });
526 |
527 | test('missing value fails', () => {
528 | expect(() => {
529 |
530 | baseInstance.missingValue > 1;
531 |
532 | }).toThrow(new TypeError('Attempt to Access to Undefined Prop: [ missingValue ] of Base'));
533 | });
534 |
535 | });
536 |
537 | describe('prototype mutations tests', () => {
538 |
539 | test('incorrect prototype invocation number get', () => {
540 | expect(() => {
541 |
542 | upperInstance.numberValue > 1;
543 |
544 | }).toThrow(new ReferenceError('Value Access Denied'));
545 | });
546 |
547 | test('incorrect prototype invocation number set', () => {
548 | expect(() => {
549 |
550 | upperInstance.numberValue = new Number(1);
551 |
552 | }).toThrow(new ReferenceError('Value Access Denied'));
553 | });
554 |
555 |
556 | test('incorrect prototype invocation string get', () => {
557 | expect(() => {
558 |
559 | upperInstance.stringValue > '1';
560 |
561 | }).toThrow(new ReferenceError('Value Access Denied'));
562 | });
563 |
564 | test('incorrect prototype invocation string set', () => {
565 | expect(() => {
566 |
567 | upperInstance.stringValue = new String(1);
568 |
569 | }).toThrow(new ReferenceError('Value Access Denied'));
570 | });
571 |
572 | });
573 |
574 | describe('methods tests', () => {
575 |
576 | test('functions are restricted for data type', () => {
577 |
578 | expect(() => {
579 |
580 | baseInstance.someMethod = function () { };
581 |
582 | }).toThrow(new TypeError('Functions are Restricted'));
583 |
584 | });
585 |
586 | test('proxy proto methods are SOLID', () => {
587 |
588 | const result = baseInstance.someMethod();
589 | expect(result).toBe(MUTATION_VALUE);
590 |
591 | });
592 |
593 | });
594 |
595 | describe('property re-definition works', () => {
596 |
597 | test('exact prototype invocation for correct property extraction', () => {
598 |
599 | Object.defineProperty(upperInstance, 'stringProp', {
600 | get() {
601 | const target = Reflect.getPrototypeOf(upperInstance) as {
602 | stringValue: string
603 | };
604 | return target.stringValue;
605 | }
606 | });
607 |
608 | const value = upperInstance.stringProp;
609 | expect(`${value}`).toEqual('123');
610 |
611 | });
612 | });
613 |
614 |
615 | describe('functional constructors tests', () => {
616 | test('construction made properly', () => {
617 |
618 | const { stringProp,
619 | constructor: {
620 | name
621 | }
622 | } = myFunctionalInstance;
623 | expect(name).toEqual('MyFunctionalConstructor');
624 | expect(stringProp.valueOf()).toEqual('123');
625 |
626 | });
627 | });
628 |
629 | describe('instanceof works', () => {
630 | test('for class construction', () => {
631 |
632 | expect(baseInstance).toBeInstanceOf(Base);
633 |
634 | });
635 | test('for simple construction', () => {
636 |
637 | expect(simpleInstance).toBeInstanceOf(SimpleBase);
638 |
639 | });
640 | test('for functional construction', () => {
641 |
642 | expect(myFunctionalInstance).toBeInstanceOf(MyFunctionalConstructor);
643 |
644 | });
645 | });
646 |
647 | describe('deep extend works', () => {
648 | test('class extended three times construction', () => {
649 |
650 | expect(tiripleExtendInstance).toBeInstanceOf(Base);
651 | expect(tiripleExtendInstance).toBeInstanceOf(SecondaryExtend);
652 | expect(tiripleExtendInstance).toBeInstanceOf(TripleExtend);
653 | expect(`${tiripleExtendInstance.stringValue}`).toEqual('123');
654 | expect(tiripleExtendInstance.second).toBeInstanceOf(Number);
655 |
656 | });
657 |
658 | test('network extention works', () => {
659 | expect(networkedInstance).toBeInstanceOf(NetworkedExtention);
660 |
661 | expect(() => {
662 |
663 | `${networkedInstance.stringValue}`;
664 |
665 | }).toThrow(new ReferenceError('Value Access Denied'));
666 |
667 | });
668 |
669 | test('builtin types works', () => {
670 | expect(extendedArrayInstance).toBeInstanceOf(Array);
671 | expect(extendedArrayInstance).toBeInstanceOf(ExtendedArray);
672 | expect(extendedArrayInstance[0]).toBe(1);
673 | extendedArrayInstance.unshift(0);
674 | extendedArrayInstance.push(5);
675 | expect(+extendedArrayInstance.length).toBe(5);
676 | expect(+extendedArrayInstance[0]).toBe(0);
677 | expect(+extendedArrayInstance[4]).toBe(5);
678 |
679 | expect(extendedSetInstance).toBeInstanceOf(Set);
680 | expect(extendedSetInstance).toBeInstanceOf(ExtendedSet);
681 |
682 | // JS Object.create(new Set([1, 2, 3])) is doing the same error!
683 | expect(() => {
684 |
685 | extendedSetInstance.has(0);
686 |
687 | }).toThrow(new TypeError('Method Set.prototype.has called on incompatible receiver [object Object]'));
688 |
689 | });
690 | });
691 |
--------------------------------------------------------------------------------
/test/noJest.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __extends = (this && this.__extends) || (function () {
3 | var extendStatics = function (d, b) {
4 | extendStatics = Object.setPrototypeOf ||
5 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6 | function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7 | return extendStatics(d, b);
8 | };
9 | return function (d, b) {
10 | if (typeof b !== "function" && b !== null)
11 | throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12 | extendStatics(d, b);
13 | function __() { this.constructor = d; }
14 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15 | };
16 | })();
17 | var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
18 | function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
19 | var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
20 | var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
21 | var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
22 | var _, done = false;
23 | for (var i = decorators.length - 1; i >= 0; i--) {
24 | var context = {};
25 | for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
26 | for (var p in contextIn.access) context.access[p] = contextIn.access[p];
27 | context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
28 | var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
29 | if (kind === "accessor") {
30 | if (result === void 0) continue;
31 | if (result === null || typeof result !== "object") throw new TypeError("Object expected");
32 | if (_ = accept(result.get)) descriptor.get = _;
33 | if (_ = accept(result.set)) descriptor.set = _;
34 | if (_ = accept(result.init)) initializers.unshift(_);
35 | }
36 | else if (_ = accept(result)) {
37 | if (kind === "field") initializers.unshift(_);
38 | else descriptor[key] = _;
39 | }
40 | }
41 | if (target) Object.defineProperty(target, contextIn.name, descriptor);
42 | done = true;
43 | };
44 | var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
45 | var useValue = arguments.length > 2;
46 | for (var i = 0; i < initializers.length; i++) {
47 | value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
48 | }
49 | return useValue ? value : void 0;
50 | };
51 | var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
52 | if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
53 | return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
54 | };
55 | Object.defineProperty(exports, "__esModule", { value: true });
56 | // BasePrototype & BaseClass are the same function
57 | // go as you want for being meaningfull
58 | // or meaningless
59 | var BasePrototype = require('..');
60 | var __1 = require("..");
61 | // eslint-disable-next-line new-cap
62 | var DecoratedByBase = function () {
63 | var _classDecorators = [(0, __1.Strict)({ someProp: 123 })];
64 | var _classDescriptor;
65 | var _classExtraInitializers = [];
66 | var _classThis;
67 | var DecoratedByBase = _classThis = /** @class */ (function () {
68 | function DecoratedByBase_1() {
69 | }
70 | return DecoratedByBase_1;
71 | }());
72 | __setFunctionName(_classThis, "DecoratedByBase");
73 | (function () {
74 | var _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
75 | __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
76 | DecoratedByBase = _classThis = _classDescriptor.value;
77 | if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
78 | __runInitializers(_classThis, _classExtraInitializers);
79 | })();
80 | return DecoratedByBase = _classThis;
81 | }();
82 | var ExtendedDecoratedByBase = /** @class */ (function (_super) {
83 | __extends(ExtendedDecoratedByBase, _super);
84 | function ExtendedDecoratedByBase() {
85 | var _this = _super.call(this) || this;
86 | _this.someProp = 321;
87 | return _this;
88 | }
89 | return ExtendedDecoratedByBase;
90 | }(DecoratedByBase));
91 | // eslint-disable-next-line new-cap
92 | var Base = /** @class */ (function (_super) {
93 | __extends(Base, _super);
94 | function Base() {
95 | var _this = _super.call(this) || this;
96 | _this.numberValue = 123;
97 | debugger;
98 | _this.stringValue = '123';
99 | _this.booleanValue = true;
100 | _this.objectValue = {};
101 | return _this;
102 | // ES2022
103 | // Object.defineProperty(this, 'getterField', {
104 | // get() {
105 | // const answer = `${this.stringValue}`;
106 | // return answer;
107 | // }
108 | // });
109 | // Object.defineProperty(this, 'setterField', {
110 | // set(value: string) {
111 | // this.stringValue = value;
112 | // }
113 | // });
114 | }
115 | Object.defineProperty(Base.prototype, "getterField", {
116 | get: function () {
117 | var answer = "".concat(this.stringValue);
118 | return answer;
119 | },
120 | enumerable: false,
121 | configurable: true
122 | });
123 | Object.defineProperty(Base.prototype, "setterField", {
124 | set: function (value) {
125 | this.stringValue = value;
126 | },
127 | enumerable: false,
128 | configurable: true
129 | });
130 | return Base;
131 | }(BasePrototype({
132 | additionalProp: 321,
133 | someMethod: function () {
134 | return this.numberValue.valueOf();
135 | },
136 | })));
137 | debugger;
138 | var baseInstance = new Base;
139 | console.log(baseInstance);
140 | debugger;
141 | var upperInstance = Object.create(baseInstance);
142 | console.log(upperInstance);
143 | var SimpleBase = /** @class */ (function (_super) {
144 | __extends(SimpleBase, _super);
145 | function SimpleBase() {
146 | var _this = _super !== null && _super.apply(this, arguments) || this;
147 | _this.stringProp = '123';
148 | return _this;
149 | // ES2022
150 | // stringProp: string;
151 | // constructor() {
152 | // super();
153 | // this.stringProp = '123';
154 | // }
155 | }
156 | return SimpleBase;
157 | }(__1.BaseClass));
158 | debugger;
159 | var simpleInstance = new SimpleBase;
160 | console.log(simpleInstance);
161 | debugger;
162 | var decorated = new DecoratedByBase;
163 | console.log(decorated);
164 | debugger;
165 | var exdecorated = new ExtendedDecoratedByBase;
166 | console.log(exdecorated);
167 | debugger;
168 |
--------------------------------------------------------------------------------
/test/noJest.ts:
--------------------------------------------------------------------------------
1 |
2 | // BasePrototype & BaseClass are the same function
3 | // go as you want for being meaningfull
4 | // or meaningless
5 | const BasePrototype = require('..');
6 | import { BaseClass, Strict } from '..';
7 |
8 | interface IBase {
9 | get getterField(): string
10 | // eslint-disable-next-line no-unused-vars
11 | set setterField(value: string)
12 | numberValue: number
13 | stringValue: string
14 | booleanValue: boolean
15 | objectValue: object
16 | }
17 |
18 |
19 |
20 | // eslint-disable-next-line new-cap
21 | @Strict({ someProp: 123 })
22 | class DecoratedByBase {
23 | someProp!: number;
24 | }
25 |
26 | class ExtendedDecoratedByBase extends DecoratedByBase {
27 | someProp: number;
28 | constructor() {
29 | super();
30 | this.someProp = 321;
31 | }
32 | }
33 |
34 | // eslint-disable-next-line new-cap
35 | class Base extends BasePrototype({
36 | additionalProp: 321,
37 | someMethod() {
38 | return this.numberValue.valueOf();
39 | },
40 | }) implements IBase {
41 | numberValue = 123;
42 | stringValue: string;
43 | booleanValue: boolean;
44 | objectValue: object;
45 |
46 | get getterField() {
47 | const answer = `${this.stringValue}`;
48 | return answer;
49 | }
50 |
51 | set setterField(value: string) {
52 | this.stringValue = value;
53 | }
54 |
55 | constructor() {
56 | super();
57 | debugger;
58 | this.stringValue = '123';
59 | this.booleanValue = true;
60 | this.objectValue = {};
61 | // ES2022
62 | // Object.defineProperty(this, 'getterField', {
63 | // get() {
64 | // const answer = `${this.stringValue}`;
65 | // return answer;
66 | // }
67 | // });
68 | // Object.defineProperty(this, 'setterField', {
69 | // set(value: string) {
70 | // this.stringValue = value;
71 | // }
72 | // });
73 | }
74 | }
75 | debugger;
76 | const baseInstance = new Base;
77 | console.log(baseInstance);
78 | debugger;
79 |
80 | const upperInstance = Object.create(baseInstance);
81 | console.log(upperInstance);
82 |
83 | class SimpleBase extends BaseClass {
84 | stringProp = '123';
85 | // ES2022
86 | // stringProp: string;
87 | // constructor() {
88 | // super();
89 | // this.stringProp = '123';
90 | // }
91 | }
92 |
93 | debugger;
94 | const simpleInstance = new SimpleBase;
95 | console.log(simpleInstance);
96 |
97 | debugger;
98 | const decorated = new DecoratedByBase;
99 | console.log(decorated);
100 |
101 | debugger;
102 | const exdecorated = new ExtendedDecoratedByBase;
103 | console.log(exdecorated);
104 |
105 | debugger;
106 |
--------------------------------------------------------------------------------
/tsconfig.jest.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es2023",
5 | "strict": true,
6 | "alwaysStrict": true,
7 | "strictFunctionTypes": true,
8 | "diagnostics": true,
9 | "noImplicitThis": true,
10 | "extendedDiagnostics": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "noUnusedLocals": true,
14 | "noUnusedParameters": true,
15 | "declaration": true,
16 | "sourceMap": false,
17 | "outDir": "lib",
18 | "traceResolution": false,
19 | "removeComments": true,
20 | "experimentalDecorators": true,
21 | "forceConsistentCasingInFileNames": true,
22 | "types": [
23 | "jest",
24 | "node"
25 | ]
26 | },
27 | "include": [
28 | "./test/**/*.ts"
29 | ],
30 | "exclude": [
31 | "./lib/**/*",
32 | "./coverage/**/*",
33 | "./node_modules/**/*",
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "strict": true,
6 | "alwaysStrict": true,
7 | "strictFunctionTypes": true,
8 | "diagnostics": true,
9 | "noImplicitThis": true,
10 | "extendedDiagnostics": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "noUnusedLocals": true,
14 | "noUnusedParameters": true,
15 | "declaration": true,
16 | "sourceMap": true,
17 | "outDir": "lib",
18 | "traceResolution": false,
19 | "removeComments": true,
20 | "experimentalDecorators": true,
21 | "forceConsistentCasingInFileNames": true,
22 | "types": ["node"]
23 | },
24 | "include": [
25 | "./src/**/*.ts",
26 | ],
27 | "exclude": [
28 | "./lib/**/*",
29 | "./coverage/**/*",
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------