Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/lib/code/language.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import type { Extension } from "@codemirror/state";

/**
* Determines the code language token used by the viewer.
*
* Explicit language wins first (trimmed and lowercased); when absent, language is inferred from
* the filename extension, and defaults to `text` when no mapping matches.
*
* @param filename - Optional source filename used for extension-based inference.
* @param explicit - Optional user-provided language override.
* @returns A normalized language key for syntax selection.
*
* Failure/fallback: unknown or missing inputs fall back to `text`.
*/
export function detectCodeLanguage(filename?: string, explicit?: string) {
const normalized = explicit?.trim().toLowerCase();
if (normalized) {
Expand All @@ -23,6 +35,17 @@ export function detectCodeLanguage(filename?: string, explicit?: string) {
return "text";
}

/**
* Lazily loads CodeMirror language support for a normalized language key.
*
* Returns an extension for supported languages and aliases (for example `js`/`javascript`,
* `python`/`py`, `yaml`/`yml`) using dynamic imports to keep base bundles small.
*
* @param language - Normalized language token from detection or artifact metadata.
* @returns A CodeMirror extension for supported languages, or `null` when unsupported.
*
* Failure/fallback: unsupported language keys return `null` so callers can render plain text.
*/
export async function loadLanguageSupport(language: string): Promise<Extension | null> {
switch (language) {
case "tsx": {
Expand Down
15 changes: 15 additions & 0 deletions src/lib/diff/git-patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,21 @@ function parsePatchSection(section: string, index: number): ParsedPatchFile {
};
}

/**
* Parses a git patch bundle into per-file patch entries.
*
* Expects a unified git patch string and splits multi-file input on each `diff --git` header;
* if no such headers are present, the full input is treated as a single section.
* Detects rename/copy metadata and binary markers (`Binary files ... differ` / `GIT binary patch`),
* normalizes paths by removing `a/` and `b/` prefixes, and sets `status`/`isBinary` accordingly.
* Output IDs are deterministic `${displayPath}-${index}` values so multiple sections with the same
* path remain distinct.
*
* @param patch - Unified git patch text that may include one or many file sections.
* @returns Parsed file-level patch records ready for diff rendering.
*
* Failure/fallback: empty or whitespace-only input returns an empty array.
*/
export function parseGitPatchBundle(patch: string): ParsedPatchFile[] {
return splitPatchSections(patch).map((section, index) => parsePatchSection(section, index));
}
13 changes: 13 additions & 0 deletions src/lib/payload/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,19 @@ function isBaseArtifact(value: unknown): value is BaseArtifact {
return hasString(value.id) && isArtifactKind(value.kind);
}

/**
* Runtime shape guard for payload envelopes decoded from untyped input.
*
* Validates top-level structure (`v`, `codec`, non-empty `artifacts`) plus per-artifact minimum
* requirements: base fields, `content` for non-diff artifacts, and either `patch` or both
* `oldContent`/`newContent` for diff artifacts.
*
* @param value - Unknown value to validate as a payload envelope.
* @returns `true` when the value matches the runtime envelope contract, otherwise `false`.
*
* Failure/fallback: this guard checks structure only and does not perform full semantic
* normalization beyond required runtime fields.
*/
export function isPayloadEnvelope(value: unknown): value is PayloadEnvelope {
if (!isRecord(value)) {
return false;
Expand Down
11 changes: 11 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

/**
* Merges conditional class values into a single Tailwind-aware class string.
*
* Combines `clsx` for variadic/conditional normalization with `tailwind-merge` conflict
* resolution so later utilities override earlier conflicting Tailwind classes.
*
* @param inputs - Class values accepted by `clsx` (strings, arrays, objects, booleans, etc.).
* @returns A merged className string with Tailwind conflicts deduplicated.
*
* Failure/fallback: invalid values are ignored by `clsx`, potentially yielding an empty string.
*/
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Loading