Formatting

This commit is contained in:
2025-10-25 17:20:23 -04:00
parent 17e7f8babd
commit b209d710b8
8 changed files with 83 additions and 85 deletions

12
.prettierrc Normal file
View File

@@ -0,0 +1,12 @@
{
"arrowParens": "avoid",
"bracketSameLine": true,
"bracketSpacing": false,
"printWidth": 180,
"semi": true,
"singleAttributePerLine": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
}

View File

@@ -1,35 +1,35 @@
import js from "@eslint/js"; import js from '@eslint/js';
import globals from "globals"; import globals from 'globals';
import tseslint from "typescript-eslint"; import tseslint from 'typescript-eslint';
import json from "@eslint/json"; import json from '@eslint/json';
import markdown from "@eslint/markdown"; import markdown from '@eslint/markdown';
import css from "@eslint/css"; import css from '@eslint/css';
import { defineConfig } from "eslint/config"; import {defineConfig} from 'eslint/config';
export default defineConfig([ export default defineConfig([
{ {
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"], files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],
plugins: {js}, plugins: {js},
extends: ["js/recommended"], extends: ['js/recommended'],
languageOptions: { globals: globals.node }, languageOptions: {globals: globals.node}
}, },
tseslint.configs.recommended, tseslint.configs.recommended,
{ {
files: ["**/*.json"], files: ['**/*.json'],
plugins: {json}, plugins: {json},
language: "json/json", language: 'json/json',
extends: ["json/recommended"], extends: ['json/recommended']
}, },
{ {
files: ["**/*.md"], files: ['**/*.md'],
plugins: {markdown}, plugins: {markdown},
language: "markdown/commonmark", language: 'markdown/commonmark',
extends: ["markdown/recommended"], extends: ['markdown/recommended']
}, },
{ {
files: ["**/*.css"], files: ['**/*.css'],
plugins: {css}, plugins: {css},
language: "css/css", language: 'css/css',
extends: ["css/recommended"], extends: ['css/recommended']
}, }
]); ]);

View File

@@ -1,8 +1,8 @@
import type IDependencyProvider from "./IDependencyProvider"; import type IDependencyProvider from './IDependencyProvider';
import type IDisposable from "../lang/IDisposable"; import type IDisposable from '../lang/IDisposable';
import Disposable from "../lang/Disposable"; import Disposable from '../lang/Disposable';
import Type from "./Type"; import Type from './Type';
import type IDependencyManager from "./IDependencyManager"; import type IDependencyManager from './IDependencyManager';
type Constructor<T = unknown> = new (...args: unknown[]) => T; type Constructor<T = unknown> = new (...args: unknown[]) => T;
type ModuleLoader = (modulePath: string) => Promise<Constructor | {default: Constructor}>; type ModuleLoader = (modulePath: string) => Promise<Constructor | {default: Constructor}>;
@@ -16,8 +16,8 @@ export default class DependencyManager implements IDependencyManager {
private readonly _pending: Type[]; private readonly _pending: Type[];
constructor(moduleLoader: ModuleLoader) { constructor(moduleLoader: ModuleLoader) {
if (typeof moduleLoader !== "function") { if (typeof moduleLoader !== 'function') {
throw new Error("Module loader must be a function"); throw new Error('Module loader must be a function');
} }
this._moduleLoader = moduleLoader; this._moduleLoader = moduleLoader;
@@ -30,25 +30,23 @@ export default class DependencyManager implements IDependencyManager {
public defineDependencies(type: Type, dependencies: Type[]): IDisposable { public defineDependencies(type: Type, dependencies: Type[]): IDisposable {
if (!(type instanceof Type)) { if (!(type instanceof Type)) {
throw new Error("Type must be a Type"); throw new Error('Type must be a Type');
} }
if (!Array.isArray(dependencies)) { if (!Array.isArray(dependencies)) {
throw new Error("Dependencies must be an array"); throw new Error('Dependencies must be an array');
} }
for (const dependency of dependencies) { for (const dependency of dependencies) {
if (!(dependency instanceof Type)) { if (!(dependency instanceof Type)) {
throw new Error("Dependency must be a Type"); throw new Error('Dependency must be a Type');
} }
} }
const key = type.toURN(); const key = type.toURN();
if (this._injections.has(key)) { if (this._injections.has(key)) {
throw new Error( throw new Error(`Dependencies already defined for type [${type.toString()}]`);
`Dependencies already defined for type [${type.toString()}]`,
);
} }
this._injections.set(key, dependencies); this._injections.set(key, dependencies);
@@ -61,7 +59,7 @@ export default class DependencyManager implements IDependencyManager {
public getDependencies(type: Type): Type[] | undefined { public getDependencies(type: Type): Type[] | undefined {
if (!(type instanceof Type)) { if (!(type instanceof Type)) {
throw new Error("Type must be an instance of Type"); throw new Error('Type must be an instance of Type');
} }
return this._injections.get(type.toURN()); return this._injections.get(type.toURN());
@@ -69,7 +67,7 @@ export default class DependencyManager implements IDependencyManager {
public addProvider(provider: IDependencyProvider): IDisposable { public addProvider(provider: IDependencyProvider): IDisposable {
if (!this.isProvider(provider)) { if (!this.isProvider(provider)) {
throw new Error("Provider must implement IDependencyProvider"); throw new Error('Provider must implement IDependencyProvider');
} }
this._providers.push(provider); this._providers.push(provider);
@@ -83,7 +81,22 @@ export default class DependencyManager implements IDependencyManager {
} }
public async resolveProvider(type: Type): Promise<IDependencyProvider> { public async resolveProvider(type: Type): Promise<IDependencyProvider> {
return this.resolve(type); if (!(type instanceof Type)) {
throw new Error('Type must be an instance of Type');
}
const candidates = this._providers.filter(provider => provider.canProvide(type));
if (candidates.length === 0) {
throw new Error(`No provider for [${type.toString()}]`);
}
if (candidates.length > 1) {
const candidateNames = candidates.map(c => c.toString()).join(', ');
throw new Error(`Multiple providers for ${type}: ${candidateNames}`);
}
return candidates[0] as IDependencyProvider;
} }
public async instantiateType(type: Type): Promise<unknown> { public async instantiateType(type: Type): Promise<unknown> {
@@ -95,10 +108,8 @@ export default class DependencyManager implements IDependencyManager {
// Check for circular dependencies // Check for circular dependencies
if (this._pending.includes(type)) { if (this._pending.includes(type)) {
const pendingChain = this._pending.map((t) => t.toString()).join(' -> '); const pendingChain = this._pending.map(t => t.toString()).join(' -> ');
throw new Error( throw new Error(`Failed to resolve ${type} due to circular dependency: ${pendingChain}`);
`Failed to resolve ${type} due to circular dependency: ${pendingChain}`
);
} }
this._pending.push(type); this._pending.push(type);
@@ -109,7 +120,7 @@ export default class DependencyManager implements IDependencyManager {
// Resolve all dependencies // Resolve all dependencies
const resolvedDependencies = await Promise.all( const resolvedDependencies = await Promise.all(
dependencies.map(async (dependency) => { dependencies.map(async dependency => {
const provider = await this.resolveProvider(dependency); const provider = await this.resolveProvider(dependency);
let instance = await provider.provide(dependency); let instance = await provider.provide(dependency);
@@ -150,7 +161,7 @@ export default class DependencyManager implements IDependencyManager {
public addEagerType(type: Type): void { public addEagerType(type: Type): void {
if (!(type instanceof Type)) { if (!(type instanceof Type)) {
throw new Error("Type must be an instance of Type"); throw new Error('Type must be an instance of Type');
} }
this._eagerTypes.push(type); this._eagerTypes.push(type);
@@ -167,35 +178,14 @@ export default class DependencyManager implements IDependencyManager {
private isProvider(obj: unknown): obj is IDependencyProvider { private isProvider(obj: unknown): obj is IDependencyProvider {
return ( return (
obj !== null && obj !== null &&
typeof obj === "object" && typeof obj === 'object' &&
"canProvide" in obj && 'canProvide' in obj &&
"provide" in obj && 'provide' in obj &&
typeof (obj as IDependencyProvider).canProvide === "function" && typeof (obj as IDependencyProvider).canProvide === 'function' &&
typeof (obj as IDependencyProvider).provide === "function" typeof (obj as IDependencyProvider).provide === 'function'
); );
} }
private resolve(type: Type): IDependencyProvider {
if (!(type instanceof Type)) {
throw new Error("Type must be an instance of Type");
}
const candidates = this._providers.filter((provider) =>
provider.canProvide(type),
);
if (candidates.length === 0) {
throw new Error(`No provider for [${type.toString()}]`);
}
if (candidates.length > 1) {
const candidateNames = candidates.map((c) => c.toString()).join(", ");
throw new Error(`Multiple providers for ${type}: ${candidateNames}`);
}
return candidates[0] as IDependencyProvider;
}
private injectDependencies(Constructor: Constructor, dependencies: unknown[]): unknown { private injectDependencies(Constructor: Constructor, dependencies: unknown[]): unknown {
if (dependencies.length === 0) { if (dependencies.length === 0) {
return new Constructor(); return new Constructor();

View File

@@ -1,6 +1,6 @@
import type Type from "./Type"; import type Type from './Type';
import type IDisposable from "../lang/IDisposable"; import type IDisposable from '../lang/IDisposable';
import type IDependencyProvider from "./IDependencyProvider"; import type IDependencyProvider from './IDependencyProvider';
export default interface IDependencyManager { export default interface IDependencyManager {
defineDependencies(type: Type, dependencies: Type[]): IDisposable; defineDependencies(type: Type, dependencies: Type[]): IDisposable;

View File

@@ -1,4 +1,4 @@
import Type from "./Type"; import Type from './Type';
export default interface IDependencyProvider { export default interface IDependencyProvider {
canProvide(type: Type): boolean; canProvide(type: Type): boolean;

View File

@@ -1,4 +1,4 @@
import Type from "./Type"; import Type from './Type';
export default class NamedType extends Type { export default class NamedType extends Type {
private readonly _name: string; private readonly _name: string;
@@ -13,11 +13,7 @@ export default class NamedType extends Type {
} }
public override equals(other: Type) { public override equals(other: Type) {
return ( return super.equals(other) && other instanceof Type && this.getName() === (other as NamedType).getName();
super.equals(other) &&
other instanceof Type &&
this.getName() === (other as NamedType).getName()
);
} }
public overridetoURN(): string { public overridetoURN(): string {

View File

@@ -1,4 +1,4 @@
import IDisposable from "./IDisposable"; import IDisposable from './IDisposable';
export default class Disposable implements IDisposable { export default class Disposable implements IDisposable {
private readonly _cleanup: () => void; private readonly _cleanup: () => void;

View File

@@ -1,4 +1,4 @@
import IDisposable from "./IDisposable"; import IDisposable from './IDisposable';
export default class DisposableList implements IDisposable { export default class DisposableList implements IDisposable {
private readonly _list: IDisposable[]; private readonly _list: IDisposable[];