@pocket-architect/core 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.editorconfig ADDED
@@ -0,0 +1,15 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ trim_trailing_whitespace = true
7
+ insert_final_newline = true
8
+
9
+ [*.md]
10
+ insert_final_newline = false
11
+ trim_trailing_whitespace = false
12
+
13
+ [*.{js,json,ts,mts,yml,yaml}]
14
+ indent_size = 2
15
+ indent_style = space
package/.eslintignore ADDED
@@ -0,0 +1,2 @@
1
+ /**/*.js
2
+ build/*
package/.eslintrc.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "env": {
3
+ "browser": false,
4
+ "es6": true,
5
+ "node": true
6
+ },
7
+ "parser": "@typescript-eslint/parser",
8
+ "parserOptions": {
9
+ "project": "tsconfig.json",
10
+ "sourceType": "module",
11
+ "ecmaVersion": 2020
12
+ },
13
+ "plugins": ["@typescript-eslint", "jest"],
14
+ "extends": [
15
+ "eslint:recommended",
16
+ "plugin:@typescript-eslint/recommended",
17
+ "plugin:jest/recommended",
18
+ "prettier"
19
+ ],
20
+ "rules": {
21
+ // The following rule is enabled only to supplement the inline suppression
22
+ // examples, and because it is not a recommended rule, you should either
23
+ // disable it, or understand what it enforces.
24
+ // https://typescript-eslint.io/rules/explicit-function-return-type/
25
+ "@typescript-eslint/explicit-function-return-type": "warn"
26
+ }
27
+ }
package/.prettierrc ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "singleQuote": true,
3
+ "trailingComma": "all",
4
+ "overrides": [
5
+ {
6
+ "files": ["*.ts", "*.mts"],
7
+ "options": {
8
+ "parser": "typescript"
9
+ }
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,3 @@
1
+ import { Entity } from './Entity';
2
+ export declare abstract class AggregateRoot<T> extends Entity<T> {
3
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AggregateRoot = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var Entity_1 = require("./Entity");
6
+ var AggregateRoot = /** @class */ (function (_super) {
7
+ tslib_1.__extends(AggregateRoot, _super);
8
+ function AggregateRoot() {
9
+ return _super !== null && _super.apply(this, arguments) || this;
10
+ }
11
+ return AggregateRoot;
12
+ }(Entity_1.Entity));
13
+ exports.AggregateRoot = AggregateRoot;
14
+ //# sourceMappingURL=AggregateRoot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AggregateRoot.js","sourceRoot":"","sources":["../src/AggregateRoot.ts"],"names":[],"mappings":";;;;AAAA,mCAAkC;AAElC;IAA+C,yCAAS;IAAxD;;IAEA,CAAC;IAAD,oBAAC;AAAD,CAAC,AAFD,CAA+C,eAAM,GAEpD;AAFqB,sCAAa"}
@@ -0,0 +1,8 @@
1
+ export type EntityId = string;
2
+ export declare abstract class Entity<T> {
3
+ protected readonly _id: EntityId;
4
+ protected props: T;
5
+ protected constructor(props: T, id?: EntityId);
6
+ equals(object?: Entity<T>): boolean;
7
+ get id(): EntityId;
8
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Entity = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var uuid_by_string_1 = tslib_1.__importDefault(require("uuid-by-string"));
6
+ var cuid2_1 = require("@paralleldrive/cuid2");
7
+ var isEntity = function (v) {
8
+ return v instanceof Entity;
9
+ };
10
+ var Entity = /** @class */ (function () {
11
+ function Entity(props, id) {
12
+ this._id = id ? id : (0, uuid_by_string_1.default)((0, cuid2_1.createId)(), (0, uuid_by_string_1.default)(this.constructor.name));
13
+ this.props = props;
14
+ }
15
+ Entity.prototype.equals = function (object) {
16
+ if (object === null || object === undefined) {
17
+ return false;
18
+ }
19
+ if (this === object) {
20
+ return true;
21
+ }
22
+ if (!isEntity(object)) {
23
+ return false;
24
+ }
25
+ return this._id == object._id;
26
+ };
27
+ Object.defineProperty(Entity.prototype, "id", {
28
+ get: function () {
29
+ return this._id;
30
+ },
31
+ enumerable: false,
32
+ configurable: true
33
+ });
34
+ return Entity;
35
+ }());
36
+ exports.Entity = Entity;
37
+ //# sourceMappingURL=Entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Entity.js","sourceRoot":"","sources":["../src/Entity.ts"],"names":[],"mappings":";;;;AAAA,0EAAuC;AACvC,8CAA+C;AAE/C,IAAM,QAAQ,GAAG,UAAI,CAAY;IAC/B,OAAO,CAAC,YAAY,MAAM,CAAA;AAC5B,CAAC,CAAA;AAID;IAIE,gBAAsB,KAAQ,EAAE,EAAa;QAC3C,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAA,wBAAU,EAAC,IAAA,gBAAQ,GAAE,EAAE,IAAA,wBAAU,EAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/E,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;IAEM,uBAAM,GAAb,UAAc,MAAkB;QAC9B,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC5C,OAAO,KAAK,CAAA;QACd,CAAC;QAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,KAAK,CAAA;QACd,CAAC;QAED,OAAO,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,CAAA;IAC/B,CAAC;IAED,sBAAI,sBAAE;aAAN;YACE,OAAO,IAAI,CAAC,GAAG,CAAA;QACjB,CAAC;;;OAAA;IACH,aAAC;AAAD,CAAC,AA5BD,IA4BC;AA5BqB,wBAAM"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var tslib_1 = require("tslib");
4
+ var Entity_1 = require("./Entity");
5
+ var TestEntity = /** @class */ (function (_super) {
6
+ tslib_1.__extends(TestEntity, _super);
7
+ function TestEntity() {
8
+ return _super !== null && _super.apply(this, arguments) || this;
9
+ }
10
+ TestEntity.create = function (props, id) {
11
+ return new TestEntity(props, id);
12
+ };
13
+ return TestEntity;
14
+ }(Entity_1.Entity));
15
+ describe('Entity', function () {
16
+ var entity;
17
+ beforeAll(function () {
18
+ entity = TestEntity.create({ name: 'test' }, '1');
19
+ });
20
+ test('base', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
21
+ var entityNew, entity2;
22
+ return tslib_1.__generator(this, function (_a) {
23
+ entityNew = TestEntity.create({ name: 'test2' });
24
+ expect(entityNew.id.length).toEqual(36); // random id
25
+ entity2 = TestEntity.create({ name: 'test2' }, '1');
26
+ expect(entity.equals(entity2)).toBeTruthy(); // same id
27
+ expect(entity.equals(entity)).toBeTruthy(); // same instance
28
+ expect(entity.equals(null)).toBeFalsy(); // null
29
+ expect(entity.equals({ id: '1' })).toBeFalsy(); // not Entity
30
+ expect(entity.id).toEqual('1');
31
+ return [2 /*return*/];
32
+ });
33
+ }); });
34
+ });
35
+ //# sourceMappingURL=Entity.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Entity.spec.js","sourceRoot":"","sources":["../src/Entity.spec.ts"],"names":[],"mappings":";;;AAAA,mCAAkC;AAKlC;IAAyB,sCAAiB;IAA1C;;IAIA,CAAC;IAHQ,iBAAM,GAAb,UAAc,KAAgB,EAAE,EAAU;QACxC,OAAO,IAAI,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACnC,CAAC;IACH,iBAAC;AAAD,CAAC,AAJD,CAAyB,eAAM,GAI9B;AAED,QAAQ,CAAC,QAAQ,EAAE;IACjB,IAAI,MAAkB,CAAC;IAEvB,SAAS,CAAC;QACR,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,EAAE;;;YACL,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YACvD,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY;YAE/C,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;YAC1D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU;YACvD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,gBAAgB;YAC5D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO;YAChD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAa,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,aAAa;YACzE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;;;SAChC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ interface ValueObjectProps {
2
+ [index: string]: any;
3
+ }
4
+ export declare abstract class ValueObject<T extends ValueObjectProps> {
5
+ readonly props: T;
6
+ protected constructor(props: T);
7
+ equals(vo?: ValueObject<T>): boolean;
8
+ }
9
+ export {};
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValueObject = void 0;
4
+ var shallow_equal_object_1 = require("shallow-equal-object");
5
+ var ValueObject = /** @class */ (function () {
6
+ function ValueObject(props) {
7
+ this.props = Object.freeze(props);
8
+ }
9
+ ValueObject.prototype.equals = function (vo) {
10
+ var props = (vo === null || vo === void 0 ? void 0 : vo.props) || vo;
11
+ if (vo === null || vo === undefined) {
12
+ return false;
13
+ }
14
+ if (props === undefined) {
15
+ return false;
16
+ }
17
+ return (0, shallow_equal_object_1.shallowEqual)(this.props, props);
18
+ };
19
+ return ValueObject;
20
+ }());
21
+ exports.ValueObject = ValueObject;
22
+ //# sourceMappingURL=ValueObject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValueObject.js","sourceRoot":"","sources":["../src/ValueObject.ts"],"names":[],"mappings":";;;AAAA,6DAAoD;AAOpD;IAGE,qBAAuB,KAAQ;QAC7B,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAEM,4BAAM,GAAb,UAAe,EAAmB;QAChC,IAAM,KAAK,GAAG,CAAA,EAAE,aAAF,EAAE,uBAAF,EAAE,CAAE,KAAK,KAAI,EAAE,CAAC;QAC9B,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAA,mCAAY,EAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IACxC,CAAC;IACH,kBAAC;AAAD,CAAC,AAjBD,IAiBC;AAjBqB,kCAAW"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var tslib_1 = require("tslib");
4
+ var ValueObject_1 = require("./ValueObject");
5
+ var TestValueObject = /** @class */ (function (_super) {
6
+ tslib_1.__extends(TestValueObject, _super);
7
+ function TestValueObject() {
8
+ return _super !== null && _super.apply(this, arguments) || this;
9
+ }
10
+ TestValueObject.create = function (props) {
11
+ return new TestValueObject(props);
12
+ };
13
+ return TestValueObject;
14
+ }(ValueObject_1.ValueObject));
15
+ describe('ValueObject', function () {
16
+ var entity;
17
+ beforeAll(function () {
18
+ entity = TestValueObject.create({ name: 'test' });
19
+ });
20
+ test('base', function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
21
+ var entity2;
22
+ return tslib_1.__generator(this, function (_a) {
23
+ entity2 = TestValueObject.create({ name: 'test2' });
24
+ expect(entity.equals(entity2)).toBeFalsy(); // same id
25
+ expect(entity.equals(entity)).toBeTruthy(); // same instance
26
+ expect(entity.equals(null)).toBeFalsy(); // null
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ expect(entity.equals({ name: 'test' })).toBeTruthy(); // same fields
29
+ return [2 /*return*/];
30
+ });
31
+ }); });
32
+ });
33
+ //# sourceMappingURL=ValueObject.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValueObject.spec.js","sourceRoot":"","sources":["../src/ValueObject.spec.ts"],"names":[],"mappings":";;;AAAA,6CAA4C;AAK5C;IAA8B,2CAAsB;IAApD;;IAIA,CAAC;IAHQ,sBAAM,GAAb,UAAc,KAAgB;QAC5B,OAAO,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IACH,sBAAC;AAAD,CAAC,AAJD,CAA8B,yBAAW,GAIxC;AAED,QAAQ,CAAC,aAAa,EAAE;IACtB,IAAI,MAAuB,CAAC;IAE5B,SAAS,CAAC;QACR,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,EAAE;;;YACL,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YAC1D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU;YACtD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,gBAAgB;YAC5D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,OAAO;YAChD,+DAA+D;YAC/D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,cAAc;;;SAC1E,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Entity, EntityId } from './Entity';
2
+ import { ValueObject } from './ValueObject';
3
+ import { AggregateRoot } from './AggregateRoot';
4
+ export { Entity, EntityId, ValueObject, AggregateRoot };
package/build/index.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AggregateRoot = exports.ValueObject = exports.Entity = void 0;
4
+ var Entity_1 = require("./Entity");
5
+ Object.defineProperty(exports, "Entity", { enumerable: true, get: function () { return Entity_1.Entity; } });
6
+ var ValueObject_1 = require("./ValueObject");
7
+ Object.defineProperty(exports, "ValueObject", { enumerable: true, get: function () { return ValueObject_1.ValueObject; } });
8
+ var AggregateRoot_1 = require("./AggregateRoot");
9
+ Object.defineProperty(exports, "AggregateRoot", { enumerable: true, get: function () { return AggregateRoot_1.AggregateRoot; } });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mCAA4C;AAK1C,uFALO,eAAM,OAKP;AAJR,6CAA4C;AAM1C,4FANO,yBAAW,OAMP;AALb,iDAAgD;AAM9C,8FANO,6BAAa,OAMP"}
package/jest.config.js ADDED
@@ -0,0 +1,18 @@
1
+ module.exports = {
2
+ testEnvironment: 'node',
3
+ preset: 'ts-jest/presets/default-esm',
4
+ transform: {
5
+ '^.+\\.m?[tj]s?$': ['ts-jest', { useESM: true }],
6
+ },
7
+ moduleNameMapper: {
8
+ '^(\\.{1,2}/.*)\\.(m)?js$': '$1',
9
+ },
10
+ testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(m)?ts$',
11
+ coverageDirectory: 'coverage',
12
+ collectCoverageFrom: [
13
+ 'src/**/*.ts',
14
+ 'src/**/*.mts',
15
+ '!src/**/*.d.ts',
16
+ '!src/**/*.d.mts',
17
+ ],
18
+ };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@pocket-architect/core",
3
+ "version": "0.1.5",
4
+ "description": "",
5
+ "main": "build/index.js",
6
+ "scripts": {
7
+ "prepublishOnly": "npm run build && npm version patch",
8
+ "clean": "rimraf coverage build tmp",
9
+ "prebuild": "npm run lint",
10
+ "build": "tsc -p tsconfig.json",
11
+ "build:watch": "tsc -w -p tsconfig.json",
12
+ "build:release": "npm run clean && tsc -p tsconfig.release.json",
13
+ "lint": "eslint . --ext .ts --ext .mts",
14
+ "test": "jest --coverage",
15
+ "prettier": "prettier --config .prettierrc --write .",
16
+ "test:watch": "jest --watch"
17
+ },
18
+ "dependencies": {
19
+ "@paralleldrive/cuid2": "^2.2.2",
20
+ "shallow-equal-object": "^1.1.1",
21
+ "uuid-by-string": "^4.0.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/jest": "^29.5.11",
25
+ "@typescript-eslint/eslint-plugin": "^6.18.0",
26
+ "@typescript-eslint/parser": "^6.18.0",
27
+ "eslint": "^8.56.0",
28
+ "eslint-config-prettier": "^9.1.0",
29
+ "eslint-plugin-jest": "^27.6.1",
30
+ "jest": "^29.7.0",
31
+ "rimraf": "^5.0.5",
32
+ "ts-jest": "^29.1.0",
33
+ "ts-node": "^10.9.1",
34
+ "tslib": "^2.6.2",
35
+ "typescript": "^5.2.2"
36
+ },
37
+ "author": "Vitalii Savchuk <esvit666@gmail.com>",
38
+ "license": "MIT"
39
+ }
@@ -0,0 +1,5 @@
1
+ import { Entity } from './Entity';
2
+
3
+ export abstract class AggregateRoot<T> extends Entity<T> {
4
+
5
+ }
@@ -0,0 +1,30 @@
1
+ import { Entity } from './Entity';
2
+
3
+ interface TestProps {
4
+ name: string;
5
+ }
6
+ class TestEntity extends Entity<TestProps> {
7
+ static create(props: TestProps, id?:string): TestEntity {
8
+ return new TestEntity(props, id);
9
+ }
10
+ }
11
+
12
+ describe('Entity', () => {
13
+ let entity: TestEntity;
14
+
15
+ beforeAll(() => {
16
+ entity = TestEntity.create({ name: 'test' }, '1');
17
+ });
18
+
19
+ test('base', async () => {
20
+ const entityNew = TestEntity.create({ name: 'test2' });
21
+ expect(entityNew.id.length).toEqual(36); // random id
22
+
23
+ const entity2 = TestEntity.create({ name: 'test2' }, '1');
24
+ expect(entity.equals(entity2)).toBeTruthy(); // same id
25
+ expect(entity.equals(entity)).toBeTruthy(); // same instance
26
+ expect(entity.equals(null)).toBeFalsy(); // null
27
+ expect(entity.equals(<TestEntity>{ id: '1' })).toBeFalsy(); // not Entity
28
+ expect(entity.id).toEqual('1');
29
+ });
30
+ });
package/src/Entity.ts ADDED
@@ -0,0 +1,38 @@
1
+ import createUUID from 'uuid-by-string'
2
+ import { createId } from '@paralleldrive/cuid2'
3
+
4
+ const isEntity = <T>(v: Entity<T>): v is Entity<T> => {
5
+ return v instanceof Entity
6
+ }
7
+
8
+ export type EntityId = string;
9
+
10
+ export abstract class Entity<T> {
11
+ protected readonly _id: EntityId;
12
+ protected props: T
13
+
14
+ protected constructor(props: T, id?: EntityId) {
15
+ this._id = id ? id : createUUID(createId(), createUUID(this.constructor.name));
16
+ this.props = props
17
+ }
18
+
19
+ public equals(object?: Entity<T>): boolean {
20
+ if (object === null || object === undefined) {
21
+ return false
22
+ }
23
+
24
+ if (this === object) {
25
+ return true
26
+ }
27
+
28
+ if (!isEntity(object)) {
29
+ return false
30
+ }
31
+
32
+ return this._id == object._id
33
+ }
34
+
35
+ get id(): EntityId {
36
+ return this._id
37
+ }
38
+ }
@@ -0,0 +1,27 @@
1
+ import { ValueObject } from './ValueObject';
2
+
3
+ interface TestProps {
4
+ name: string;
5
+ }
6
+ class TestValueObject extends ValueObject<TestProps> {
7
+ static create(props: TestProps): TestValueObject {
8
+ return new TestValueObject(props);
9
+ }
10
+ }
11
+
12
+ describe('ValueObject', () => {
13
+ let entity: TestValueObject;
14
+
15
+ beforeAll(() => {
16
+ entity = TestValueObject.create({ name: 'test' });
17
+ });
18
+
19
+ test('base', async () => {
20
+ const entity2 = TestValueObject.create({ name: 'test2' });
21
+ expect(entity.equals(entity2)).toBeFalsy(); // same id
22
+ expect(entity.equals(entity)).toBeTruthy(); // same instance
23
+ expect(entity.equals(null)).toBeFalsy(); // null
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ expect(entity.equals(<any>{ name: 'test' })).toBeTruthy(); // same fields
26
+ });
27
+ });
@@ -0,0 +1,25 @@
1
+ import { shallowEqual } from "shallow-equal-object";
2
+
3
+ interface ValueObjectProps {
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ [index: string]: any;
6
+ }
7
+
8
+ export abstract class ValueObject<T extends ValueObjectProps> {
9
+ public readonly props: T;
10
+
11
+ protected constructor (props: T) {
12
+ this.props = Object.freeze(props);
13
+ }
14
+
15
+ public equals (vo?: ValueObject<T>) : boolean {
16
+ const props = vo?.props || vo;
17
+ if (vo === null || vo === undefined) {
18
+ return false;
19
+ }
20
+ if (props === undefined) {
21
+ return false;
22
+ }
23
+ return shallowEqual(this.props, props)
24
+ }
25
+ }
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { Entity, EntityId } from './Entity';
2
+ import { ValueObject } from './ValueObject';
3
+ import { AggregateRoot } from './AggregateRoot';
4
+
5
+ export {
6
+ Entity,
7
+ EntityId,
8
+ ValueObject,
9
+ AggregateRoot
10
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es5",
4
+ "module": "commonjs",
5
+ "lib": [
6
+ "es2017",
7
+ "es2018.asynciterable"
8
+ ],
9
+ "moduleResolution": "node",
10
+ "rootDir": "./src",
11
+ "outDir": "build",
12
+ "allowSyntheticDefaultImports": true,
13
+ "importHelpers": true,
14
+ "alwaysStrict": true,
15
+ "sourceMap": true,
16
+ "declaration": true,
17
+ "esModuleInterop": true,
18
+ "forceConsistentCasingInFileNames": true,
19
+ "noFallthroughCasesInSwitch": true,
20
+ "noImplicitReturns": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "noImplicitAny": false,
24
+ "noImplicitThis": false,
25
+ "strictNullChecks": false,
26
+ "experimentalDecorators": true,
27
+ "skipLibCheck": true
28
+ },
29
+ "include": ["**/*", "__tests__/**/*"]
30
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "sourceMap": false,
6
+ "removeComments": true
7
+ },
8
+ "include": ["**/*"]
9
+ }