Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: introduce EnumRecord utility methods #60

Merged
merged 1 commit into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading