diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b8e8982a..2f7774a5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,6 +7,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc - uses: ./.github/actions/setup - name: Run ESLint check run: yarn lint:ci @@ -15,6 +18,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc - uses: ./.github/actions/setup - name: Run unit tests uses: ArtiomTr/jest-coverage-report-action@v2 @@ -28,6 +34,9 @@ jobs: STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc - name: Setup environment uses: ./.github/actions/setup @@ -99,6 +108,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc - uses: ./.github/actions/setup - name: Build the package run: yarn build diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index 091897d1..9e811939 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -7,6 +7,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc - uses: ./.github/actions/setup - name: Run ESLint check run: yarn lint:ci @@ -15,6 +18,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc - uses: ./.github/actions/setup - name: Run unit tests uses: ArtiomTr/jest-coverage-report-action@v2 @@ -28,6 +34,9 @@ jobs: STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc - uses: ./.github/actions/setup @@ -40,6 +49,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version-file: .nvmrc - uses: ./.github/actions/setup - name: Build the package run: yarn build diff --git a/src/utils/EventBus/EventBus.ts b/src/utils/EventBus/EventBus.ts new file mode 100644 index 00000000..f5ffa1f7 --- /dev/null +++ b/src/utils/EventBus/EventBus.ts @@ -0,0 +1,4 @@ +/** + * Provides an event bus for using in the document model + */ +export class EventBus extends EventTarget {} diff --git a/src/utils/EventBus/events/BlockAddedEvent.ts b/src/utils/EventBus/events/BlockAddedEvent.ts new file mode 100644 index 00000000..2a7bc1fe --- /dev/null +++ b/src/utils/EventBus/events/BlockAddedEvent.ts @@ -0,0 +1,30 @@ +import type { BlockNodeSerialized } from '../../../entities/BlockNode/types/index.js'; +import type { EventAction } from '../types/EventAction.js'; +import type { EventPayloadBase } from '../types/EventPayloadBase.js'; +import type { BlockIndex } from '../types/indexing.js'; +import { EventType } from '../types/EventType.js'; + +/** + * Add Block Event Payload + */ +interface BlockAddedEventPayload extends EventPayloadBase { + /** + * The data of the added block + */ + data: BlockNodeSerialized; +} + +/** + * Add Block Custom Event + */ +export class BlockAddedEvent extends CustomEvent { + /** + * Constructor + * + * @param payload - The event payload + */ + constructor(payload: BlockAddedEventPayload) { + // Stryker disable next-line ObjectLiteral + super(EventType.Changed, { detail: payload }); + } +} diff --git a/src/utils/EventBus/events/BlockModifiedEvent.ts b/src/utils/EventBus/events/BlockModifiedEvent.ts new file mode 100644 index 00000000..0440627b --- /dev/null +++ b/src/utils/EventBus/events/BlockModifiedEvent.ts @@ -0,0 +1,30 @@ +import type { BlockNodeSerialized } from '../../../entities/BlockNode/types/index.js'; +import type { EventAction } from '../types/EventAction.js'; +import type { EventPayloadBase } from '../types/EventPayloadBase.js'; +import type { BlockIndex } from '../types/indexing.js'; +import { EventType } from '../types/EventType.js'; + +/** + * Modify Block Event Payload + */ +interface BlockModifiedEventPayload extends EventPayloadBase { + /** + * The data of the modified block + */ + data: BlockNodeSerialized; +} + +/** + * Modify Block Custom Event + */ +export class BlockModifiedEvent extends CustomEvent { + /** + * Constructor + * + * @param payload - The event payload + */ + constructor(payload: BlockModifiedEventPayload) { + // Stryker disable next-line ObjectLiteral + super(EventType.Changed, { detail: payload }); + } +} diff --git a/src/utils/EventBus/events/BlockRemovedEvent.ts b/src/utils/EventBus/events/BlockRemovedEvent.ts new file mode 100644 index 00000000..b9d15c22 --- /dev/null +++ b/src/utils/EventBus/events/BlockRemovedEvent.ts @@ -0,0 +1,30 @@ +import type { EventAction } from '../types/EventAction.js'; +import type { BlockNodeSerialized } from '../../../entities/BlockNode/types/index.js'; +import type { EventPayloadBase } from '../types/EventPayloadBase.js'; +import type { BlockIndex } from '../types/indexing.js'; +import { EventType } from '../types/EventType.js'; + +/** + * Remove Block Event Payload + */ +interface BlockRemovedEventPayload extends EventPayloadBase { + /** + * The data of the removed block + */ + data: BlockNodeSerialized; +} + +/** + * Remove Block Custom Event + */ +export class BlockRemovedEvent extends CustomEvent { + /** + * Constructor + * + * @param payload - The event payload + */ + constructor(payload: BlockRemovedEventPayload) { + // Stryker disable next-line ObjectLiteral + super(EventType.Changed, { detail: payload }); + } +} diff --git a/src/utils/EventBus/types/EventAction.ts b/src/utils/EventBus/types/EventAction.ts new file mode 100644 index 00000000..96a826d1 --- /dev/null +++ b/src/utils/EventBus/types/EventAction.ts @@ -0,0 +1,19 @@ +/** + * Enumeration of the possible event actions + */ +export enum EventAction { + /** + * Event indicating that some new information was added to the document model + */ + Added = 'added', + + /** + * Event indicating that some information was removed from the document model + */ + Removed = 'removed', + + /** + * Event indicating that some existing information was modified in the document model + */ + Modified = 'modified', +} diff --git a/src/utils/EventBus/types/EventMap.ts b/src/utils/EventBus/types/EventMap.ts new file mode 100644 index 00000000..cb13f432 --- /dev/null +++ b/src/utils/EventBus/types/EventMap.ts @@ -0,0 +1,16 @@ +import type { EventType } from './EventType.js'; +import type { BlockAddedEvent } from '../events/BlockAddedEvent.js'; +import type { BlockModifiedEvent } from '../events/BlockModifiedEvent.js'; +import type { BlockRemovedEvent } from '../events/BlockRemovedEvent.js'; + +/** + * Alias for all block events + */ +type BlockEvents = BlockAddedEvent | BlockModifiedEvent | BlockRemovedEvent; + +/** + * Map of all events that can be emitted inside the DocumentModel + */ +export type EventMap = { + [EventType.Changed]: BlockEvents; +}; diff --git a/src/utils/EventBus/types/EventPayloadBase.ts b/src/utils/EventBus/types/EventPayloadBase.ts new file mode 100644 index 00000000..07f1dcc6 --- /dev/null +++ b/src/utils/EventBus/types/EventPayloadBase.ts @@ -0,0 +1,22 @@ +import type { EventAction } from './EventAction.js'; +import type { Index as IndexType } from './indexing.js'; + +/** + * Common fields for all events related to the document model + */ +export interface EventPayloadBase { + /** + * The index of changed information + */ + index: Index; + + /** + * The action that was performed on the information + */ + action: Action; + + /** + * The data of the changed information + */ + data: unknown; +} diff --git a/src/utils/EventBus/types/EventTarget.d.ts b/src/utils/EventBus/types/EventTarget.d.ts new file mode 100644 index 00000000..1ed7bea5 --- /dev/null +++ b/src/utils/EventBus/types/EventTarget.d.ts @@ -0,0 +1,10 @@ +import type { EventMap } from './EventMap.js'; + +/** + * Augment EventTarget's addEventListener method to accept CustomEvent + */ +declare global { + interface EventTarget { + addEventListener(type: T, listener: (event: EventMap[T]) => void): void; + } +} diff --git a/src/utils/EventBus/types/EventType.ts b/src/utils/EventBus/types/EventType.ts new file mode 100644 index 00000000..501b7ef3 --- /dev/null +++ b/src/utils/EventBus/types/EventType.ts @@ -0,0 +1,9 @@ +/** + * Event types enum that can be emitted by the document model + */ +export enum EventType { + /** + * The document model has been changed + */ + Changed = 'changed', +} diff --git a/src/utils/EventBus/types/indexing.ts b/src/utils/EventBus/types/indexing.ts new file mode 100644 index 00000000..87604543 --- /dev/null +++ b/src/utils/EventBus/types/indexing.ts @@ -0,0 +1,41 @@ +import type { BlockTuneName, DataKey } from '../../../entities/index.js'; + +/** + * Alias for a document id + */ +type DocumentId = string; + +/** + * Numeric id for a block node + */ +type BlockIndexAlias = number; + +/** + * Index for a document node + */ +export type DocumentIndex = DocumentId; + +/** + * Index for a block node + */ +export type BlockIndex = `${DocumentIndex}:${BlockIndexAlias}`; + +/** + * Numeric index for data or tune changes in block node + */ +type StartIndex = number; + +/** + * Index for data changes in block node + */ +export type DataIndex = `${BlockIndex}:data@${DataKey}:${StartIndex}`; + +/** + * Index for tune changes in block node + */ +export type TuneIndex = `${BlockIndex}:tune@${BlockTuneName}`; + +/** + * Possible index types + */ +export type Index = DocumentIndex | BlockIndex | DataIndex | TuneIndex; diff --git a/stryker.conf.mjs b/stryker.conf.mjs index f8e67675..08cea5a9 100644 --- a/stryker.conf.mjs +++ b/stryker.conf.mjs @@ -25,6 +25,10 @@ const config = { checkers: ["typescript"], timeoutMS: 10000, mutate: ["./src/**/*.ts", "!./src/**/__mocks__/*.ts", "!./src/**/*.spec.ts"], + /* + * In some cases PRs might not have any unit-tests + */ + allowEmpty: true, }; export default config;