Compare commits

...

1 Commits

Author SHA1 Message Date
Kit Langton 75cbba355e refactor: unwrap PluginLoader namespace + self-reexport 2026-04-16 19:53:44 -04:00
+27 -27
View File
@@ -11,30 +11,29 @@ import {
import { ConfigPlugin } from "@/config/plugin" import { ConfigPlugin } from "@/config/plugin"
import { InstallationVersion } from "@/installation/version" import { InstallationVersion } from "@/installation/version"
export namespace PluginLoader { export type Plan = {
export type Plan = {
spec: string spec: string
options: ConfigPlugin.Options | undefined options: ConfigPlugin.Options | undefined
deprecated: boolean deprecated: boolean
} }
export type Resolved = Plan & { export type Resolved = Plan & {
source: PluginSource source: PluginSource
target: string target: string
entry: string entry: string
pkg?: PluginPackage pkg?: PluginPackage
} }
export type Missing = Plan & { export type Missing = Plan & {
source: PluginSource source: PluginSource
target: string target: string
pkg?: PluginPackage pkg?: PluginPackage
message: string message: string
} }
export type Loaded = Resolved & { export type Loaded = Resolved & {
mod: Record<string, unknown> mod: Record<string, unknown>
} }
type Candidate = { origin: ConfigPlugin.Origin; plan: Plan } type Candidate = { origin: ConfigPlugin.Origin; plan: Plan }
type Report = { type Report = {
start?: (candidate: Candidate, retry: boolean) => void start?: (candidate: Candidate, retry: boolean) => void
missing?: (candidate: Candidate, retry: boolean, message: string, resolved: Missing) => void missing?: (candidate: Candidate, retry: boolean, message: string, resolved: Missing) => void
error?: ( error?: (
@@ -44,21 +43,21 @@ export namespace PluginLoader {
error: unknown, error: unknown,
resolved?: Resolved, resolved?: Resolved,
) => void ) => void
} }
function plan(item: ConfigPlugin.Spec): Plan { function plan(item: ConfigPlugin.Spec): Plan {
const spec = ConfigPlugin.pluginSpecifier(item) const spec = ConfigPlugin.pluginSpecifier(item)
return { spec, options: ConfigPlugin.pluginOptions(item), deprecated: isDeprecatedPlugin(spec) } return { spec, options: ConfigPlugin.pluginOptions(item), deprecated: isDeprecatedPlugin(spec) }
} }
export async function resolve( export async function resolve(
plan: Plan, plan: Plan,
kind: PluginKind, kind: PluginKind,
): Promise< ): Promise<
| { ok: true; value: Resolved } | { ok: true; value: Resolved }
| { ok: false; stage: "missing"; value: Missing } | { ok: false; stage: "missing"; value: Missing }
| { ok: false; stage: "install" | "entry" | "compatibility"; error: unknown } | { ok: false; stage: "install" | "entry" | "compatibility"; error: unknown }
> { > {
let target = "" let target = ""
try { try {
target = await resolvePluginTarget(plan.spec) target = await resolvePluginTarget(plan.spec)
@@ -94,9 +93,9 @@ export namespace PluginLoader {
} }
} }
return { ok: true, value: { ...plan, source: base.source, target: base.target, entry: base.entry, pkg: base.pkg } } return { ok: true, value: { ...plan, source: base.source, target: base.target, entry: base.entry, pkg: base.pkg } }
} }
export async function load(row: Resolved): Promise<{ ok: true; value: Loaded } | { ok: false; error: unknown }> { export async function load(row: Resolved): Promise<{ ok: true; value: Loaded } | { ok: false; error: unknown }> {
let mod let mod
try { try {
mod = await import(row.entry) mod = await import(row.entry)
@@ -105,16 +104,16 @@ export namespace PluginLoader {
} }
if (!mod) return { ok: false, error: new Error(`Plugin ${row.spec} module is empty`) } if (!mod) return { ok: false, error: new Error(`Plugin ${row.spec} module is empty`) }
return { ok: true, value: { ...row, mod } } return { ok: true, value: { ...row, mod } }
} }
async function attempt<R>( async function attempt<R>(
candidate: Candidate, candidate: Candidate,
kind: PluginKind, kind: PluginKind,
retry: boolean, retry: boolean,
finish: ((load: Loaded, origin: ConfigPlugin.Origin, retry: boolean) => Promise<R | undefined>) | undefined, finish: ((load: Loaded, origin: ConfigPlugin.Origin, retry: boolean) => Promise<R | undefined>) | undefined,
missing: ((value: Missing, origin: ConfigPlugin.Origin, retry: boolean) => Promise<R | undefined>) | undefined, missing: ((value: Missing, origin: ConfigPlugin.Origin, retry: boolean) => Promise<R | undefined>) | undefined,
report: Report | undefined, report: Report | undefined,
): Promise<R | undefined> { ): Promise<R | undefined> {
const plan = candidate.plan const plan = candidate.plan
if (plan.deprecated) return if (plan.deprecated) return
report?.start?.(candidate, retry) report?.start?.(candidate, retry)
@@ -138,18 +137,18 @@ export namespace PluginLoader {
} }
if (!finish) return loaded.value as R if (!finish) return loaded.value as R
return finish(loaded.value, candidate.origin, retry) return finish(loaded.value, candidate.origin, retry)
} }
type Input<R> = { type Input<R> = {
items: ConfigPlugin.Origin[] items: ConfigPlugin.Origin[]
kind: PluginKind kind: PluginKind
wait?: () => Promise<void> wait?: () => Promise<void>
finish?: (load: Loaded, origin: ConfigPlugin.Origin, retry: boolean) => Promise<R | undefined> finish?: (load: Loaded, origin: ConfigPlugin.Origin, retry: boolean) => Promise<R | undefined>
missing?: (value: Missing, origin: ConfigPlugin.Origin, retry: boolean) => Promise<R | undefined> missing?: (value: Missing, origin: ConfigPlugin.Origin, retry: boolean) => Promise<R | undefined>
report?: Report report?: Report
} }
export async function loadExternal<R = Loaded>(input: Input<R>): Promise<R[]> { export async function loadExternal<R = Loaded>(input: Input<R>): Promise<R[]> {
const candidates = input.items.map((origin) => ({ origin, plan: plan(origin.spec) })) const candidates = input.items.map((origin) => ({ origin, plan: plan(origin.spec) }))
const list: Array<Promise<R | undefined>> = [] const list: Array<Promise<R | undefined>> = []
for (const candidate of candidates) { for (const candidate of candidates) {
@@ -170,5 +169,6 @@ export namespace PluginLoader {
const ready: R[] = [] const ready: R[] = []
for (const item of out) if (item !== undefined) ready.push(item) for (const item of out) if (item !== undefined) ready.push(item)
return ready return ready
}
} }
export * as PluginLoader from "./loader"