Skip to content

Commit

Permalink
refactor: introduce EnumRecord utility methods (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
timkurvers committed Apr 18, 2024
1 parent 74ca112 commit baf3387
Show file tree
Hide file tree
Showing 12 changed files with 9,134 additions and 11,863 deletions.
6 changes: 6 additions & 0 deletions babel.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' }}],
'@babel/preset-typescript',
],
};
3 changes: 2 additions & 1 deletion jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ module.exports = {
coverageDirectory: './coverage/',
moduleFileExtensions: ['js', 'ts'],
testMatch: [
'**/spec/**/*.spec.js',
'**/*.test.js',
'**/*.test.ts',
],
verbose: true,
};
20,859 changes: 9,033 additions & 11,826 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@
"fengari": "0.1.4"
},
"devDependencies": {
"@babel/preset-env": "7.24.4",
"@babel/preset-typescript": "7.24.1",
"@commitlint/cli": "18.4.4",
"@commitlint/config-conventional": "18.4.4",
"@types/jest": "29.5.12",
"@typescript-eslint/eslint-plugin": "6.19.0",
"eslint": "8.56.0",
"eslint-plugin-import": "2.29.1",
"husky": "^4.3.6",
"jest": "26.0.1",
"jest": "29.7.0",
"lint-staged": "15.2.0",
"typescript": "^5.2.2",
"vite": "^5.0.13"
Expand Down
5 changes: 0 additions & 5 deletions spec/.eslintrc

This file was deleted.

1 change: 0 additions & 1 deletion spec/index.spec.js

This file was deleted.

14 changes: 2 additions & 12 deletions src/ui/components/UIRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import DrawLayerType from '../DrawLayerType';
import Screen from '../../gfx/Screen';
import ScreenLayer from '../../gfx/ScreenLayer';
import { EdgeRect } from '../../math';
import { EnumRecord, LinkedList, NDCtoDDCWidth, NDCtoDDCHeight } from '../../utils';
import { EnumRecord, LinkedList, NDCtoDDCWidth, NDCtoDDCHeight, enumRecordFor } from '../../utils';

import Frame, { FrameFlag } from './simple/Frame';
import FramePointType from './abstract/FramePointType';
Expand Down Expand Up @@ -31,17 +31,7 @@ class UIRoot extends LayoutFrame {
anchor: FramePointType.TOPLEFT,
};

this.strata = [
new FrameStrata(FrameStrataType.WORLD),
new FrameStrata(FrameStrataType.BACKGROUND),
new FrameStrata(FrameStrataType.LOW),
new FrameStrata(FrameStrataType.MEDIUM),
new FrameStrata(FrameStrataType.HIGH),
new FrameStrata(FrameStrataType.DIALOG),
new FrameStrata(FrameStrataType.FULLSCREEN),
new FrameStrata(FrameStrataType.FULLSCREEN_DIALOG),
new FrameStrata(FrameStrataType.TOOLTIP),
];
this.strata = enumRecordFor(FrameStrataType, (type) => new FrameStrata(type));

this.frames = LinkedList.using('framesLink');
this.destroyedFrames = LinkedList.using('destroyedLink');
Expand Down
10 changes: 2 additions & 8 deletions src/ui/components/abstract/FrameStrataLevel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import DrawLayerType from '../../DrawLayerType';
import Frame from '../simple/Frame';
import RenderBatch from '../../rendering/RenderBatch';
import { EnumRecord, LinkedList } from '../../../utils';
import { EnumRecord, LinkedList, enumRecordFor } from '../../../utils';

class FrameStrataLevel {
index: number;
Expand All @@ -19,13 +19,7 @@ class FrameStrataLevel {
this.pendingFrames = LinkedList.using('strataLink');
this.frames = LinkedList.using('strataLink');

this.batches = [
new RenderBatch(DrawLayerType.BACKGROUND),
new RenderBatch(DrawLayerType.BORDER),
new RenderBatch(DrawLayerType.ARTWORK),
new RenderBatch(DrawLayerType.OVERLAY),
new RenderBatch(DrawLayerType.HIGHLIGHT),
];
this.batches = enumRecordFor(DrawLayerType, (type) => new RenderBatch(type));

this.batchDirty = 0;

Expand Down
9 changes: 2 additions & 7 deletions src/ui/components/simple/Frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
LinkedListLink,
LinkedListNode,
Status,
enumRecordFor,
stringToBoolean,
} from '../../../utils';
import { EPSILON1, Rect, areClose } from '../../../math';
Expand Down Expand Up @@ -80,13 +81,7 @@ class Frame extends ScriptRegion {
this.level = 0;
this.frameScale = 1.0;

this.layersEnabled = [
true,
true,
true,
true,
false,
];
this.layersEnabled = enumRecordFor(DrawLayerType, (type) => type !== DrawLayerType.HIGHLIGHT);
this.backdrop = null;

this.regions = LinkedList.using('regionLink');
Expand Down
5 changes: 4 additions & 1 deletion src/ui/components/simple/Texture.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Client from '../../../Client';
import Device from '../../../gfx/Device';
import DrawLayerType from '../../DrawLayerType';
import FramePointType from '../../components/abstract/FramePointType';
import GfxTexture from '../../../gfx/Texture';
import Region from './Region';
import RenderBatch from '../../rendering/RenderBatch';
Expand All @@ -15,6 +16,7 @@ import {
NDCtoDDCHeight,
NDCtoDDCWidth,
Status,
enumSizeFor,
maxAspectCompensation,
stringToBoolean,
stringToFloat,
Expand Down Expand Up @@ -255,12 +257,13 @@ class Texture extends Region {
postLoadXML(_node: XMLNode) {
if (this._parent) {
let i = 0;
const length = enumSizeFor(FramePointType);
for (const point of this.points) {
if (point && !(point.flags & 0x8)) {
break;
}

if (i + 1 === this.points.length) {
if (i + 1 === length) {
this.setAllPoints(this._parent, true);
break;
}
Expand Down
53 changes: 53 additions & 0 deletions src/utils/types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { enumRecordFor, enumSizeFor, enumValuesFor } from './types';

enum Currency {
USD = 'US Dollar',
EUR = 'Euro'
}

enum Ranking {
FIRST = 1,
SECOND = 2,
THIRD = 3
}

describe('enumValuesFor', () => {
it('returns an array of string enum values', () => {
expect(enumValuesFor(Currency)).toEqual([Currency.USD, Currency.EUR]);
});

it('returns an array of number enum values', () => {
expect(enumValuesFor(Ranking)).toEqual([Ranking.FIRST, Ranking.SECOND, Ranking.THIRD]);
});
});

describe('enumRecordFor', () => {
it('constructs an iterable string enum record', () => {
const record = enumRecordFor(Currency, (value) => value.length);
expect(record).toEqual({
[Currency.USD]: 9,
[Currency.EUR]: 4,
});
expect(Array.from(record)).toEqual([9, 4]);
});

it('constructs an iterable number enum record', () => {
const record = enumRecordFor(Ranking, (value) => value * 3);
expect(record).toEqual({
[Ranking.FIRST]: 3,
[Ranking.SECOND]: 6,
[Ranking.THIRD]: 9,
});
expect(Array.from(record)).toEqual([3, 6, 9]);
});
});

describe('enumSizeFor', () => {
it('returns size for string enum', () => {
expect(enumSizeFor(Currency)).toEqual(2);
});

it('returns size for number enum', () => {
expect(enumSizeFor(Ranking)).toEqual(3);
});
});
27 changes: 26 additions & 1 deletion src/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
export type EnumRecord<E extends string | number | symbol, V> = Record<E, V> & Iterable<V> & { length: number };
export type EnumRecord<E extends string | number, V> = Record<E, V> & Iterable<V>;

// Loosely adapted from: https://github.com/microsoft/TypeScript/issues/4753#issuecomment-694557208
type EnumType<T> = { [name: string]: T }

export function enumValuesFor<T extends string>(enumeration: EnumType<T>): T[];
export function enumValuesFor<T extends string | number>(enumeration: EnumType<T>): Exclude<T, string>[];
export function enumValuesFor<T>(enumeration: EnumType<T>): T[] {
const isStringEnum = Object.values(enumeration).every((value) => typeof value === 'string');
return Object.values(enumeration).filter((value) => isStringEnum || typeof value === 'number');
}

export function enumRecordFor<T extends string, V extends (value: T) => unknown>(enumeration: EnumType<T>, mapFv: V): EnumRecord<T, ReturnType<V>>;
export function enumRecordFor<T extends string | number, V extends (value: Exclude<T, string>) => unknown>(enumeration: EnumType<T>, mapFn: V): EnumRecord<Exclude<T, string>, ReturnType<V>>;
export function enumRecordFor<T extends string | number, V extends (value: T) => unknown>(enumeration: EnumType<T>, mapFn: V): EnumRecord<T, ReturnType<V>> {
const values = enumValuesFor(enumeration);
const record = Object.assign({}, ...values.map((value) => ({ [value]: mapFn(value) })));
Object.defineProperty(record, Symbol.iterator, {
value: () => Object.values(record).values()
});
return record;
}

export function enumSizeFor<T extends string | number>(enumeration: EnumType<T>): number {
return enumValuesFor(enumeration).length;
}

// See: https://github.com/microsoft/TypeScript/issues/5863#issuecomment-1336204919
export type ThisConstructor<
Expand Down

0 comments on commit baf3387

Please sign in to comment.