Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586// src/utils/folder-path.ts//// Shared folder-path normalization and validation. Used by:// - src/editor/attachment-settings.ts (resolver input; permissive)// - src/plugins/daily-notes (settings; validation + normalize)// - src/layout/settings/FolderPickerPopup (inline-create input; UX validation)//// Two layers:// normalizeFolderPath: whitespace-trim, slash-trim, collapse `/+`. Returns// empty string for root-equivalent inputs. Pure shape// transformation; never inspects segment content.// validateFolderPath: normalize + reject paths containing `.`/`..`/blank// segments OR segments whose own whitespace differs// from their trim. Returns either the normalized form// or a user-readable rejection reason.//// Two layers because callers have different concerns:// - The resolver in attachment-settings just needs "give me a clean path or// vault root"; bad input falls back to root rather than throwing.// - The UI submit path needs a discriminated success/failure so it can show// a useful error message.
export interface ValidatedFolderPath { ok: true /** The normalized (canonical) form of the input. Never starts/ends with `/`, * never contains `//`. Empty string means vault root. */ normalized: string}
export interface InvalidFolderPath { ok: false /** Human-readable rejection reason suitable for inline UI display. */ reason: string}
export type FolderPathValidation = ValidatedFolderPath | InvalidFolderPath
/** * Normalize a folder path. Pure shape transformation: * - Trim outer whitespace. * - Strip leading and trailing slashes. * - Collapse consecutive slashes (`a//b` → `a/b`). * Returns empty string for root-equivalent inputs (`''`, `'/'`, `' '`). * * Does NOT inspect segment content. Callers that need strict checks * (reject `..`, blank segments, inner whitespace) should use * `validateFolderPath` instead. */export function normalizeFolderPath(raw: string): string { return raw .trim() .replace(/\/+/g, '/') .replace(/^\/+/, '') .replace(/\/+$/, '')}
/** * Validate a folder path for use as a vault-relative folder reference. * Normalizes the input, then rejects it if any segment is: * - `.` or `..` — path traversal * - empty after trim — would create `//` * - differs from its own trim — leading/trailing whitespace inside a segment * * Empty input (after normalize) is treated as the vault root and considered * valid (`{ ok: true, normalized: '' }`). Callers that require a non-empty * folder (e.g. inline-create UI) must check `normalized !== ''` themselves. * * The rejection reasons are intentionally short and user-facing. */export function validateFolderPath(raw: string): FolderPathValidation { const normalized = normalizeFolderPath(raw) if (normalized === '') return { ok: true, normalized: '' }
const segments = normalized.split('/') for (const seg of segments) { if (seg === '.' || seg === '..') { return { ok: false, reason: `Path segment '${seg}' is not allowed.` } } if (seg !== seg.trim()) { return { ok: false, reason: `Segment '${seg}' has leading or trailing whitespace.` } } }
return { ok: true, normalized }}