Skip to content

Commit

Permalink
feat(core): change from stamps to TypeScript classes (#4095)
Browse files Browse the repository at this point in the history
Refs #3481

BREAKING CHANGE: IdentityManager from apidom-core package became a class and requires to be instantiated with new operator.
  • Loading branch information
char0n committed May 14, 2024
1 parent b84d9cb commit 3bb7131
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 72 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/apidom-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"ramda": "~0.30.0",
"ramda-adjunct": "^5.0.0",
"short-unique-id": "^5.0.2",
"stampit": "^4.3.2"
"ts-mixer": "^6.0.3"
},
"files": [
"cjs/",
Expand Down
113 changes: 49 additions & 64 deletions packages/apidom-core/src/identity/index.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,60 @@
import { Element, StringElement } from 'minim';
import stampit from 'stampit';
import ShortUniqueId from 'short-unique-id';

import ElementIdentityError from './errors/ElementIdentityError';
import { isElement, isStringElement } from '../predicates';

export interface IdentityManager<T extends Element = Element> {
length: number;
uuid: ShortUniqueId;
identityMap: WeakMap<T, StringElement>;
export class IdentityManager {
protected readonly uuid: ShortUniqueId;

identify(this: IdentityManager<T>, element: T): StringElement;
forget(this: IdentityManager<T>, element: T): boolean;
generateId(this: IdentityManager<T>): string;
}
protected readonly identityMap: WeakMap<Element, StringElement>;

// @TODO(oliwia.rogala@smartbear.com): transforming this stamp to class will break backward compatibility
export const IdentityManager: stampit.Stamp<IdentityManager> = stampit({
props: {
uuid: null,
length: null,
identityMap: null,
},
init(this: IdentityManager, { length = 6 } = {}) {
this.length = 6;
constructor({ length = 6 } = {}) {
this.uuid = new ShortUniqueId({ length });
this.identityMap = new WeakMap();
},
methods: {
identify<T extends Element>(this: IdentityManager, element: T): StringElement {
if (!isElement(element)) {
throw new ElementIdentityError(
'Cannot not identify the element. `element` is neither structurally compatible nor a subclass of an Element class.',
{
value: element,
},
);
}

// use already assigned identity
if (
element.meta.hasKey('id') &&
isStringElement(element.meta.get('id')) &&
!element.meta.get('id').equals('')
) {
return element.id;
}

// assign identity in immutable way
if (this.identityMap.has(element)) {
return this.identityMap.get(element)!;
}

// return element identity
const id = new StringElement(this.generateId());
this.identityMap.set(element, id);
return id;
},

forget<T extends Element>(this: IdentityManager, element: T): boolean {
if (this.identityMap.has(element)) {
this.identityMap.delete(element);
return true;
}
return false;
},

generateId(this: IdentityManager): string {
return this.uuid.randomUUID();
},
},
});
}

identify<T extends Element>(this: IdentityManager, element: T): StringElement {
if (!isElement(element)) {
throw new ElementIdentityError(
'Cannot not identify the element. `element` is neither structurally compatible nor a subclass of an Element class.',
{
value: element,
},
);
}

// use already assigned identity
if (
element.meta.hasKey('id') &&
isStringElement(element.meta.get('id')) &&
!element.meta.get('id').equals('')
) {
return element.id;
}

// assign identity in immutable way
if (this.identityMap.has(element)) {
return this.identityMap.get(element)!;
}

// return element identity
const id = new StringElement(this.generateId());
this.identityMap.set(element, id);
return id;
}

forget<T extends Element>(element: T): boolean {
if (this.identityMap.has(element)) {
this.identityMap.delete(element);
return true;
}
return false;
}

generateId() {
return this.uuid.randomUUID();
}
}

export const defaultIdentityManager = IdentityManager({ length: 6 });
export const defaultIdentityManager = new IdentityManager();
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const plugin =

return {
pre() {
identityManager = IdentityManager({ length });
identityManager = new IdentityManager({ length });
},
visitor: {
enter<T extends Element>(element: T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const plugin =

return {
pre() {
identityManager = IdentityManager({ length });
identityManager = new IdentityManager({ length });
},
visitor: {
enter<T extends Element>(element: T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import Reference from '../../../Reference';
const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];

// initialize element identity manager
const identityManager = IdentityManager();
const identityManager = new IdentityManager();

const AsyncApi2DereferenceVisitor = stampit({
props: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import Reference from '../../../Reference';
const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];

// initialize element identity manager
const identityManager = IdentityManager();
const identityManager = new IdentityManager();

const OpenApi2DereferenceVisitor = stampit({
props: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { AncestorLineage } from '../../util';
const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];

// initialize element identity manager
const identityManager = IdentityManager();
const identityManager = new IdentityManager();

// eslint-disable-next-line @typescript-eslint/naming-convention
const OpenApi3_0DereferenceVisitor = stampit({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import EvaluationJsonSchemaUriError from '../../../errors/EvaluationJsonSchemaUr
const visitAsync = visit[Symbol.for('nodejs.util.promisify.custom')];

// initialize element identity manager
const identityManager = IdentityManager();
const identityManager = new IdentityManager();

// eslint-disable-next-line @typescript-eslint/naming-convention
const OpenApi3_1DereferenceVisitor = stampit({
Expand Down

0 comments on commit 3bb7131

Please sign in to comment.