feat: migrate default config and templates to npm specifiers
- quartz.config.default.yaml: all 44 plugins use @quartz-community/* npm specifiers - cli/templates/*.yaml: all 4 templates updated (default, blog, obsidian, ttrpg) - bootstrap-cli.mjs: updated help text - package.json: devDeps use npm semver ranges instead of github: specifiers - gitLoader.ts: regeneratePluginIndex scans npm packages from node_modules - install-plugins.ts: generates plugin index for npm packages - Removed quartz.lock.json (only relevant for git-installed plugins)
This commit is contained in:
@@ -4,6 +4,7 @@ import { execSync } from "child_process"
|
||||
import git from "isomorphic-git"
|
||||
import http from "isomorphic-git/http/node"
|
||||
import { styleText } from "util"
|
||||
import { createRequire } from "module"
|
||||
import { pathToFileURL } from "url"
|
||||
import { PluginSource } from "./types"
|
||||
|
||||
@@ -916,9 +917,11 @@ export function validatePluginExternals(
|
||||
}
|
||||
}
|
||||
|
||||
export async function regeneratePluginIndex(options: { verbose?: boolean } = {}): Promise<void> {
|
||||
export async function regeneratePluginIndex(
|
||||
options: { verbose?: boolean; npmPackages?: string[] } = {},
|
||||
): Promise<void> {
|
||||
if (!fs.existsSync(PLUGINS_CACHE_DIR)) {
|
||||
return
|
||||
fs.mkdirSync(PLUGINS_CACHE_DIR, { recursive: true })
|
||||
}
|
||||
|
||||
const pluginDirs = fs.readdirSync(PLUGINS_CACHE_DIR).filter((name) => {
|
||||
@@ -927,10 +930,12 @@ export async function regeneratePluginIndex(options: { verbose?: boolean } = {})
|
||||
})
|
||||
|
||||
// Phase 1: Collect all exports per plugin, detect conflicts
|
||||
// importPath maps plugin key → the import specifier used in generated index.ts
|
||||
const pluginExports = new Map<
|
||||
string,
|
||||
{ overridable: string[]; passthrough: string[]; types: string[] }
|
||||
>()
|
||||
const importPath = new Map<string, string>()
|
||||
const nameCount = new Map<string, number>()
|
||||
|
||||
for (const pluginName of pluginDirs) {
|
||||
@@ -954,6 +959,45 @@ export async function regeneratePluginIndex(options: { verbose?: boolean } = {})
|
||||
|
||||
if (overridable.length > 0 || passthrough.length > 0 || types.length > 0) {
|
||||
pluginExports.set(pluginName, { overridable, passthrough, types })
|
||||
importPath.set(pluginName, `./${pluginName}`)
|
||||
for (const n of [...overridable, ...passthrough]) {
|
||||
nameCount.set(n, (nameCount.get(n) ?? 0) + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const npmPkg of options.npmPackages ?? []) {
|
||||
let distIndex: string | undefined
|
||||
try {
|
||||
const esmRequire = createRequire(import.meta.url)
|
||||
const pkgJsonPath = esmRequire.resolve(`${npmPkg}/package.json`)
|
||||
distIndex = path.join(path.dirname(pkgJsonPath), "dist", "index.d.ts")
|
||||
} catch {
|
||||
if (options.verbose) {
|
||||
console.log(styleText("yellow", `⚠`), `Skipping npm package ${npmPkg}: not found`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (!distIndex || !fs.existsSync(distIndex)) {
|
||||
if (options.verbose) {
|
||||
console.log(styleText("yellow", `⚠`), `Skipping npm package ${npmPkg}: no dist/index.d.ts`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
const dtsContent = fs.readFileSync(distIndex, "utf-8")
|
||||
const exportedNames = parseExportsFromDts(dtsContent)
|
||||
const named = exportedNames.filter((e) => !e.startsWith("type "))
|
||||
const types = exportedNames.filter((e) => e.startsWith("type ")).map((e) => e.slice(5))
|
||||
|
||||
const overridable = named.filter((n) => isOverridableExport(n, dtsContent))
|
||||
const passthrough = named.filter((n) => !isOverridableExport(n, dtsContent))
|
||||
|
||||
const key = npmPkg.replace(/^@/, "").replace(/\//g, "__")
|
||||
if (overridable.length > 0 || passthrough.length > 0 || types.length > 0) {
|
||||
pluginExports.set(key, { overridable, passthrough, types })
|
||||
importPath.set(key, npmPkg)
|
||||
for (const n of [...overridable, ...passthrough]) {
|
||||
nameCount.set(n, (nameCount.get(n) ?? 0) + 1)
|
||||
}
|
||||
@@ -966,19 +1010,17 @@ export async function regeneratePluginIndex(options: { verbose?: boolean } = {})
|
||||
lines.push(`import { componentRegistry } from "../../quartz/components/registry"`)
|
||||
lines.push("")
|
||||
|
||||
// Type re-exports
|
||||
for (const [pluginName, { types }] of pluginExports) {
|
||||
for (const [pluginKey, { types }] of pluginExports) {
|
||||
if (types.length > 0) {
|
||||
lines.push(`export type { ${types.join(", ")} } from "./${pluginName}"`)
|
||||
lines.push(`export type { ${types.join(", ")} } from "${importPath.get(pluginKey)}"`)
|
||||
}
|
||||
}
|
||||
|
||||
// Direct re-exports for non-overridable values (constants, utility functions, etc.)
|
||||
for (const [pluginName, { passthrough }] of pluginExports) {
|
||||
for (const [pluginKey, { 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(`export { ${unique.join(", ")} } from "${importPath.get(pluginKey)}"`)
|
||||
}
|
||||
}
|
||||
lines.push("")
|
||||
|
||||
Reference in New Issue
Block a user