Skip to content

Commit a4b0e5a

Browse files
committed
refactor(entity): simplify component options retrieval
1 parent 029c9e1 commit a4b0e5a

File tree

2 files changed

+37
-17
lines changed

2 files changed

+37
-17
lines changed

src/entity.test.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -439,19 +439,22 @@ describe("Component Options", () => {
439439
const normalComp = component();
440440

441441
const exclusiveOpts = getComponentOptions(exclusiveComp);
442-
expect(exclusiveOpts?.exclusive).toBe(true);
443-
expect(exclusiveOpts?.cascadeDelete).toBe(undefined);
442+
expect(exclusiveOpts.exclusive).toBe(true);
443+
expect(exclusiveOpts.cascadeDelete).toBe(undefined);
444444

445445
const cascadeOpts = getComponentOptions(cascadeComp);
446-
expect(cascadeOpts?.exclusive).toBe(undefined);
447-
expect(cascadeOpts?.cascadeDelete).toBe(true);
446+
expect(cascadeOpts.exclusive).toBe(undefined);
447+
expect(cascadeOpts.cascadeDelete).toBe(true);
448448

449449
const bothOpts = getComponentOptions(bothComp);
450-
expect(bothOpts?.exclusive).toBe(true);
451-
expect(bothOpts?.cascadeDelete).toBe(true);
450+
expect(bothOpts.exclusive).toBe(true);
451+
expect(bothOpts.cascadeDelete).toBe(true);
452452

453453
const normalOpts = getComponentOptions(normalComp);
454-
expect(normalOpts).toBe(undefined);
454+
expect(normalOpts.name).toBe(undefined);
455+
expect(normalOpts.exclusive).toBe(undefined);
456+
expect(normalOpts.cascadeDelete).toBe(undefined);
457+
expect(normalOpts.dontFragment).toBe(undefined);
455458
});
456459

457460
it("should support name in options object", () => {
@@ -493,10 +496,16 @@ describe("Component Options", () => {
493496
const combinedComp = component({ cascadeDelete: true, dontFragment: true });
494497

495498
const options = getComponentOptions(combinedComp);
496-
expect(options?.cascadeDelete).toBe(true);
497-
expect(options?.dontFragment).toBe(true);
499+
expect(options.cascadeDelete).toBe(true);
500+
expect(options.dontFragment).toBe(true);
498501

499502
expect(isCascadeDeleteComponent(combinedComp)).toBe(true);
500503
expect(isDontFragmentComponent(combinedComp)).toBe(true);
501504
});
505+
506+
it("should throw error for invalid component ID", () => {
507+
expect(() => getComponentOptions(0 as ComponentId)).toThrow("Invalid component ID");
508+
expect(() => getComponentOptions(1025 as ComponentId)).toThrow("Invalid component ID");
509+
expect(() => getComponentOptions(-1 as ComponentId)).toThrow("Invalid component ID");
510+
});
502511
});

src/entity.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,6 @@ export class ComponentIdAllocator {
438438

439439
const globalComponentIdAllocator = new ComponentIdAllocator();
440440

441-
const ComponentNames: Map<ComponentId<any>, string> = new Map();
442441
const ComponentIdForNames: Map<string, ComponentId<any>> = new Map();
443442

444443
/**
@@ -472,7 +471,8 @@ export interface ComponentOptions {
472471
dontFragment?: boolean;
473472
}
474473

475-
const ComponentOptions: Map<ComponentId<any>, ComponentOptions> = new Map();
474+
// Array for component names (Component ID range: 1-1023)
475+
const componentNames: (string | undefined)[] = new Array(COMPONENT_ID_MAX + 1);
476476

477477
// BitSets for fast component option checks (Component ID range: 1-1023)
478478
const exclusiveFlags = new BitSet(COMPONENT_ID_MAX + 1);
@@ -513,13 +513,12 @@ export function component<T = void>(nameOrOptions?: string | ComponentOptions):
513513
throw new Error(`Component name "${name}" is already registered`);
514514
}
515515

516-
ComponentNames.set(id, name);
516+
componentNames[id] = name;
517517
ComponentIdForNames.set(name, id);
518518
}
519519

520520
// Register options if provided
521521
if (options) {
522-
ComponentOptions.set(id, options);
523522
// Set bitset flags for fast lookup
524523
if (options.exclusive) exclusiveFlags.set(id);
525524
if (options.cascadeDelete) cascadeDeleteFlags.set(id);
@@ -543,16 +542,28 @@ export function getComponentIdByName(name: string): ComponentId<any> | undefined
543542
* @returns The component name if found, undefined otherwise
544543
*/
545544
export function getComponentNameById(id: ComponentId<any>): string | undefined {
546-
return ComponentNames.get(id);
545+
return componentNames[id];
547546
}
548547

549548
/**
550549
* Get component options by its ID
551550
* @param id The component ID
552-
* @returns The component options if found, undefined otherwise
551+
* @returns The component options
553552
*/
554-
export function getComponentOptions(id: ComponentId<any>): ComponentOptions | undefined {
555-
return ComponentOptions.get(id);
553+
export function getComponentOptions(id: ComponentId<any>): ComponentOptions {
554+
if (!isComponentId(id)) {
555+
throw new Error("Invalid component ID");
556+
}
557+
const hasName = componentNames[id] !== undefined;
558+
const hasExclusive = exclusiveFlags.has(id);
559+
const hasCascadeDelete = cascadeDeleteFlags.has(id);
560+
const hasDontFragment = dontFragmentFlags.has(id);
561+
return {
562+
name: hasName ? componentNames[id] : undefined,
563+
exclusive: hasExclusive ? true : undefined,
564+
cascadeDelete: hasCascadeDelete ? true : undefined,
565+
dontFragment: hasDontFragment ? true : undefined,
566+
};
556567
}
557568

558569
/**

0 commit comments

Comments
 (0)