@nkzw/codiff-core 1.14.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ import { type ReactNode } from 'react';
3
3
  import type { CodiffDiffStyle, CodiffKeymap } from '../../config/types.ts';
4
4
  import type { CodeViewInstance, DiffSearchMatch, ReviewComment, ReviewIdentity, ReviewScrollTarget, WalkthroughNote } from '../../lib/app-types.ts';
5
5
  import type { ChangedFile, CodiffPreferences, CommitMetadata, DefinitionCandidate, DefinitionSearchRequest, DefinitionSearchResult, DiffImageContentRequest, DiffImageContentResult, DiffSection, GitIdentity, PullRequestCodeQualityFinding, ReviewSource } from '../../types.ts';
6
+ import { type CodeEditingStore } from '../hooks/useCodeEditing.ts';
6
7
  type PullRequestSource = Extract<ReviewSource, {
7
8
  type: 'pull-request';
8
9
  }>;
@@ -39,13 +40,14 @@ type HeaderReviewDiffBlock = {
39
40
  selected?: boolean;
40
41
  };
41
42
  export type ReviewDiffBlock = FileReviewDiffBlock | HeaderReviewDiffBlock;
42
- export declare function ReviewCodeView({ activeSearchMatch, agentId, agentLabel, allowViewedToggle, blocks, bottomInset, codeQualityFindings, collapsed, comments, commitMetadata, diffLineHeight, diffStyle, disableWorkerPool, expandedReviewKeys, files, focusCommentId, focusCommentRequest, forceExpandedPaths, gitIdentity, hunkNavigation, initialMarkdownPreviewSectionIds, isReadOnly, itemVersionByKey, keymap, loadingSectionIds, onActiveBlockChange, onAskCodex, onCommentDraftChange, onCreateComment, onDeleteComment, onFindDefinitions, onLoadImageContent, onLoadSection, onLoadSectionContents, onOpenDefinition, onOpenFile, onRefreshMarkdown, onResolveThread, onSaveCommentEdit, onSelectPathFromScroll, onSubmitComment, onToggleCollapsed, onToggleViewed, onUpdateComment, onUpdateSourceDescription, onUpdateSourceTitle, onUploadSourceDescriptionAsset, reviewIdentityByPath, scrollTarget, searchQuery, selectedPath, showSourceDescription, showWhitespace, source, sourceDescriptionActions, sourceDescriptionFooter, supportsReviewCommentActions, theme, viewed, walkthroughNotes, wordWrap, }: {
43
+ export declare function ReviewCodeView({ activeSearchMatch, agentId, agentLabel, allowViewedToggle, blocks, bottomInset, codeEditingStore, codeQualityFindings, collapsed, comments, commitMetadata, diffLineHeight, diffStyle, disableWorkerPool, expandedReviewKeys, files, focusCommentId, focusCommentRequest, forceExpandedPaths, gitIdentity, hunkNavigation, initialMarkdownPreviewSectionIds, isReadOnly, itemVersionByKey, keymap, loadingSectionIds, onActiveBlockChange, onAskCodex, onCommentDraftChange, onCreateComment, onDeleteComment, onFindDefinitions, onLoadImageContent, onLoadSection, onLoadSectionContents, onOpenDefinition, onOpenFile, onRefreshMarkdown, onResolveThread, onSaveCommentEdit, onSelectPathFromScroll, onSubmitComment, onToggleCollapsed, onToggleViewed, onUpdateComment, onUpdateSourceDescription, onUpdateSourceTitle, onUploadSourceDescriptionAsset, reviewIdentityByPath, scrollTarget, searchQuery, selectedPath, showSourceDescription, showWhitespace, source, sourceDescriptionActions, sourceDescriptionFooter, supportsReviewCommentActions, theme, viewed, walkthroughNotes, wordWrap, }: {
43
44
  activeSearchMatch: DiffSearchMatch | null;
44
45
  agentId: 'codex' | 'claude' | 'opencode' | 'pi';
45
46
  agentLabel: string;
46
47
  allowViewedToggle?: boolean;
47
48
  blocks?: ReadonlyArray<ReviewDiffBlock>;
48
49
  bottomInset?: number;
50
+ codeEditingStore?: CodeEditingStore;
49
51
  codeQualityFindings?: ReadonlyArray<PullRequestCodeQualityFinding>;
50
52
  collapsed: ReadonlySet<string>;
51
53
  comments: ReadonlyArray<ReviewComment>;
@@ -0,0 +1,68 @@
1
+ import type { CodeViewDiffItem, CodeViewItem } from '@pierre/diffs';
2
+ import type { CodeViewItemMetadata, ReviewAnnotationMetadata } from '../../lib/app-types.ts';
3
+ import type { RepositoryFileDocument } from '../../types.ts';
4
+ export declare const CODE_AUTOSAVE_DELAY = 300;
5
+ export type EditSession = {
6
+ dirty: boolean;
7
+ document: RepositoryFileDocument;
8
+ finishing?: 'done' | 'revert';
9
+ hasChanges: boolean;
10
+ item: CodeViewDiffItem<ReviewAnnotationMetadata>;
11
+ metadata: CodeViewItemMetadata;
12
+ originalContent: string;
13
+ saveError?: string;
14
+ saving?: boolean;
15
+ sourceKey: string;
16
+ };
17
+ declare const createFileEditingStore: (onChange: () => void) => {
18
+ draftRef: {
19
+ current: string;
20
+ };
21
+ finish: (revert: boolean, beforeClose?: () => Promise<void>) => Promise<boolean>;
22
+ flush: () => Promise<boolean>;
23
+ getSnapshot: () => EditSession | null;
24
+ setDraft: (content: string) => void;
25
+ setSession: (session: EditSession | null) => void;
26
+ };
27
+ export type CodeEditingSession = ReturnType<typeof createFileEditingStore>;
28
+ export declare const getCodeEditKey: (sourceKey: string, itemId: string) => string;
29
+ export declare const createCodeEditingStore: () => {
30
+ clear: () => void;
31
+ flush: (sourceKey: string) => Promise<boolean[]>;
32
+ get: (sourceKey: string, itemId: string) => {
33
+ draftRef: {
34
+ current: string;
35
+ };
36
+ finish: (revert: boolean, beforeClose?: () => Promise<void>) => Promise<boolean>;
37
+ flush: () => Promise<boolean>;
38
+ getSnapshot: () => EditSession | null;
39
+ setDraft: (content: string) => void;
40
+ setSession: (session: EditSession | null) => void;
41
+ } | undefined;
42
+ getForItem: (item: CodeViewItem<ReviewAnnotationMetadata>) => {
43
+ draftRef: {
44
+ current: string;
45
+ };
46
+ finish: (revert: boolean, beforeClose?: () => Promise<void>) => Promise<boolean>;
47
+ flush: () => Promise<boolean>;
48
+ getSnapshot: () => EditSession | null;
49
+ setDraft: (content: string) => void;
50
+ setSession: (session: EditSession | null) => void;
51
+ } | undefined;
52
+ getSnapshot: () => ReadonlyMap<string, EditSession>;
53
+ hasFile: (path: string) => boolean;
54
+ hasUnsavedEdits: () => boolean;
55
+ start: (session: EditSession) => {
56
+ draftRef: {
57
+ current: string;
58
+ };
59
+ finish: (revert: boolean, beforeClose?: () => Promise<void>) => Promise<boolean>;
60
+ flush: () => Promise<boolean>;
61
+ getSnapshot: () => EditSession | null;
62
+ setDraft: (content: string) => void;
63
+ setSession: (session: EditSession | null) => void;
64
+ } | null;
65
+ subscribe: (listener: () => void) => () => void;
66
+ };
67
+ export type CodeEditingStore = ReturnType<typeof createCodeEditingStore>;
68
+ export {};
@@ -0,0 +1,34 @@
1
+ import { type CodeViewItem, type FileDiffLoadedFiles } from '@pierre/diffs';
2
+ import type { EditorChangeEvent, EditorFactory, EditorOptions, EditorType } from '@pierre/diffs/edit';
3
+ import type { CodeViewHandle, CodeViewItemEditCompleteHandler } from '@pierre/diffs/react';
4
+ import { type RefObject } from 'react';
5
+ import type { CodiffKeymap } from '../../config/types.ts';
6
+ import type { CodeViewItemMetadata, ReviewAnnotationMetadata } from '../../lib/app-types.ts';
7
+ import type { ChangedFile, DiffSection } from '../../types.ts';
8
+ import { type CodeEditingStore, type EditSession } from './code-editing-store.ts';
9
+ export { createCodeEditingStore, type CodeEditingStore } from './code-editing-store.ts';
10
+ export declare const createCodeEditor: EditorFactory<ReviewAnnotationMetadata, undefined>;
11
+ export declare function useUnsavedCodeEditsGuard(store: CodeEditingStore): void;
12
+ export declare function useCodeEditing({ codeViewRef, items, keymap, onLoadSectionContents, onRefresh, selectedItemId, sourceKey, store: sharedStore, }: {
13
+ codeViewRef: RefObject<CodeViewHandle<ReviewAnnotationMetadata, undefined> | null>;
14
+ items: ReadonlyArray<CodeViewItem<ReviewAnnotationMetadata>>;
15
+ keymap?: CodiffKeymap;
16
+ onLoadSectionContents?: (file: ChangedFile, section: DiffSection) => Promise<FileDiffLoadedFiles>;
17
+ onRefresh?: (file: ChangedFile, section: DiffSection) => Promise<boolean>;
18
+ selectedItemId?: string;
19
+ sourceKey: string;
20
+ store?: CodeEditingStore;
21
+ }): {
22
+ canStartEdit: (itemId: string, path: string) => boolean;
23
+ doneEdit: (itemId: string) => Promise<void>;
24
+ editorOptions: EditorOptions<EditorType, ReviewAnnotationMetadata, undefined>;
25
+ getError: (itemId: string) => string | undefined;
26
+ isBusy: (itemId: string) => boolean;
27
+ items: readonly CodeViewItem<ReviewAnnotationMetadata>[];
28
+ onItemEditChange: (event: EditorChangeEvent<EditorType, ReviewAnnotationMetadata, undefined>, item: CodeViewItem<ReviewAnnotationMetadata>) => void;
29
+ onItemEditComplete: CodeViewItemEditCompleteHandler<ReviewAnnotationMetadata, undefined>;
30
+ prepareEdit: (item: CodeViewItem<ReviewAnnotationMetadata>, metadata: CodeViewItemMetadata) => Promise<void>;
31
+ revertEdit: (itemId: string) => Promise<void>;
32
+ sessions: Map<string, EditSession>;
33
+ startEdit: (item: CodeViewItem<ReviewAnnotationMetadata>, metadata: CodeViewItemMetadata) => Promise<void>;
34
+ };
@@ -30,6 +30,8 @@ export type CodiffKeymap = {
30
30
  commandBar: KeyCombo;
31
31
  diffSearch: KeyCombo;
32
32
  discardComment: KeyCombo;
33
+ doneEditing: KeyCombo;
34
+ editFile: KeyCombo;
33
35
  fileFilter: KeyCombo;
34
36
  nextHunk: KeyComboBinding;
35
37
  nextSearchMatch: KeyCombo;
@@ -1,5 +1,4 @@
1
- import type { DiffSection, GitFileStatus } from '../types.ts';
2
- export declare const statusLabel: Record<GitFileStatus, string>;
1
+ import type { DiffSection } from '../types.ts';
3
2
  export declare const sectionLabel: Record<DiffSection['kind'], string>;
4
3
  export declare const DEFAULT_PADDING = 11;
5
4
  export declare const codeViewLayout: {
@@ -106,10 +106,14 @@ declare const getSectionWalkthroughHunks: (file: {
106
106
  sectionKind: string;
107
107
  status: string;
108
108
  }[];
109
+ /** Read the source-order hunk ordinal from a section-scoped id.
110
+ * @param {string} sectionId @param {string} hunkId
111
+ */
112
+ declare const getHunkOrdinal: (sectionId: string, hunkId: string) => number | null;
109
113
  /**
110
114
  * @param {string} patch
111
115
  * @param {string} sectionId
112
116
  * @param {ReadonlyArray<string>} hunkIds
113
117
  */
114
118
  declare const filterPatchToHunkIds: (patch: string, sectionId: string, hunkIds: ReadonlyArray<string>) => string | null;
115
- export { buildAnchorDisplay, extractPatchHunks, filterPatchToHunkIds, getSectionWalkthroughHunks, HUNK_HEADER, hunkDisplayEnd, hunkDisplayStart, isGeneratedWalkthroughFile, isGeneratedWalkthroughPath, isSyntheticWalkthroughHunk, parseHunkHeader, sumHunkLineCounts, };
119
+ export { buildAnchorDisplay, extractPatchHunks, filterPatchToHunkIds, getHunkOrdinal, getSectionWalkthroughHunks, HUNK_HEADER, hunkDisplayEnd, hunkDisplayStart, isGeneratedWalkthroughFile, isGeneratedWalkthroughPath, isSyntheticWalkthroughHunk, parseHunkHeader, sumHunkLineCounts, };
@@ -209,7 +209,9 @@ const getSectionWalkthroughHunks = (file, section) => {
209
209
  }));
210
210
  return shouldCreateSyntheticHunk(file, section) ? [createSyntheticSectionHunk(file, section)] : [];
211
211
  };
212
- /** @param {string} sectionId @param {string} hunkId */
212
+ /** Read the source-order hunk ordinal from a section-scoped id.
213
+ * @param {string} sectionId @param {string} hunkId
214
+ */
213
215
  const getHunkOrdinal = (sectionId, hunkId) => {
214
216
  const prefix = `${sectionId}:h`;
215
217
  if (!hunkId.startsWith(prefix)) return null;
@@ -256,4 +258,4 @@ const filterPatchToHunkIds = (patch, sectionId, hunkIds) => {
256
258
  return patch.endsWith("\n") && !focused.endsWith("\n") ? `${focused}\n` : focused;
257
259
  };
258
260
  //#endregion
259
- export { HUNK_HEADER, buildAnchorDisplay, extractPatchHunks, filterPatchToHunkIds, getSectionWalkthroughHunks, hunkDisplayEnd, hunkDisplayStart, isGeneratedWalkthroughFile, isGeneratedWalkthroughPath, isSyntheticWalkthroughHunk, parseHunkHeader, sumHunkLineCounts };
261
+ export { HUNK_HEADER, buildAnchorDisplay, extractPatchHunks, filterPatchToHunkIds, getHunkOrdinal, getSectionWalkthroughHunks, hunkDisplayEnd, hunkDisplayStart, isGeneratedWalkthroughFile, isGeneratedWalkthroughPath, isSyntheticWalkthroughHunk, parseHunkHeader, sumHunkLineCounts };
@@ -64,7 +64,7 @@ export type WalkthroughHunkRun = {
64
64
  };
65
65
  /** Resolve one normalized hunk to its exact live `ChangedFile` and `DiffSection`. */
66
66
  export declare const resolveWalkthroughHunkFile: (hunk: WalkthroughHunk, files: ReadonlyArray<ChangedFile>) => ResolvedWalkthroughHunkFile | null;
67
- /** Resolve item hunks in authored order, coalescing adjacent hunks from the same file section. */
67
+ /** Resolve authored hunk order, coalescing only forward runs within each file section. */
68
68
  export declare const resolveWalkthroughHunkRuns: (item: WalkthroughHunkGroup, files: ReadonlyArray<ChangedFile>) => ReadonlyArray<WalkthroughHunkRun>;
69
69
  export declare const getWalkthroughRunNote: (item: WalkthroughHunkGroup, run: WalkthroughHunkRun) => string | undefined;
70
70
  /**