UNPKG

astro

Version:

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

80 lines (79 loc) • 3.02 kB
import { mergeConfig as mergeViteConfig } from "vite"; import { arraify, isObject, isURL } from "../util-runtime.js"; function isImageServiceTargets(service) { return isObject(service) && ("build" in service || "runtime" in service); } function hasDefinedValues(value) { return Object.values(value).some((v) => v !== undefined); } function mergeConfigRecursively(defaults, overrides, rootPath) { const merged = { ...defaults }; for (const key in overrides) { const value = overrides[key]; if (value == null) { continue; } const existing = merged[key]; if (existing == null) { merged[key] = value; continue; } // fields that require special handling: if (key === "vite" && rootPath === "") { merged[key] = mergeViteConfig(existing, value); continue; } // Merging a single service with `{ build, runtime }` would mix the shapes. if (key === "service" && rootPath === "image") { // An override like `{ entrypoint: undefined }` sets nothing, so it shouldn't replace the existing service. if (isObject(value) && !hasDefinedValues(value)) { continue; } if (isImageServiceTargets(existing) !== isImageServiceTargets(value)) { merged[key] = value; continue; } } if (key === "server" && rootPath === "") { // server config can be a function or an object, if one of the two values is a function, // create a new wrapper function that merges them if (typeof existing === "function" || typeof value === "function") { merged[key] = (...args) => { const existingConfig = typeof existing === "function" ? existing(...args) : existing; const valueConfig = typeof value === "function" ? value(...args) : value; return mergeConfigRecursively(existingConfig, valueConfig, key); }; continue; } } // for server.allowedHosts, if either value is a boolean, don't merge as arrays if (key === "allowedHosts" && rootPath === "server" && (typeof existing === "boolean" || typeof value === "boolean")) { merged[key] = typeof value === "boolean" ? value : existing; continue; } if (Array.isArray(existing) || Array.isArray(value)) { merged[key] = [...arraify(existing ?? []), ...arraify(value ?? [])]; continue; } if (isURL(existing) && isURL(value)) { merged[key] = value; continue; } // `markdown.processor` is replaced atomically. Deep-merging would mix the inactive // default's options into the user's chosen processor (e.g. user passes a third-party // processor, the default unified() `createRenderer` would leak in). if (key === "processor" && rootPath === "markdown" && isObject(value) && typeof value.createRenderer === "function") { merged[key] = value; continue; } if (isObject(existing) && isObject(value)) { merged[key] = mergeConfigRecursively(existing, value, rootPath ? `${rootPath}.${key}` : key); continue; } merged[key] = value; } return merged; } export function mergeConfig(defaults, overrides) { return mergeConfigRecursively(defaults, overrides, ""); }