fix: improved plugin type resolution

This commit is contained in:
saberzero1
2026-05-21 17:59:26 +02:00
parent 0c63884f65
commit 7fd0590a46
2 changed files with 143 additions and 25 deletions
+45 -13
View File
@@ -914,7 +914,10 @@ export async function regeneratePluginIndex(options: { verbose?: boolean } = {})
})
// Phase 1: Collect all exports per plugin, detect conflicts
const pluginExports = new Map<string, { named: string[]; types: string[] }>()
const pluginExports = new Map<
string,
{ overridable: string[]; passthrough: string[]; types: string[] }
>()
const nameCount = new Map<string, number>()
for (const pluginName of pluginDirs) {
@@ -933,9 +936,12 @@ export async function regeneratePluginIndex(options: { verbose?: boolean } = {})
const named = exportedNames.filter((e) => !e.startsWith("type "))
const types = exportedNames.filter((e) => e.startsWith("type ")).map((e) => e.slice(5))
if (named.length > 0 || types.length > 0) {
pluginExports.set(pluginName, { named, types })
for (const n of named) {
const overridable = named.filter((n) => isOverridableExport(n, dtsContent))
const passthrough = named.filter((n) => !isOverridableExport(n, dtsContent))
if (overridable.length > 0 || passthrough.length > 0 || types.length > 0) {
pluginExports.set(pluginName, { overridable, passthrough, types })
for (const n of [...overridable, ...passthrough]) {
nameCount.set(n, (nameCount.get(n) ?? 0) + 1)
}
}
@@ -953,17 +959,26 @@ export async function regeneratePluginIndex(options: { verbose?: boolean } = {})
lines.push(`export type { ${types.join(", ")} } from "./${pluginName}"`)
}
}
// Direct re-exports for non-overridable values (constants, utility functions, etc.)
for (const [pluginName, { passthrough }] of pluginExports) {
if (passthrough.length === 0) continue
const unique = passthrough.filter((n) => (nameCount.get(n) ?? 0) === 1)
if (unique.length > 0) {
lines.push(`export { ${unique.join(", ")} } from "./${pluginName}"`)
}
}
lines.push("")
// Generate the plugins map with override wrappers
// Generate the plugins map with override wrappers (overridable exports only)
lines.push(
`export const plugins: Record<string, Record<string, (...args: unknown[]) => void>> = {`,
)
for (const [pluginName, { named }] of pluginExports) {
if (named.length === 0) continue
for (const [pluginName, { overridable }] of pluginExports) {
if (overridable.length === 0) continue
const escapedName = pluginName.replace(/"/g, '\\"')
lines.push(` "${escapedName}": {`)
for (const n of named) {
for (const n of overridable) {
lines.push(
` ${n}: (...args: unknown[]) => { componentRegistry.setOptionOverrides("${escapedName}", args[0] as Record<string, unknown>); },`,
)
@@ -973,12 +988,12 @@ export async function regeneratePluginIndex(options: { verbose?: boolean } = {})
lines.push(`}`)
lines.push("")
// Top-level exports: only for non-conflicting names
for (const [pluginName, { named }] of pluginExports) {
if (named.length === 0) continue
// Top-level exports for overridable names: alias to the plugins map wrapper
for (const [pluginName, { overridable }] of pluginExports) {
if (overridable.length === 0) continue
const unique = named.filter((n) => (nameCount.get(n) ?? 0) === 1)
const conflicting = named.filter((n) => (nameCount.get(n) ?? 0) > 1)
const unique = overridable.filter((n) => (nameCount.get(n) ?? 0) === 1)
const conflicting = overridable.filter((n) => (nameCount.get(n) ?? 0) > 1)
if (unique.length > 0) {
const escapedName = pluginName.replace(/"/g, '\\"')
@@ -1014,6 +1029,23 @@ export async function regeneratePluginIndex(options: { verbose?: boolean } = {})
const INTERNAL_EXPORTS = new Set(["manifest", "default"])
const PLUGIN_TYPE_PATTERN =
/Quartz(?:Emitter|Transformer|Filter|PageType)Plugin|QuartzComponentConstructor|\(.*\)\s*=>\s*QuartzComponent\b/
function resolveOriginalName(exportName: string, dtsContent: string): string {
const aliasPattern = new RegExp(`(\\w+)\\s+as\\s+${exportName}\\b`)
const match = dtsContent.match(aliasPattern)
return match ? match[1] : exportName
}
function isOverridableExport(name: string, dtsContent: string): boolean {
const declName = resolveOriginalName(name, dtsContent)
const declPattern = new RegExp(`declare\\s+const\\s+${declName}\\s*:\\s*(.+?)(?:;|$)`, "m")
const match = dtsContent.match(declPattern)
if (!match) return false
return PLUGIN_TYPE_PATTERN.test(match[1])
}
function parseExportsFromDts(content: string): string[] {
const exports: string[] = []