core: add documentation comments to plugin configuration merge logic

Adds explanatory comments to config.ts and plugin.ts clarifying:

- How plugin specs are stored and normalized during config loading

- Why plugin_origins tracks provenance for location-sensitive decisions

- Why path-like specs are resolved early to prevent reinterpretation during merges

- How plugin deduplication works while keeping origin metadata for writes and diagnostics
This commit is contained in:
Dax Raad
2026-04-16 12:55:40 -04:00
parent 9bf2dfea35
commit 8b1f0e2d90
2 changed files with 28 additions and 6 deletions
+10 -1
View File
@@ -8,11 +8,16 @@ export namespace ConfigPlugin {
const Options = z.record(z.string(), z.unknown())
export type Options = z.infer<typeof Options>
// Spec is the user-config value: either just a plugin identifier, or the identifier plus inline options.
// It answers "what should we load?" but says nothing about where that value came from.
export const Spec = z.union([z.string(), z.tuple([z.string(), Options])])
export type Spec = z.infer<typeof Spec>
export type Scope = "global" | "local"
// Origin keeps the original config provenance attached to a spec.
// After multiple config files are merged, callers still need to know which file declared the plugin
// and whether it should behave like a global or project-local plugin.
export type Origin = {
spec: Spec
source: string
@@ -33,7 +38,7 @@ export namespace ConfigPlugin {
return plugins
}
export function pluginSpecifier(plugin: ConfigPlugin.Spec): string {
export function pluginSpecifier(plugin: Spec): string {
return Array.isArray(plugin) ? plugin[0] : plugin
}
@@ -41,6 +46,8 @@ export namespace ConfigPlugin {
return Array.isArray(plugin) ? plugin[1] : undefined
}
// Path-like specs are resolved relative to the config file that declared them so merges later on do not
// accidentally reinterpret `./plugin.ts` relative to some other directory.
export async function resolvePluginSpec(plugin: Spec, configFilepath: string): Promise<Spec> {
const spec = pluginSpecifier(plugin)
if (!isPathPluginSpec(spec)) return plugin
@@ -58,6 +65,8 @@ export namespace ConfigPlugin {
return resolved
}
// Dedupe on the load identity (package name for npm specs, exact file URL for local specs), but keep the
// full Origin so downstream code still knows which config file won and where follow-up writes should go.
export function deduplicatePluginOrigins(plugins: Origin[]): Origin[] {
const seen = new Set<string>()
const list: Origin[] = []