/**
 * release-notes/output-dir.mjs — shared output directory resolver.
 *
 * Extracted from draft.mjs, compile.mjs, and publish.mjs to eliminate
 * copy-paste duplication (QUA-003).
 */
import { resolve } from 'node:path';
import { loadProjectConfig } from '../config/load.mjs';
const DEFAULT_OUTPUT_DIR = 'docs/releases';
/** Allowlist for release tag values — semver-compatible subset. */
const TAG_PATTERN = /^[a-zA-Z0-9._-]+$/;
/**
 * Validate a release tag. Throws if the tag contains path-traversal
 * sequences (`..`, `/`) or characters outside the semver-compatible
 * allowlist. Defends path.join calls in compile.mjs and publish.mjs
 * against directory escape (SEC-001).
 *
 * @param {string} tag
 * @returns {void}
 */
export function validateTag(tag) {
    if (tag.includes('..') || tag.includes('/')) {
        throw new Error(`Invalid --tag: "${tag}" contains path-traversal sequences (.. or /)`);
    }
    if (!TAG_PATTERN.test(tag)) {
        throw new Error(`Invalid --tag: "${tag}" must match /^[a-zA-Z0-9._-]+$/ (no spaces or special characters)`);
    }
}
/**
 * Resolve the canonical output directory from flag override → config → default.
 * Flag override wins when present. Returns an absolute path.
 *
 * @param {string} projectDir
 * @param {string | null} flagOverride
 * @returns {string}
 */
export function resolveOutputDir(projectDir, flagOverride) {
    const config = loadProjectConfig(projectDir);
    const configured = config?.changelog?.release_notes?.output_dir;
    return resolve(projectDir, flagOverride ?? (typeof configured === 'string' ? configured : DEFAULT_OUTPUT_DIR));
}
//# sourceMappingURL=output-dir.mjs.map