📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* Trail filename utilities
|
||||
*
|
||||
* Build filenames with configurable prefix-root-suffix pattern.
|
||||
* Root is always the timestamp (YYYYMMDDhhmm), prefix and suffix are optional.
|
||||
*
|
||||
* @module trail/filename
|
||||
*/
|
||||
|
||||
export interface FilenameOptions {
|
||||
/** Optional prefix (e.g., "handoff", "log") */
|
||||
prefix?: string;
|
||||
/** Timestamp root (YYYYMMDDhhmm) - required */
|
||||
root: string;
|
||||
/** Optional suffix (e.g., session ID, slug) */
|
||||
suffix?: string;
|
||||
/** File extension (default: "md") */
|
||||
ext?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a filename from parts
|
||||
*
|
||||
* Pattern: [prefix-]root[-suffix].ext
|
||||
*
|
||||
* @example
|
||||
* buildFilename({ root: "202601221430", prefix: "handoff", suffix: "f4b8aa3a" })
|
||||
* // => "handoff-202601221430-f4b8aa3a.md"
|
||||
*
|
||||
* @example
|
||||
* buildFilename({ root: "202601221445", suffix: "api-research" })
|
||||
* // => "202601221445-api-research.md"
|
||||
*
|
||||
* @example
|
||||
* buildFilename({ root: "202601221500", prefix: "handoff" })
|
||||
* // => "handoff-202601221500.md"
|
||||
*/
|
||||
export function buildFilename(options: FilenameOptions): string {
|
||||
const { prefix, root, suffix, ext = "md" } = options;
|
||||
|
||||
const parts: string[] = [];
|
||||
|
||||
if (prefix) {
|
||||
parts.push(prefix);
|
||||
}
|
||||
|
||||
parts.push(root);
|
||||
|
||||
if (suffix) {
|
||||
parts.push(suffix);
|
||||
}
|
||||
|
||||
return `${parts.join("-")}.${ext}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a trail filename into its components
|
||||
*
|
||||
* Expects pattern: [prefix-]YYYYMMDDhhmm[-suffix].ext
|
||||
* The 12-digit timestamp is the anchor for parsing.
|
||||
*/
|
||||
export function parseFilename(filename: string): {
|
||||
prefix?: string;
|
||||
root: string;
|
||||
suffix?: string;
|
||||
ext: string;
|
||||
} | null {
|
||||
// Remove extension
|
||||
const dotIndex = filename.lastIndexOf(".");
|
||||
if (dotIndex === -1) return null;
|
||||
|
||||
const ext = filename.slice(dotIndex + 1);
|
||||
const base = filename.slice(0, dotIndex);
|
||||
|
||||
// Find the 12-digit timestamp (YYYYMMDDhhmm)
|
||||
const timestampMatch = base.match(/(\d{12})/);
|
||||
if (!timestampMatch) return null;
|
||||
|
||||
const root = timestampMatch[1];
|
||||
const rootIndex = base.indexOf(root);
|
||||
|
||||
// Everything before timestamp is prefix
|
||||
const beforeRoot = base.slice(0, rootIndex);
|
||||
const prefix = beforeRoot.endsWith("-")
|
||||
? beforeRoot.slice(0, -1)
|
||||
: beforeRoot || undefined;
|
||||
|
||||
// Everything after timestamp is suffix
|
||||
const afterRoot = base.slice(rootIndex + root.length);
|
||||
const suffix = afterRoot.startsWith("-")
|
||||
? afterRoot.slice(1)
|
||||
: afterRoot || undefined;
|
||||
|
||||
return { prefix: prefix || undefined, root, suffix: suffix || undefined, ext };
|
||||
}
|
||||
|
||||
/**
|
||||
* Slugify a string for use in filenames
|
||||
*
|
||||
* Converts to lowercase, replaces spaces/special chars with hyphens,
|
||||
* removes consecutive hyphens, trims hyphens from ends.
|
||||
*/
|
||||
export function slugify(input: string): string {
|
||||
return input
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/[^\w\s-]/g, "") // Remove special chars except hyphens
|
||||
.replace(/[\s_]+/g, "-") // Replace spaces/underscores with hyphens
|
||||
.replace(/-+/g, "-") // Collapse consecutive hyphens
|
||||
.replace(/^-|-$/g, ""); // Trim hyphens from ends
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate session ID for filename use
|
||||
*
|
||||
* Takes first 8 characters of session ID for brevity while maintaining uniqueness.
|
||||
*/
|
||||
export function truncateSessionId(sessionId: string): string {
|
||||
return sessionId.slice(0, 8);
|
||||
}
|
||||
Reference in New Issue
Block a user