Skip to content

Commit eb7e6cf

Browse files
committed
feat: unflatten module tree
1 parent 2301917 commit eb7e6cf

File tree

2 files changed

+61
-42
lines changed

2 files changed

+61
-42
lines changed

mixins.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ function interceptNavigationControlMessage(e: Event): boolean {
4444
} else {
4545
(async function () {
4646
for (const identifier of modules) {
47-
const instance = RootModule.INSTANCE.getChild(identifier)?.getEnabledInstance();
47+
const instance = RootModule.INSTANCE.getDescendant(identifier)?.getEnabledInstance();
4848
if (!instance) {
4949
continue;
5050
}

module.ts

+60-41
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export interface Metadata {
4646
}
4747

4848
export abstract class ModuleBase<
49-
C extends ModuleBase<any>,
49+
C extends ModuleBase<C, any>,
5050
I extends ModuleInstanceBase<ModuleBase<C, I>> = ModuleInstanceBase<ModuleBase<C, any>>,
5151
> {
5252
public instances = new Map<Version, I>();
@@ -63,14 +63,32 @@ export abstract class ModuleBase<
6363
return this.identifier;
6464
}
6565

66-
public abstract newChild(identifier: ModuleIdentifier, module: _Module): Promise<C>;
66+
public abstract newDescendant(identifier: ModuleIdentifier, module: _Module): Promise<C>;
6767

68-
public getChild(identifier: ModuleIdentifier): C | undefined {
69-
return this.children[identifier];
68+
public getDescendant(identifier: ModuleIdentifier): C | null {
69+
for (const child of this.getChildren()) {
70+
if (identifier.startsWith(child.identifier)) {
71+
if (identifier.length === child.identifier.length) {
72+
return child;
73+
}
74+
return child.getDescendant(identifier);
75+
}
76+
}
77+
return null;
78+
}
79+
80+
public getLastParentOf(identifier: ModuleIdentifier): C | null {
81+
for (const child of this.getChildren()) {
82+
if (identifier.startsWith(child.identifier)) {
83+
return child.getLastParentOf(identifier);
84+
}
85+
}
86+
// @ts-ignore :(
87+
return this;
7088
}
7189

72-
public async getChildOrNew(identifier: ModuleIdentifier): Promise<C> {
73-
return this.getChild(identifier) ?? this.newChild(identifier, { enabled: "", v: {} });
90+
public async getDescendantOrNew(identifier: ModuleIdentifier): Promise<C> {
91+
return this.getDescendant(identifier) ?? this.newDescendant(identifier, { enabled: "", v: {} });
7492
}
7593

7694
private setChild(identifier: ModuleIdentifier, child: C) {
@@ -85,16 +103,14 @@ export abstract class ModuleBase<
85103
return Object.values(this.children);
86104
}
87105

88-
public getDescendants(identifier: ModuleIdentifier): Array<ModuleBase<any, ModuleInstanceBase<any>>> {
89-
if (identifier === this.identifier) {
90-
return [this];
106+
public *getDescendantsByDepth(): Generator<ModuleBase<any, ModuleInstanceBase<any>>> {
107+
for (const child of this.getChildren()) {
108+
yield child;
109+
yield* child.getDescendantsByDepth();
91110
}
92-
return this.getChildren().filter((child) => child.identifier.startsWith(identifier)).flatMap((child) =>
93-
child.getDescendants(identifier)
94-
);
95111
}
96112

97-
public *getAllDescendantsByBreadth(): Generator<ModuleBase<ModuleBase<any>>> {
113+
public *getDescendantsByBreadth(): Generator<ModuleBase<ModuleBase<any>>> {
98114
const i: Array<ModuleBase<ModuleBase<any>>> = [this];
99115

100116
while (i.length) {
@@ -138,8 +154,8 @@ export class RootModule extends ModuleBase<Module, never> {
138154
Object.freeze(this.instances);
139155
}
140156

141-
override newChild(identifier: ModuleIdentifier, module: _Module, local = false) {
142-
return Module.prototype.newChild.call(this, identifier, module, local);
157+
override newDescendant(identifier: ModuleIdentifier, module: _Module, local = false) {
158+
return Module.prototype.newDescendant.call(this, identifier, module, local);
143159
}
144160
}
145161

@@ -153,11 +169,20 @@ export class Module extends ModuleBase<Module, ModuleInstance> {
153169
super(parent, children, identifier);
154170
}
155171

156-
override newChild(identifier: ModuleIdentifier, module: _Module, local = false) {
157-
if (this.getChild(identifier)) {
172+
override newDescendant(identifier: ModuleIdentifier, module: _Module, local = false) {
173+
if (this.getDescendant(identifier)) {
158174
throw new Error(`Module ${identifier} already exists`);
159175
}
160-
return new Module(this, {}, identifier, local ? module.enabled : "").init(module.v, local);
176+
177+
const parent = this.getLastParentOf(identifier) as Module;
178+
const descendant = new Module(parent, {}, identifier, local ? module.enabled : "");
179+
for (const child of parent.getChildren()) {
180+
if (child.getIdentifier().startsWith(identifier) && child != descendant) {
181+
child.parent = descendant;
182+
}
183+
}
184+
185+
return descendant.init(module.v, local);;
161186
}
162187

163188
override async newInstance(
@@ -230,7 +255,7 @@ export interface MixinLoader {
230255
awaitedMixins: Promise<void>[];
231256
}
232257

233-
export abstract class ModuleInstanceBase<M extends ModuleBase<any> = ModuleBase<any>> {
258+
export abstract class ModuleInstanceBase<M extends ModuleBase<M> = ModuleBase<any>> {
234259
public getName() {
235260
return this.metadata?.name;
236261
}
@@ -288,7 +313,10 @@ export class ModuleInstance extends ModuleInstanceBase<Module> implements MixinL
288313
Object.keys(provider)
289314
// TODO: revisit this check
290315
.filter((i) => i.startsWith(this.getModuleIdentifier()))
291-
.forEach(async (identifier) => this.module.newChild(identifier, provider[identifier]));
316+
.forEach(async (identifier) => {
317+
const module = await this.module.getDescendantOrNew(identifier);
318+
await module.init(provider[identifier].v, false);
319+
});
292320
}
293321

294322
private _transformer = createTransformer(this);
@@ -473,7 +501,7 @@ export class ModuleInstance extends ModuleInstanceBase<Module> implements MixinL
473501
if (dependency === "spotify") {
474502
return satisfies(SPOTIFY_VERSION, range);
475503
}
476-
const module = RootModule.INSTANCE.getChild(dependency)?.getEnabledInstance();
504+
const module = RootModule.INSTANCE.getDescendant(dependency)?.getEnabledInstance();
477505
if (!module?.canLoadRecur(isPreload, range)) {
478506
return false;
479507
}
@@ -502,7 +530,7 @@ export class ModuleInstance extends ModuleInstanceBase<Module> implements MixinL
502530

503531
await Promise.all(
504532
Object.keys(this.metadata!.dependencies).map((dependency) => {
505-
const module = RootModule.INSTANCE.getChild(dependency)!.getEnabledInstance()!;
533+
const module = RootModule.INSTANCE.getDescendant(dependency)!.getEnabledInstance()!;
506534
return module.loadMixinsRecur();
507535
}),
508536
);
@@ -521,7 +549,7 @@ export class ModuleInstance extends ModuleInstanceBase<Module> implements MixinL
521549

522550
await Promise.all(
523551
Object.keys(this.metadata!.dependencies).map((dependency) => {
524-
const module = RootModule.INSTANCE.getChild(dependency)!.getEnabledInstance()!;
552+
const module = RootModule.INSTANCE.getDescendant(dependency)!.getEnabledInstance()!;
525553
module.dependants.add(this);
526554
return module.loadRecur();
527555
}),
@@ -542,7 +570,7 @@ export class ModuleInstance extends ModuleInstanceBase<Module> implements MixinL
542570
const resolve = this.transition.extend();
543571

544572
for (const dependency of Object.keys(this.metadata!.dependencies)) {
545-
const module = RootModule.INSTANCE.getChild(dependency)!.getEnabledInstance()!;
573+
const module = RootModule.INSTANCE.getDescendant(dependency)!.getEnabledInstance()!;
546574
module.dependants.delete(this);
547575
}
548576
await Promise.all(Array.from(this.dependants).map((dependant) => dependant.unloadRecur()));
@@ -586,21 +614,10 @@ export class ModuleInstance extends ModuleInstanceBase<Module> implements MixinL
586614
return null;
587615
}
588616

589-
const module = await RootModule.INSTANCE.getChildOrNew(this.getModuleIdentifier());
590-
const instance = new ModuleInstance(
591-
module,
592-
this.getVersion(),
593-
this.metadata,
594-
this.artifacts,
595-
this.checksum,
596-
true,
597-
false,
598-
);
599-
module.instances.set(instance.getVersion(), instance);
600617
this.added = true;
601618
resolve();
602619

603-
return instance;
620+
return this;
604621
}
605622

606623
public canInstallRemove() {
@@ -741,7 +758,7 @@ export async function loadLocalModules() {
741758

742759
return Promise.all(
743760
Object.keys(localModules).map((identifier) =>
744-
RootModule.INSTANCE.newChild(identifier, localModules[identifier], true)
761+
RootModule.INSTANCE.newDescendant(identifier, localModules[identifier], true)
745762
),
746763
);
747764
}
@@ -754,16 +771,18 @@ export async function loadRemoteModules() {
754771

755772
await Promise.all(
756773
Object.keys(remoteModules).map(async (identifier) => {
757-
const module = await RootModule.INSTANCE.getChildOrNew(identifier);
774+
const module = await RootModule.INSTANCE.getDescendantOrNew(identifier);
758775
await module.init(remoteModules[identifier].v, false);
759776
}),
760777
);
761778
}
762779

763780
const getLoadableChildrenInstances = () =>
764-
RootModule.INSTANCE.getChildren().map((module) => module.getEnabledInstance()).filter(
765-
(instance) => instance?.canLoad(),
766-
) as ModuleInstance[];
781+
Array.from(RootModule.INSTANCE.getDescendantsByBreadth())
782+
.map((module) => (module as Module).getEnabledInstance())
783+
.filter(
784+
(instance) => instance?.canLoad(),
785+
) as ModuleInstance[];
767786

768787
export const enableAllLoadableMixins = () =>
769788
Promise.all(getLoadableChildrenInstances().map((instance) => instance._loadMixins()));

0 commit comments

Comments
 (0)