Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Refactor commit and diff types, updates outdated diff types
Sebastian Martinez committed 2 years ago
commit ca6762fc956bc06b152e72a8f7334954630b1d38
parent afab097d09e9b3563153d4327905bb687c1f75c2
5 files changed +168 -143
modified httpd-client/index.ts
@@ -11,8 +11,6 @@ import type {
  Commit,
  CommitHeader,
  Diff,
-
  DiffAddedDeletedModifiedChangeset,
-
  DiffCopiedMovedChangeset,
  HunkLine,
} from "./lib/project/commit.js";
import type { Issue, IssueState } from "./lib/project/issue.js";
@@ -44,8 +42,6 @@ export type {
  Commit,
  CommitHeader,
  Diff,
-
  DiffAddedDeletedModifiedChangeset,
-
  DiffCopiedMovedChangeset,
  DiffResponse,
  HunkLine,
  Issue,
modified httpd-client/lib/project/commit.ts
@@ -1,171 +1,175 @@
-
import type { ZodSchema } from "zod";
-
import { array, literal, number, object, string, union } from "zod";
-

-
interface GitPerson {
-
  name: string;
-
  email: string;
-
}
+
import type { z } from "zod";
+
import { array, literal, number, object, optional, string, union } from "zod";
+

+
export { commitHeaderSchema, diffSchema, commitSchema, commitsSchema };
+

+
export type {
+
  Commits,
+
  HunkLine,
+
  Commit,
+
  DiffFile,
+
  Diff,
+
  DiffCopiedChangeset,
+
  DiffMovedChangeset,
+
  CommitHeader,
+
  DiffAddedChangeset,
+
  DiffDeletedChangeset,
+
  DiffModifiedChangeset,
+
  DiffContent,
+
};

const gitPersonSchema = object({
  name: string(),
  email: string(),
-
}) satisfies ZodSchema<GitPerson>;
-

-
export interface CommitHeader {
-
  id: string;
-
  author: GitPerson;
-
  summary: string;
-
  description: string;
-
  parents: string[];
-
  committer: GitPerson & { time: number };
-
}
-

-
export const commitHeaderSchema = object({
+
});
+

+
type CommitHeader = z.infer<typeof commitHeaderSchema>;
+

+
const commitHeaderSchema = object({
  id: string(),
  author: gitPersonSchema,
  summary: string(),
  description: string(),
  parents: array(string()),
  committer: gitPersonSchema.merge(object({ time: number() })),
-
}) satisfies ZodSchema<CommitHeader>;
+
});

-
interface AdditionHunkLine {
-
  line: string;
-
  lineNo: number;
-
  type: "addition";
-
}
+
type AdditionHunkLine = z.infer<typeof additionHunkLineSchema>;

const additionHunkLineSchema = object({
  line: string(),
  lineNo: number(),
  type: literal("addition"),
-
}) satisfies ZodSchema<AdditionHunkLine>;
+
});

-
interface DeletionHunkLine {
-
  line: string;
-
  lineNo: number;
-
  type: "deletion";
-
}
+
type DeletionHunkLine = z.infer<typeof deletionHunkLineSchema>;

const deletionHunkLineSchema = object({
  line: string(),
  lineNo: number(),
  type: literal("deletion"),
-
}) satisfies ZodSchema<DeletionHunkLine>;
+
});

-
interface ContextHunkLine {
-
  line: string;
-
  lineNoNew: number;
-
  lineNoOld: number;
-
  type: "context";
-
}
+
type DiffFile = z.infer<typeof diffFileSchema>;
+

+
const diffFileSchema = object({
+
  oid: string(),
+
  mode: union([
+
    literal("blob"),
+
    literal("blobExecutable"),
+
    literal("tree"),
+
    literal("link"),
+
    literal("commit"),
+
  ]),
+
});
+

+
type ContextHunkLine = z.infer<typeof contextHunkLineSchema>;

const contextHunkLineSchema = object({
  line: string(),
  lineNoNew: number(),
  lineNoOld: number(),
  type: literal("context"),
-
}) satisfies ZodSchema<ContextHunkLine>;
+
});

-
export type HunkLine = AdditionHunkLine | DeletionHunkLine | ContextHunkLine;
+
type HunkLine = AdditionHunkLine | DeletionHunkLine | ContextHunkLine;

const hunkLineSchema = union([
  additionHunkLineSchema,
  deletionHunkLineSchema,
  contextHunkLineSchema,
-
]) satisfies ZodSchema<HunkLine>;
-

-
interface ChangesetHunk {
-
  header: string;
-
  lines: HunkLine[];
-
}
+
]);

const changesetHunkSchema = object({
  header: string(),
  lines: array(hunkLineSchema),
-
}) satisfies ZodSchema<ChangesetHunk>;
-

-
export interface DiffAddedDeletedModifiedChangeset {
-
  path: string;
-
  diff: {
-
    type: "plain" | "binary" | "empty";
-
    hunks: ChangesetHunk[];
-
    eof: "noneMissing" | "oldMissing" | "newMissing" | "bothMissing";
-
  };
-
}
-

-
const diffAddedDeletedModifiedChangesetSchema = object({
+
});
+

+
type DiffContent = z.infer<typeof diffContentSchema>;
+

+
const diffContentSchema = object({
+
  type: union([literal("plain"), literal("binary"), literal("empty")]),
+
  hunks: array(changesetHunkSchema),
+
  eof: union([
+
    literal("noneMissing"),
+
    literal("oldMissing"),
+
    literal("newMissing"),
+
    literal("bothMissing"),
+
  ]),
+
});
+

+
type DiffAddedChangeset = z.infer<typeof diffAddedChangesetSchema>;
+

+
const diffAddedChangesetSchema = object({
  path: string(),
-
  diff: object({
-
    type: union([literal("plain"), literal("binary"), literal("empty")]),
-
    hunks: array(changesetHunkSchema),
-
    eof: union([
-
      literal("noneMissing"),
-
      literal("oldMissing"),
-
      literal("newMissing"),
-
      literal("bothMissing"),
-
    ]),
-
  }),
-
}) satisfies ZodSchema<DiffAddedDeletedModifiedChangeset>;
+
  diff: diffContentSchema,
+
  new: diffFileSchema,
+
});

-
export interface DiffCopiedMovedChangeset {
-
  newPath: string;
-
  oldPath: string;
-
}
+
type DiffDeletedChangeset = z.infer<typeof diffDeletedChangesetSchema>;

-
const diffCopiedMovedChangesetSchema = object({
+
const diffDeletedChangesetSchema = object({
+
  path: string(),
+
  diff: diffContentSchema,
+
  old: diffFileSchema,
+
});
+

+
type DiffModifiedChangeset = z.infer<typeof diffModifiedChangesetSchema>;
+

+
const diffModifiedChangesetSchema = object({
+
  path: string(),
+
  diff: diffContentSchema,
+
  new: diffFileSchema,
+
  old: diffFileSchema,
+
});
+

+
type DiffCopiedChangeset = z.infer<typeof diffCopiedChangesetSchema>;
+

+
const diffCopiedChangesetSchema = object({
  newPath: string(),
  oldPath: string(),
-
}) satisfies ZodSchema<DiffCopiedMovedChangeset>;
-

-
export interface Diff {
-
  added: DiffAddedDeletedModifiedChangeset[];
-
  deleted: DiffAddedDeletedModifiedChangeset[];
-
  moved: DiffCopiedMovedChangeset[];
-
  copied: DiffCopiedMovedChangeset[];
-
  modified: DiffAddedDeletedModifiedChangeset[];
-
  stats: {
-
    filesChanged: number;
-
    insertions: number;
-
    deletions: number;
-
  };
-
}
-

-
export const diffSchema = object({
-
  added: array(diffAddedDeletedModifiedChangesetSchema),
-
  deleted: array(diffAddedDeletedModifiedChangesetSchema),
-
  moved: array(diffCopiedMovedChangesetSchema),
-
  copied: array(diffCopiedMovedChangesetSchema),
-
  modified: array(diffAddedDeletedModifiedChangesetSchema),
+
});
+

+
type DiffMovedChangeset = z.infer<typeof diffMovedChangesetSchema>;
+

+
const diffMovedChangesetSchema = diffCopiedChangesetSchema.merge(
+
  object({
+
    old: optional(diffFileSchema),
+
    new: optional(diffFileSchema),
+
    diff: optional(diffContentSchema),
+
  }),
+
);
+

+
type Diff = z.infer<typeof diffSchema>;
+

+
const diffSchema = object({
+
  added: array(diffAddedChangesetSchema),
+
  deleted: array(diffDeletedChangesetSchema),
+
  modified: array(diffModifiedChangesetSchema),
+
  moved: array(diffMovedChangesetSchema),
+
  copied: array(diffCopiedChangesetSchema),
  stats: object({
    filesChanged: number(),
    insertions: number(),
    deletions: number(),
  }),
-
}) satisfies ZodSchema<Diff>;
+
});

-
export interface Commit {
-
  commit: CommitHeader;
-
  diff: Diff;
-
  branches: string[];
-
}
+
type Commit = z.infer<typeof commitSchema>;

-
export const commitSchema = object({
+
const commitSchema = object({
  commit: commitHeaderSchema,
  diff: diffSchema,
  branches: array(string()),
-
}) satisfies ZodSchema<Commit>;
+
});

-
export interface Commits {
-
  commits: Commit[];
-
  stats: { commits: number; branches: number; contributors: number };
-
}
+
type Commits = z.infer<typeof commitsSchema>;

-
export const commitsSchema = object({
+
const commitsSchema = object({
  commits: array(commitSchema),
  stats: object({
    commits: number(),
    branches: number(),
    contributors: number(),
  }),
-
}) satisfies ZodSchema<Commits>;
+
});
modified src/views/projects/Changeset.svelte
@@ -72,25 +72,53 @@
    <FileDiff
      {projectId}
      {baseUrl}
-
      {file}
      {revision}
+
      filePath={file.path}
+
      fileDiff={file.diff}
      headerBadgeCaption="added" />
  {/each}
  {#each diff.deleted as file}
    <FileDiff
      {projectId}
      {baseUrl}
-
      {file}
      {revision}
+
      filePath={file.path}
+
      fileDiff={file.diff}
      headerBadgeCaption="deleted" />
  {/each}
  {#each diff.modified as file}
-
    <FileDiff {projectId} {baseUrl} {file} {revision} />
+
    <FileDiff
+
      {projectId}
+
      {baseUrl}
+
      {revision}
+
      filePath={file.path}
+
      fileDiff={file.diff} />
  {/each}
  {#each diff.moved as file}
-
    <FileLocationChange {projectId} {baseUrl} {file} {revision} mode="moved" />
+
    {#if file.diff}
+
      <FileDiff
+
        {projectId}
+
        {baseUrl}
+
        {revision}
+
        filePath={file.newPath}
+
        fileDiff={file.diff} />
+
    {:else}
+
      <FileLocationChange
+
        {projectId}
+
        {baseUrl}
+
        {revision}
+
        newPath={file.newPath}
+
        oldPath={file.oldPath}
+
        mode="moved" />
+
    {/if}
  {/each}
  {#each diff.copied as file}
-
    <FileLocationChange {projectId} {baseUrl} {file} {revision} mode="copied" />
+
    <FileLocationChange
+
      {projectId}
+
      {baseUrl}
+
      {revision}
+
      newPath={file.newPath}
+
      oldPath={file.oldPath}
+
      mode="copied" />
  {/each}
</div>
modified src/views/projects/Changeset/FileDiff.svelte
@@ -1,16 +1,14 @@
<script lang="ts">
  import { onDestroy, onMount } from "svelte";
-
  import type {
-
    BaseUrl,
-
    DiffAddedDeletedModifiedChangeset,
-
    HunkLine,
-
  } from "@httpd-client";
+
  import type { DiffContent } from "@httpd-client/lib/project/commit";
+
  import type { BaseUrl, HunkLine } from "@httpd-client";

  import Badge from "@app/components/Badge.svelte";
  import Icon from "@app/components/Icon.svelte";
  import Link from "@app/components/Link.svelte";

-
  export let file: DiffAddedDeletedModifiedChangeset;
+
  export let filePath: string;
+
  export let fileDiff: DiffContent;
  export let revision: string;
  export let headerBadgeCaption: "added" | "deleted" | undefined = undefined;
  export let baseUrl: BaseUrl;
@@ -28,11 +26,9 @@
    if (selection) {
      document
        .getElementById(
-
          [
-
            file.path,
-
            "H" + selection.startHunk,
-
            "L" + selection.startLine,
-
          ].join("-"),
+
          [filePath, "H" + selection.startHunk, "L" + selection.startLine].join(
+
            "-",
+
          ),
        )
        ?.scrollIntoView();
    }
@@ -57,7 +53,7 @@
  function updateSelection() {
    const fragment = window.location.hash.substring(1);
    const match = fragment.match(/(.+):H(\d+)L(\d+)(H(\d+)L(\d+))?/);
-
    if (match && match[1] === file.path) {
+
    if (match && match[1] === filePath) {
      selection = {
        startHunk: parseInt(match[2]),
        startLine: parseInt(match[3]),
@@ -139,7 +135,7 @@
    lineIdx: number,
    event: MouseEvent,
  ): string {
-
    const path = file.path;
+
    const path = filePath;
    // single line selection
    if (!event.shiftKey) {
      return path + ":H" + hunkIdx + "L" + lineIdx;
@@ -317,7 +313,7 @@
  }
</style>

-
<div id={file.path} class="wrapper">
+
<div id={filePath} class="wrapper">
  <header class="header">
    <!-- svelte-ignore a11y-click-events-have-key-events -->
    <!-- svelte-ignore a11y-no-static-element-interactions -->
@@ -329,7 +325,7 @@
      {/if}
    </div>
    <div class="actions">
-
      <p class="txt-regular">{file.path}</p>
+
      <p class="txt-regular">{filePath}</p>
      {#if headerBadgeCaption === "added"}
        <Badge variant="positive">added</Badge>
      {:else if headerBadgeCaption === "deleted"}
@@ -342,7 +338,7 @@
          resource: "project.source",
          project: projectId,
          node: baseUrl,
-
          path: file.path,
+
          path: filePath,
          revision,
        }}>
        <Icon name="browse" />
@@ -351,10 +347,10 @@
  </header>
  {#if !collapsed}
    <main>
-
      {#if file.diff.type === "plain"}
-
        {#if file.diff.hunks.length > 0}
+
      {#if fileDiff.type === "plain"}
+
        {#if fileDiff.hunks.length > 0}
          <table class="diff" data-file-diff-select>
-
            {#each file.diff.hunks as hunk, hunkIdx}
+
            {#each fileDiff.hunks as hunk, hunkIdx}
              <tr
                class="diff-line hunk-header"
                class:selected={hunkHeaderSelected(selection, hunkIdx)}>
@@ -370,7 +366,7 @@
                  class={`diff-line type-${line.type}`}
                  class:selected={isLineSelected(selection, hunkIdx, lineIdx)}>
                  <td
-
                    id={[file.path, "H" + hunkIdx, "L" + lineIdx].join("-")}
+
                    id={[filePath, "H" + hunkIdx, "L" + lineIdx].join("-")}
                    class="diff-line-number left"
                    on:click={e => selectLine(hunkIdx, lineIdx, e)}>
                    <div class="selection-indicator" />
modified src/views/projects/Changeset/FileLocationChange.svelte
@@ -1,11 +1,12 @@
<script lang="ts">
-
  import type { BaseUrl, DiffCopiedMovedChangeset } from "@httpd-client";
+
  import type { BaseUrl } from "@httpd-client";

  import Badge from "@app/components/Badge.svelte";
  import Icon from "@app/components/Icon.svelte";
  import Link from "@app/components/Link.svelte";

-
  export let file: DiffCopiedMovedChangeset;
+
  export let newPath: string;
+
  export let oldPath: string;
  export let revision: string;
  export let mode: "moved" | "copied";
  export let baseUrl: BaseUrl;
@@ -40,10 +41,10 @@
  }
</style>

-
<div id={file.newPath} class="wrapper">
+
<div id={newPath} class="wrapper">
  <header class="header">
    <div class="actions">
-
      <p class="txt-regular">{file.oldPath} → {file.newPath}</p>
+
      <p class="txt-regular">{oldPath} → {newPath}</p>
      {#if mode === "moved"}
        <Badge variant="foreground">moved</Badge>
      {:else if mode === "copied"}
@@ -56,7 +57,7 @@
          resource: "project.source",
          project: projectId,
          node: baseUrl,
-
          path: file.newPath,
+
          path: newPath,
          revision,
        }}>
        <Icon name="browse" />