diff --git a/src/output.ts b/src/output.ts index 45509f35..4d667b42 100644 --- a/src/output.ts +++ b/src/output.ts @@ -1,5 +1,5 @@ -import { copyFile, writeFile } from 'node:fs/promises' -import { join, relative } from 'node:path' +import { copyFile, mkdir, writeFile } from 'node:fs/promises' +import { dirname, join, relative } from 'node:path' import { logger } from './logger' @@ -96,7 +96,12 @@ export const outputAssets = async (dest: string, assets: Map): P logger.log(`skipped copy '${name}' with same content`) return } - await copyFile(from, join(dest, name)) + const destPath = join(dest, name) + const destDir = dirname(destPath) + if (destDir !== dest) { + await mkdir(destDir, { recursive: true }) + } + await copyFile(from, destPath) // logger.log(`copied '${name}' from '${from}'`) emitted.set(name, from) count++ diff --git a/src/schemas/image.ts b/src/schemas/image.ts index be17b396..acc5f0d2 100644 --- a/src/schemas/image.ts +++ b/src/schemas/image.ts @@ -12,17 +12,21 @@ export interface ImageOptions { * @default undefined */ absoluteRoot?: string - // /** - // * allow remote url - // * @default false - // */ - // allowRemoteUrl?: boolean + /** + * Custom output name template for the asset + * Supports placeholders: [name], [hash], [hash:N], [ext] + * Can include subdirectories (e.g., 'logos/[name]-[hash:6].[ext]') + * @default undefined (uses global output.name from config) + * @example 'logo-[name]-[hash:6].[ext]' + * @example 'logos/[name]-[hash:6].[ext]' + */ + outputName?: string } /** * Image schema */ -export const image = ({ absoluteRoot }: ImageOptions = {}) => +export const image = ({ absoluteRoot, outputName }: ImageOptions = {}) => string().transform(async (value, { meta, addIssue }) => { try { if (absoluteRoot && /^\//.test(value)) { @@ -44,7 +48,8 @@ export const image = ({ absoluteRoot }: ImageOptions = {}) => const { output } = meta.config // process asset as relative path - return await processAsset(value, meta.path, output.name, output.base, true) + const assetName = outputName ?? output.name + return await processAsset(value, meta.path, assetName, output.base, true) } catch (err) { const message = err instanceof Error ? err.message : String(err) addIssue({ fatal: true, code: 'custom', message })