├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── .husky └── pre-commit ├── LICENSE ├── README.md ├── jest.config.js ├── lib ├── errors.d.ts ├── errors.js ├── errors.js.map ├── fields.d.ts ├── fields.js ├── fields.js.map ├── index.d.ts ├── index.js ├── index.js.map └── types │ ├── functions.d.ts │ ├── functions.js │ ├── functions.js.map │ ├── index.d.ts │ ├── index.js │ ├── index.js.map │ ├── nullish.d.ts │ ├── nullish.js │ ├── nullish.js.map │ ├── objects.d.ts │ ├── objects.js │ ├── objects.js.map │ ├── primitives.d.ts │ ├── primitives.js │ ├── primitives.js.map │ ├── special.d.ts │ ├── special.js │ └── special.js.map ├── package-lock.json ├── package.json ├── src ├── errors.ts ├── fields.ts ├── index.ts └── types │ ├── functions.ts │ ├── index.ts │ ├── nullish.ts │ ├── objects.ts │ ├── primitives.ts │ └── special.ts ├── test ├── __snapshots__ │ └── index.ts.snap ├── addition.js ├── index.ts ├── noJest.js └── noJest.ts ├── tsconfig.jest.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | trim_trailing_whitespace = false 5 | indent_style = tab 6 | end_of_line = lf 7 | insert_final_newline = true 8 | 9 | [{package*.json,*.yml}] 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentout/typeomatica/b17f54479df39705c434c3730dc79ad934cf439f/.eslintignore -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | env: { 4 | node: true, 5 | es6: true, 6 | }, 7 | extends: [ 8 | 'eslint:recommended', 9 | 'plugin:@typescript-eslint/eslint-recommended' 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 2018, 13 | sourceType: 'module' 14 | }, 15 | rules: { 16 | indent: ['error', 'tab'], 17 | 'linebreak-style': ['error', 'unix'], 18 | quotes: ['error', 'single'], 19 | semi: ['error', 'always'], 20 | // 'no-unused-vars': 'warn', 21 | 'no-shadow': [ 22 | 'error', 23 | { 24 | builtinGlobals: true, 25 | hoist: 'all', 26 | allow: [], 27 | }, 28 | ], 29 | // 'space-before-function-paren': [ 30 | // 'warn', { 31 | // 'anonymous': 'always', 32 | // 'named': 'always', 33 | // 'asyncArrow': 'always' 34 | // } 35 | // ], 36 | 'prefer-template': 'warn', 37 | 'prefer-spread': 'warn', 38 | 'no-useless-concat': 'warn', 39 | 'prefer-rest-params': 'warn', 40 | 'prefer-destructuring': 'warn', 41 | 'no-useless-computed-key': 'warn', 42 | 'no-useless-constructor': 'warn', 43 | 'no-useless-rename': 'warn', 44 | 'no-this-before-super': 'warn', 45 | 'no-new-symbol': 'warn', 46 | 'no-duplicate-imports': 'warn', 47 | 'no-confusing-arrow': 'warn', 48 | 'no-multi-assign': 'warn', 49 | 'no-lonely-if': 'warn', 50 | 'newline-per-chained-call': 'warn', 51 | 'new-cap': 'warn', 52 | 'func-name-matching': 'error', 53 | // 'consistent-this' : 'error', 54 | 'line-comment-position': [ 55 | 'warn', 56 | { 57 | position: 'above', 58 | }, 59 | ], 60 | yoda: 'warn', 61 | }, 62 | 'overrides': [ 63 | { 64 | 'files': ['lib/**/*.js'], 65 | 'rules': { 66 | 'prefer-rest-params': 0, 67 | 'no-redeclare': 0 68 | } 69 | } 70 | ] 71 | 72 | }; 73 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | 2 | # Automatically normalize line endings for all text-based files 3 | # http://git-scm.com/docs/gitattributes#_end_of_line_conversion 4 | 5 | # For the following file types, normalize line endings to LF on 6 | # checkin and prevent conversion to CRLF when they are checked out 7 | # (this is required in order to prevent newline related issues like, 8 | # for example, after the build script is run) 9 | *.html text eol=lf 10 | *.css text eol=lf 11 | *.less text eol=lf 12 | *.scss text eol=lf 13 | *.sss text eol=lf 14 | *.sass text eol=lf 15 | *.js text eol=lf 16 | *.json text eol=lf 17 | *.yml text eol=lf 18 | *.yaml text eol=lf 19 | *.md text eol=lf 20 | *.sh text eol=lf 21 | *.txt text eol=lf 22 | *.xml text eol=lf 23 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [18.x, 20.x] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - run: npm ci 28 | - run: npm run build --if-present 29 | - run: npm test 30 | 31 | 32 | test: 33 | runs-on: ubuntu-latest 34 | 35 | steps: 36 | - uses: actions/checkout@master 37 | - name: Use Node.js 18.x 38 | uses: actions/setup-node@master 39 | with: 40 | node-version: 18.x 41 | 42 | - name: npm install 43 | run: npm install 44 | 45 | - name: Test 46 | run: npm run test:cov 47 | 48 | - name: Coveralls Parallel 49 | uses: coverallsapp/github-action@master 50 | with: 51 | github-token: ${{ secrets.github_token }} 52 | parallel: true 53 | 54 | finish: 55 | needs: test 56 | runs-on: ubuntu-latest 57 | steps: 58 | - name: Coveralls Finished 59 | uses: coverallsapp/github-action@master 60 | with: 61 | github-token: ${{ secrets.github_token }} 62 | parallel-finished: true 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | .env 4 | todo.txt 5 | back.* 6 | coverage 7 | .nyc_output 8 | .idea 9 | test/index.js 10 | .npmrc -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm test 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Mythographica → went.out@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Type ø matica 2 | 3 | [![Coverage Status](https://coveralls.io/repos/github/wentout/typeomatica/badge.svg?branch=main)](https://coveralls.io/github/wentout/typeomatica?branch=main) 4 | 5 | ![NPM](https://img.shields.io/npm/l/typeomatica) 6 | ![GitHub package.json version](https://img.shields.io/github/package-json/v/wentout/typeomatica) 7 | ![GitHub last commit](https://img.shields.io/github/last-commit/wentout/typeomatica) 8 | 9 | [**$ npm install typeomatica**](https://www.npmjs.com/package/typeomatica) 10 | 11 | 12 | This package is a part of [mnemonica](https://www.npmjs.com/package/mnemonica) project. 13 | 14 | Strict Types checker for objects which represent Data Types. 15 | 16 | # how it works 17 | 18 | see `test/index.ts` 19 | 20 | ```js 21 | 22 | class SimpleBase extends BasePrototype { 23 | stringProp = '123'; 24 | }; 25 | 26 | // nect code line will work properly 27 | simpleInstance.stringProp = '321'; 28 | 29 | // but next code line will throw TypeError('Type Mismatch') 30 | // @ts-ignore 31 | simpleInstance.stringProp = 123; 32 | 33 | ``` 34 | 35 | That is it. It will be impossible to assign anything else except of: 36 | 37 | ```js 38 | typeof something === 'string' 39 | ``` 40 | 41 | to `stringProp` in runtime. 42 | 43 | As we describe Data Types — please take a peek for tests directory: 44 | [HERE](https://github.com/wentout/typeomatica/blob/main/test/index.ts). 45 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | testMatch: ['**/test/**/index.ts'], 5 | // testMatch: ['**/test/**/index.ts', '**/test/**/addition.js'], 6 | transform : { 7 | '\\./test/*.ts$': ['ts-jest', { 8 | tsconfig : './tsconfig.jest.json' 9 | }] 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /lib/errors.d.ts: -------------------------------------------------------------------------------- 1 | export declare const ErrorsNames: { 2 | TYPE_MISMATCH: string; 3 | ACCESS_DENIED: string; 4 | MISSING_PROP: string; 5 | RIP_FUNCTIONS: string; 6 | FORBIDDEN_RE: string; 7 | }; 8 | -------------------------------------------------------------------------------- /lib/errors.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ErrorsNames = void 0; 4 | exports.ErrorsNames = { 5 | TYPE_MISMATCH: 'Type Mismatch', 6 | ACCESS_DENIED: 'Value Access Denied', 7 | MISSING_PROP: 'Attempt to Access to Undefined Prop', 8 | RIP_FUNCTIONS: 'Functions are Restricted', 9 | FORBIDDEN_RE: 'Re-Assirnment is Forbidden' 10 | }; 11 | //# sourceMappingURL=errors.js.map -------------------------------------------------------------------------------- /lib/errors.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEA,QAAA,WAAW,GAAG;IAC1B,aAAa,EAAE,eAAe;IAC9B,aAAa,EAAE,qBAAqB;IACpC,YAAY,EAAE,qCAAqC;IACnD,aAAa,EAAE,0BAA0B;IACzC,YAAY,EAAE,4BAA4B;CAC1C,CAAC"} -------------------------------------------------------------------------------- /lib/fields.d.ts: -------------------------------------------------------------------------------- 1 | declare const SymbolInitialValue: unique symbol; 2 | interface FieldDefinition { 3 | [SymbolInitialValue]: unknown; 4 | } 5 | export declare class FieldConstructor implements FieldDefinition { 6 | [SymbolInitialValue]: unknown; 7 | get get(): () => unknown; 8 | get set(): () => never; 9 | constructor(value: unknown); 10 | static get SymbolInitialValue(): symbol; 11 | } 12 | export {}; 13 | -------------------------------------------------------------------------------- /lib/fields.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.FieldConstructor = void 0; 4 | const errors_1 = require("./errors"); 5 | const SymbolInitialValue = Symbol('Initial Value'); 6 | class FieldConstructor { 7 | get get() { 8 | const self = this; 9 | return function () { 10 | return self[SymbolInitialValue]; 11 | }; 12 | } 13 | get set() { 14 | return function () { 15 | throw new TypeError(errors_1.ErrorsNames.FORBIDDEN_RE); 16 | }; 17 | } 18 | constructor(value) { 19 | this[SymbolInitialValue] = value; 20 | } 21 | static get SymbolInitialValue() { 22 | return SymbolInitialValue; 23 | } 24 | } 25 | exports.FieldConstructor = FieldConstructor; 26 | Object.freeze(FieldConstructor.prototype); 27 | Object.seal(FieldConstructor.prototype); 28 | //# sourceMappingURL=fields.js.map -------------------------------------------------------------------------------- /lib/fields.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"fields.js","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;AAEb,qCAAuC;AAEvC,MAAM,kBAAkB,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AAenD,MAAa,gBAAgB;IAE5B,IAAW,GAAG;QACb,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,OAAO;YACN,OAAO,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACjC,CAAC,CAAC;IACH,CAAC;IACD,IAAW,GAAG;QACb,OAAO;YACN,MAAM,IAAI,SAAS,CAAC,oBAAW,CAAC,YAAY,CAAC,CAAC;QAC/C,CAAC,CAAC;IACH,CAAC;IACD,YAAa,KAAc;QAC1B,IAAI,CAAC,kBAAkB,CAAC,GAAG,KAAK,CAAC;IAClC,CAAC;IACD,MAAM,KAAK,kBAAkB;QAC5B,OAAO,kBAAkB,CAAC;IAC3B,CAAC;CACD;AAnBD,4CAmBC;AAoCD,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;AAC1C,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC"} -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export declare const BaseConstructorPrototype: { 2 | (): void; 3 | new (): unknown; 4 | }; 5 | export declare class BaseClass extends BaseConstructorPrototype { 6 | } 7 | export { FieldConstructor } from './fields'; 8 | type StrictRuntime = { 9 | (...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 | --------------------------------------------------------------------------------