git-chopstick-core 0.1.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.
Files changed (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -0
  3. package/examples/get-status.ts +84 -0
  4. package/package.json +20 -0
  5. package/src/git/add.ts +16 -0
  6. package/src/git/apply.ts +154 -0
  7. package/src/git/authentication.ts +19 -0
  8. package/src/git/branch.ts +206 -0
  9. package/src/git/checkout-index.ts +40 -0
  10. package/src/git/checkout.ts +235 -0
  11. package/src/git/cherry-pick.ts +504 -0
  12. package/src/git/clean.ts +9 -0
  13. package/src/git/clone.ts +86 -0
  14. package/src/git/coerce-to-buffer.ts +4 -0
  15. package/src/git/coerce-to-string.ts +4 -0
  16. package/src/git/commit.ts +136 -0
  17. package/src/git/config.ts +392 -0
  18. package/src/git/core.ts +625 -0
  19. package/src/git/create-tail-stream.ts +36 -0
  20. package/src/git/credential.ts +83 -0
  21. package/src/git/description.ts +33 -0
  22. package/src/git/diff-check.ts +27 -0
  23. package/src/git/diff-index.ts +116 -0
  24. package/src/git/diff.ts +880 -0
  25. package/src/git/environment.ts +116 -0
  26. package/src/git/exec.ts +285 -0
  27. package/src/git/fetch.ts +141 -0
  28. package/src/git/for-each-ref.ts +160 -0
  29. package/src/git/format-patch.ts +17 -0
  30. package/src/git/git-delimiter-parser.ts +95 -0
  31. package/src/git/gitignore.ts +157 -0
  32. package/src/git/index.ts +36 -0
  33. package/src/git/init.ts +11 -0
  34. package/src/git/interpret-trailers.ts +176 -0
  35. package/src/git/lfs.ts +100 -0
  36. package/src/git/log.ts +376 -0
  37. package/src/git/merge-tree.ts +42 -0
  38. package/src/git/merge.ts +154 -0
  39. package/src/git/multi-operation-terminal-output.ts +68 -0
  40. package/src/git/pull.ts +130 -0
  41. package/src/git/push-terminal-chunk.ts +41 -0
  42. package/src/git/push.ts +119 -0
  43. package/src/git/rebase.ts +627 -0
  44. package/src/git/reflog.ts +127 -0
  45. package/src/git/refs.ts +63 -0
  46. package/src/git/remote.ts +143 -0
  47. package/src/git/reorder.ts +153 -0
  48. package/src/git/reset.ts +101 -0
  49. package/src/git/rev-list.ts +201 -0
  50. package/src/git/rev-parse.ts +92 -0
  51. package/src/git/revert.ts +55 -0
  52. package/src/git/rm.ts +31 -0
  53. package/src/git/show.ts +88 -0
  54. package/src/git/spawn.ts +38 -0
  55. package/src/git/squash.ts +173 -0
  56. package/src/git/stage.ts +97 -0
  57. package/src/git/stash.ts +302 -0
  58. package/src/git/status.ts +502 -0
  59. package/src/git/submodule.ts +212 -0
  60. package/src/git/tag.ts +134 -0
  61. package/src/git/update-index.ts +169 -0
  62. package/src/git/update-ref.ts +50 -0
  63. package/src/git/var.ts +42 -0
  64. package/src/git/worktree-include.ts +146 -0
  65. package/src/git/worktree.ts +219 -0
  66. package/src/lib/api.ts +7 -0
  67. package/src/lib/diff-parser.ts +249 -0
  68. package/src/lib/directory-exists.ts +10 -0
  69. package/src/lib/errno-exception.ts +12 -0
  70. package/src/lib/fatal-error.ts +23 -0
  71. package/src/lib/feature-flag.ts +29 -0
  72. package/src/lib/file-system.ts +7 -0
  73. package/src/lib/get-old-path.ts +11 -0
  74. package/src/lib/git/environment.ts +14 -0
  75. package/src/lib/git-perf.ts +3 -0
  76. package/src/lib/helpers/default-branch.ts +3 -0
  77. package/src/lib/helpers/path.ts +5 -0
  78. package/src/lib/hooks/with-hooks-env.ts +7 -0
  79. package/src/lib/merge.ts +3 -0
  80. package/src/lib/noop.ts +1 -0
  81. package/src/lib/patch-formatter.ts +18 -0
  82. package/src/lib/path-exists.ts +7 -0
  83. package/src/lib/progress/from-process.ts +10 -0
  84. package/src/lib/progress/index.ts +43 -0
  85. package/src/lib/progress/revert.ts +17 -0
  86. package/src/lib/rebase.ts +3 -0
  87. package/src/lib/remove-remote-prefix.ts +4 -0
  88. package/src/lib/resolve-git-proxy.ts +3 -0
  89. package/src/lib/round.ts +4 -0
  90. package/src/lib/split-buffer.ts +14 -0
  91. package/src/lib/status-parser.ts +188 -0
  92. package/src/lib/stores/helpers/find-default-remote.ts +3 -0
  93. package/src/lib/trampoline/trampoline-environment.ts +8 -0
  94. package/src/models/branch.ts +78 -0
  95. package/src/models/cherry-pick.ts +12 -0
  96. package/src/models/clone-options.ts +6 -0
  97. package/src/models/commit-identity.ts +35 -0
  98. package/src/models/commit.ts +44 -0
  99. package/src/models/computed-action.ts +6 -0
  100. package/src/models/diff/diff-data.ts +78 -0
  101. package/src/models/diff/diff-line.ts +36 -0
  102. package/src/models/diff/diff-selection.ts +165 -0
  103. package/src/models/diff/image-diff.ts +6 -0
  104. package/src/models/diff/image.ts +8 -0
  105. package/src/models/diff/index.ts +6 -0
  106. package/src/models/diff/raw-diff.ts +41 -0
  107. package/src/models/git-author.ts +16 -0
  108. package/src/models/manual-conflict-resolution.ts +4 -0
  109. package/src/models/merge.ts +6 -0
  110. package/src/models/multi-commit-operation.ts +6 -0
  111. package/src/models/progress.ts +67 -0
  112. package/src/models/rebase.ts +20 -0
  113. package/src/models/remote.ts +10 -0
  114. package/src/models/repository.ts +16 -0
  115. package/src/models/stash-entry.ts +25 -0
  116. package/src/models/status.ts +275 -0
  117. package/src/models/submodule.ts +13 -0
  118. package/src/models/worktree.ts +11 -0
  119. package/tsconfig.json +17 -0
@@ -0,0 +1,165 @@
1
+ export enum DiffSelectionType {
2
+ All = 'All',
3
+ Partial = 'Partial',
4
+ None = 'None',
5
+ }
6
+
7
+ function typeMatchesSelection(
8
+ selectionType: DiffSelectionType,
9
+ selected: boolean
10
+ ): boolean {
11
+ switch (selectionType) {
12
+ case DiffSelectionType.All:
13
+ return selected
14
+ case DiffSelectionType.None:
15
+ return !selected
16
+ case DiffSelectionType.Partial:
17
+ return false
18
+ }
19
+ }
20
+
21
+ export class DiffSelection {
22
+ public static fromInitialSelection(
23
+ initialSelection: DiffSelectionType.All | DiffSelectionType.None
24
+ ): DiffSelection {
25
+ return new DiffSelection(initialSelection, null, null)
26
+ }
27
+
28
+ private constructor(
29
+ private readonly defaultSelectionType: DiffSelectionType.All | DiffSelectionType.None,
30
+ private readonly divergingLines: Set<number> | null = null,
31
+ private readonly selectableLines: Set<number> | null = null
32
+ ) {}
33
+
34
+ public getSelectionType(): DiffSelectionType {
35
+ const divergingLines = this.divergingLines
36
+ const selectableLines = this.selectableLines
37
+
38
+ if (!divergingLines || divergingLines.size === 0) {
39
+ return this.defaultSelectionType
40
+ }
41
+
42
+ if (selectableLines && selectableLines.size === divergingLines.size) {
43
+ const allSelectableLinesAreDivergent = [...selectableLines].every(i =>
44
+ divergingLines.has(i)
45
+ )
46
+ if (allSelectableLinesAreDivergent) {
47
+ return this.defaultSelectionType === DiffSelectionType.All
48
+ ? DiffSelectionType.None
49
+ : DiffSelectionType.All
50
+ }
51
+ }
52
+
53
+ return DiffSelectionType.Partial
54
+ }
55
+
56
+ public isSelected(lineIndex: number): boolean {
57
+ const lineIsDivergent =
58
+ !!this.divergingLines && this.divergingLines.has(lineIndex)
59
+
60
+ if (this.defaultSelectionType === DiffSelectionType.All) {
61
+ return !lineIsDivergent
62
+ }
63
+ return lineIsDivergent
64
+ }
65
+
66
+ public isRangeSelected(from: number, length: number): DiffSelectionType {
67
+ if (length <= 0) return DiffSelectionType.None
68
+
69
+ const computedSelectionType = this.getSelectionType()
70
+ if (computedSelectionType !== DiffSelectionType.Partial) {
71
+ return computedSelectionType
72
+ }
73
+
74
+ if (length === 1) {
75
+ return this.isSelected(from) ? DiffSelectionType.All : DiffSelectionType.None
76
+ }
77
+
78
+ const to = from + length
79
+ let foundSelected = false
80
+ let foundDeselected = false
81
+ for (let i = from; i < to; i++) {
82
+ if (this.isSelected(i)) foundSelected = true
83
+ if (!this.isSelected(i)) foundDeselected = true
84
+ if (foundSelected && foundDeselected) return DiffSelectionType.Partial
85
+ }
86
+
87
+ return foundSelected ? DiffSelectionType.All : DiffSelectionType.None
88
+ }
89
+
90
+ public isSelectable(lineIndex: number): boolean {
91
+ return this.selectableLines ? this.selectableLines.has(lineIndex) : true
92
+ }
93
+
94
+ public withLineSelection(lineIndex: number, selected: boolean): DiffSelection {
95
+ return this.withRangeSelection(lineIndex, 1, selected)
96
+ }
97
+
98
+ public withRangeSelection(from: number, length: number, selected: boolean): DiffSelection {
99
+ const computedSelectionType = this.getSelectionType()
100
+ const to = from + length
101
+
102
+ if (typeMatchesSelection(computedSelectionType, selected)) {
103
+ return this
104
+ }
105
+
106
+ if (computedSelectionType === DiffSelectionType.Partial) {
107
+ const newDivergingLines = new Set<number>(this.divergingLines!)
108
+
109
+ if (typeMatchesSelection(this.defaultSelectionType, selected)) {
110
+ for (let i = from; i < to; i++) {
111
+ newDivergingLines.delete(i)
112
+ }
113
+ } else {
114
+ for (let i = from; i < to; i++) {
115
+ if (this.isSelectable(i)) {
116
+ newDivergingLines.add(i)
117
+ }
118
+ }
119
+ }
120
+
121
+ return new DiffSelection(
122
+ this.defaultSelectionType,
123
+ newDivergingLines.size === 0 ? null : newDivergingLines,
124
+ this.selectableLines
125
+ )
126
+ }
127
+
128
+ const newDivergingLines = new Set<number>()
129
+ for (let i = from; i < to; i++) {
130
+ if (this.isSelectable(i)) {
131
+ newDivergingLines.add(i)
132
+ }
133
+ }
134
+
135
+ return new DiffSelection(
136
+ computedSelectionType,
137
+ newDivergingLines,
138
+ this.selectableLines
139
+ )
140
+ }
141
+
142
+ public withToggleLineSelection(lineIndex: number): DiffSelection {
143
+ return this.withLineSelection(lineIndex, !this.isSelected(lineIndex))
144
+ }
145
+
146
+ public withSelectAll(): DiffSelection {
147
+ return new DiffSelection(DiffSelectionType.All, null, this.selectableLines)
148
+ }
149
+
150
+ public withSelectNone(): DiffSelection {
151
+ return new DiffSelection(DiffSelectionType.None, null, this.selectableLines)
152
+ }
153
+
154
+ public withSelectableLines(selectableLines: Set<number>) {
155
+ const divergingLines = this.divergingLines
156
+ ? new Set([...this.divergingLines].filter(x => selectableLines.has(x)))
157
+ : null
158
+
159
+ return new DiffSelection(
160
+ this.defaultSelectionType,
161
+ divergingLines,
162
+ selectableLines
163
+ )
164
+ }
165
+ }
@@ -0,0 +1,6 @@
1
+ export enum ImageDiffType {
2
+ TwoUp,
3
+ Swipe,
4
+ OnionSkin,
5
+ Difference,
6
+ }
@@ -0,0 +1,8 @@
1
+ export class Image {
2
+ public constructor(
3
+ public readonly rawContents: ArrayBufferLike,
4
+ public readonly contents: string,
5
+ public readonly mediaType: string,
6
+ public readonly bytes: number
7
+ ) {}
8
+ }
@@ -0,0 +1,6 @@
1
+ export * from './diff-data'
2
+ export * from './diff-line'
3
+ export * from './diff-selection'
4
+ export * from './image'
5
+ export * from './raw-diff'
6
+ export * from './image-diff'
@@ -0,0 +1,41 @@
1
+ import { DiffLine } from './diff-line'
2
+
3
+ export enum DiffHunkExpansionType {
4
+ None = 'None',
5
+ Up = 'Up',
6
+ Down = 'Down',
7
+ Both = 'Both',
8
+ Short = 'Short',
9
+ }
10
+
11
+ export class DiffHunk {
12
+ public constructor(
13
+ public readonly header: DiffHunkHeader,
14
+ public readonly lines: ReadonlyArray<DiffLine>,
15
+ public readonly unifiedDiffStart: number,
16
+ public readonly unifiedDiffEnd: number,
17
+ public readonly expansionType: DiffHunkExpansionType
18
+ ) {}
19
+ }
20
+
21
+ export class DiffHunkHeader {
22
+ public constructor(
23
+ public readonly oldStartLine: number,
24
+ public readonly oldLineCount: number,
25
+ public readonly newStartLine: number,
26
+ public readonly newLineCount: number
27
+ ) {}
28
+
29
+ public toDiffLineRepresentation() {
30
+ return `@@ -${this.oldStartLine},${this.oldLineCount} +${this.newStartLine},${this.newLineCount} @@`
31
+ }
32
+ }
33
+
34
+ export interface IRawDiff {
35
+ readonly header: string
36
+ readonly contents: string
37
+ readonly hunks: ReadonlyArray<DiffHunk>
38
+ readonly isBinary: boolean
39
+ readonly maxLineNumber: number
40
+ readonly hasHiddenBidiChars: boolean
41
+ }
@@ -0,0 +1,16 @@
1
+ export class GitAuthor {
2
+ public static parse(value: string): GitAuthor | null {
3
+ const m = value.match(/^(.*?)\s*<(.+?)>\s*$/)
4
+ if (!m) return null
5
+ return new GitAuthor(m[1], m[2])
6
+ }
7
+
8
+ public constructor(
9
+ public readonly name: string,
10
+ public readonly email: string
11
+ ) {}
12
+
13
+ public toString(): string {
14
+ return `${this.name} <${this.email}>`
15
+ }
16
+ }
@@ -0,0 +1,4 @@
1
+ export enum ManualConflictResolution {
2
+ theirs = 'theirs',
3
+ ours = 'ours',
4
+ }
@@ -0,0 +1,6 @@
1
+ export type MergeTreeResult = {
2
+ readonly sha: string
3
+ readonly tree: string
4
+ readonly conflicted: boolean
5
+ readonly mergeBase: string
6
+ }
@@ -0,0 +1,6 @@
1
+ export enum MultiCommitOperationKind {
2
+ Squash = 'Squash',
3
+ Reorder = 'Reorder',
4
+ CherryPick = 'CherryPick',
5
+ Amend = 'Amend',
6
+ }
@@ -0,0 +1,67 @@
1
+ interface IProgress {
2
+ readonly value: number
3
+ readonly title?: string
4
+ readonly description?: string
5
+ }
6
+
7
+ export interface IGenericProgress extends IProgress {
8
+ kind: 'generic'
9
+ }
10
+
11
+ export interface ICheckoutProgress extends IProgress {
12
+ kind: 'checkout'
13
+ readonly target: string
14
+ readonly description: string
15
+ }
16
+
17
+ export interface IFetchProgress extends IProgress {
18
+ kind: 'fetch'
19
+ readonly remote: string
20
+ }
21
+
22
+ export interface IPullProgress extends IProgress {
23
+ kind: 'pull'
24
+ readonly remote: string
25
+ }
26
+
27
+ export interface IPushProgress extends IProgress {
28
+ kind: 'push'
29
+ readonly remote: string
30
+ readonly branch: string
31
+ }
32
+
33
+ export interface ICloneProgress extends IProgress {
34
+ kind: 'clone'
35
+ }
36
+
37
+ export interface IRevertProgress extends IProgress {
38
+ kind: 'revert'
39
+ }
40
+
41
+ export interface IMultiCommitOperationProgress extends IProgress {
42
+ readonly kind: 'multiCommitOperation'
43
+ readonly currentCommitSummary: string
44
+ readonly position: number
45
+ readonly totalCommitCount: number
46
+ }
47
+
48
+ export type Progress =
49
+ | IGenericProgress
50
+ | ICheckoutProgress
51
+ | IFetchProgress
52
+ | IPullProgress
53
+ | IPushProgress
54
+ | IRevertProgress
55
+ | IMultiCommitOperationProgress
56
+
57
+ export function clampProgress<T extends Progress>(
58
+ minimum: number,
59
+ maximum: number,
60
+ progressCallback: (progress: T) => void
61
+ ): (progress: T) => void {
62
+ return (progress: T) =>
63
+ progressCallback({
64
+ ...progress,
65
+ value: minimum + progress.value * (maximum - minimum),
66
+ })
67
+ }
@@ -0,0 +1,20 @@
1
+ import { IMultiCommitOperationProgress } from './progress'
2
+ import { CommitOneLine } from './commit'
3
+
4
+ export type RebaseInternalState = {
5
+ readonly targetBranch: string
6
+ readonly baseBranchTip: string
7
+ readonly originalBranchTip: string
8
+ }
9
+
10
+ export type RebaseProgressOptions = {
11
+ commits: ReadonlyArray<CommitOneLine>
12
+ progressCallback: (progress: IMultiCommitOperationProgress) => void
13
+ }
14
+
15
+ export enum ComputedAction {
16
+ Clean = 'Clean',
17
+ Conflicts = 'Conflicts',
18
+ Invalid = 'Invalid',
19
+ Loading = 'Loading',
20
+ }
@@ -0,0 +1,10 @@
1
+ export interface IRemote {
2
+ readonly name: string
3
+ readonly url: string
4
+ }
5
+
6
+ export function remoteEquals(x: IRemote | null, y: IRemote | null) {
7
+ if (x === y) return true
8
+ if (x === null || y === null) return false
9
+ return x.name === y.name && x.url === y.url
10
+ }
@@ -0,0 +1,16 @@
1
+ import * as Path from 'path'
2
+
3
+ export class Repository {
4
+ public readonly name: string
5
+
6
+ public constructor(
7
+ public readonly path: string,
8
+ public readonly id: number
9
+ ) {
10
+ this.name = Path.basename(path)
11
+ }
12
+
13
+ public get resolvedGitDir(): string {
14
+ return Path.join(this.path, '.git')
15
+ }
16
+ }
@@ -0,0 +1,25 @@
1
+ import { CommittedFileChange } from './status'
2
+
3
+ export interface IStashEntry {
4
+ readonly name: string
5
+ readonly branchName: string
6
+ readonly stashSha: string
7
+ readonly files: StashedFileChanges
8
+ readonly tree: string
9
+ readonly parents: ReadonlyArray<string>
10
+ }
11
+
12
+ export enum StashedChangesLoadStates {
13
+ NotLoaded = 'NotLoaded',
14
+ Loading = 'Loading',
15
+ Loaded = 'Loaded',
16
+ }
17
+
18
+ export type StashedFileChanges =
19
+ | {
20
+ readonly kind: StashedChangesLoadStates.NotLoaded | StashedChangesLoadStates.Loading
21
+ }
22
+ | {
23
+ readonly kind: StashedChangesLoadStates.Loaded
24
+ readonly files: ReadonlyArray<CommittedFileChange>
25
+ }
@@ -0,0 +1,275 @@
1
+ import { DiffSelection, DiffSelectionType } from './diff'
2
+
3
+ export enum GitStatusEntry {
4
+ Modified = 'M',
5
+ Added = 'A',
6
+ Deleted = 'D',
7
+ Renamed = 'R',
8
+ Copied = 'C',
9
+ Unchanged = '.',
10
+ Untracked = '?',
11
+ Ignored = '!',
12
+ UpdatedButUnmerged = 'U',
13
+ }
14
+
15
+ export enum AppFileStatusKind {
16
+ New = 'New',
17
+ Modified = 'Modified',
18
+ Deleted = 'Deleted',
19
+ Copied = 'Copied',
20
+ Renamed = 'Renamed',
21
+ Conflicted = 'Conflicted',
22
+ Untracked = 'Untracked',
23
+ }
24
+
25
+ export type PlainFileStatus = {
26
+ kind: AppFileStatusKind.New | AppFileStatusKind.Modified | AppFileStatusKind.Deleted
27
+ submoduleStatus?: SubmoduleStatus
28
+ }
29
+
30
+ export type CopiedOrRenamedFileStatus = {
31
+ kind: AppFileStatusKind.Copied | AppFileStatusKind.Renamed
32
+ oldPath: string
33
+ renameIncludesModifications: boolean
34
+ submoduleStatus?: SubmoduleStatus
35
+ }
36
+
37
+ export type ConflictsWithMarkers = {
38
+ kind: AppFileStatusKind.Conflicted
39
+ entry: TextConflictEntry
40
+ conflictMarkerCount: number
41
+ submoduleStatus?: SubmoduleStatus
42
+ }
43
+
44
+ export type ManualConflict = {
45
+ kind: AppFileStatusKind.Conflicted
46
+ entry: ManualConflictEntry
47
+ submoduleStatus?: SubmoduleStatus
48
+ }
49
+
50
+ export type ConflictedFileStatus = ConflictsWithMarkers | ManualConflict
51
+
52
+ export function isConflictedFileStatus(
53
+ appFileStatus: AppFileStatus
54
+ ): appFileStatus is ConflictedFileStatus {
55
+ return appFileStatus.kind === AppFileStatusKind.Conflicted
56
+ }
57
+
58
+ export function isConflictWithMarkers(
59
+ conflictedFileStatus: ConflictedFileStatus
60
+ ): conflictedFileStatus is ConflictsWithMarkers {
61
+ return 'conflictMarkerCount' in conflictedFileStatus
62
+ }
63
+
64
+ export type UntrackedFileStatus = {
65
+ kind: AppFileStatusKind.Untracked
66
+ submoduleStatus?: SubmoduleStatus
67
+ }
68
+
69
+ export type AppFileStatus =
70
+ | PlainFileStatus
71
+ | CopiedOrRenamedFileStatus
72
+ | ConflictedFileStatus
73
+ | UntrackedFileStatus
74
+
75
+ export type SubmoduleStatus = {
76
+ readonly commitChanged: boolean
77
+ readonly modifiedChanges: boolean
78
+ readonly untrackedChanges: boolean
79
+ }
80
+
81
+ type OrdinaryEntry = {
82
+ readonly kind: 'ordinary'
83
+ readonly type: 'added' | 'modified' | 'deleted'
84
+ readonly index?: GitStatusEntry
85
+ readonly workingTree?: GitStatusEntry
86
+ readonly submoduleStatus?: SubmoduleStatus
87
+ }
88
+
89
+ type RenamedOrCopiedEntry = {
90
+ readonly kind: 'renamed' | 'copied'
91
+ readonly index?: GitStatusEntry
92
+ readonly workingTree?: GitStatusEntry
93
+ readonly submoduleStatus?: SubmoduleStatus
94
+ readonly renameOrCopyScore?: number
95
+ }
96
+
97
+ export enum UnmergedEntrySummary {
98
+ AddedByUs = 'added-by-us',
99
+ DeletedByUs = 'deleted-by-us',
100
+ AddedByThem = 'added-by-them',
101
+ DeletedByThem = 'deleted-by-them',
102
+ BothDeleted = 'both-deleted',
103
+ BothAdded = 'both-added',
104
+ BothModified = 'both-modified',
105
+ }
106
+
107
+ type TextConflictDetails =
108
+ | {
109
+ readonly action: UnmergedEntrySummary.BothAdded
110
+ readonly us: GitStatusEntry.Added
111
+ readonly them: GitStatusEntry.Added
112
+ }
113
+ | {
114
+ readonly action: UnmergedEntrySummary.BothModified
115
+ readonly us: GitStatusEntry.UpdatedButUnmerged
116
+ readonly them: GitStatusEntry.UpdatedButUnmerged
117
+ }
118
+
119
+ type TextConflictEntry = {
120
+ readonly kind: 'conflicted'
121
+ readonly submoduleStatus?: SubmoduleStatus
122
+ } & TextConflictDetails
123
+
124
+ type ManualConflictDetails = {
125
+ readonly submoduleStatus?: SubmoduleStatus
126
+ } & (
127
+ | { readonly action: UnmergedEntrySummary.BothAdded; readonly us: GitStatusEntry.Added; readonly them: GitStatusEntry.Added }
128
+ | { readonly action: UnmergedEntrySummary.BothModified; readonly us: GitStatusEntry.UpdatedButUnmerged; readonly them: GitStatusEntry.UpdatedButUnmerged }
129
+ | { readonly action: UnmergedEntrySummary.AddedByUs; readonly us: GitStatusEntry.Added; readonly them: GitStatusEntry.UpdatedButUnmerged }
130
+ | { readonly action: UnmergedEntrySummary.DeletedByThem; readonly us: GitStatusEntry.UpdatedButUnmerged; readonly them: GitStatusEntry.Deleted }
131
+ | { readonly action: UnmergedEntrySummary.AddedByThem; readonly us: GitStatusEntry.UpdatedButUnmerged; readonly them: GitStatusEntry.Added }
132
+ | { readonly action: UnmergedEntrySummary.DeletedByUs; readonly us: GitStatusEntry.Deleted; readonly them: GitStatusEntry.UpdatedButUnmerged }
133
+ | { readonly action: UnmergedEntrySummary.BothDeleted; readonly us: GitStatusEntry.Deleted; readonly them: GitStatusEntry.Deleted }
134
+ )
135
+
136
+ type ManualConflictEntry = {
137
+ readonly kind: 'conflicted'
138
+ readonly submoduleStatus?: SubmoduleStatus
139
+ } & ManualConflictDetails
140
+
141
+ export type UnmergedEntry = TextConflictEntry | ManualConflictEntry
142
+
143
+ type UntrackedEntry = {
144
+ readonly kind: 'untracked'
145
+ readonly submoduleStatus?: SubmoduleStatus
146
+ }
147
+
148
+ export type FileEntry =
149
+ | OrdinaryEntry
150
+ | RenamedOrCopiedEntry
151
+ | UnmergedEntry
152
+ | UntrackedEntry
153
+
154
+ export class FileChange {
155
+ public readonly id: string
156
+
157
+ public constructor(
158
+ public readonly path: string,
159
+ public readonly status: AppFileStatus
160
+ ) {
161
+ if (
162
+ status.kind === AppFileStatusKind.Renamed ||
163
+ status.kind === AppFileStatusKind.Copied
164
+ ) {
165
+ this.id = `${status.kind}+${path}+${status.oldPath}`
166
+ } else {
167
+ this.id = `${status.kind}+${path}`
168
+ }
169
+ }
170
+
171
+ public isDeleted(): boolean {
172
+ return this.status.kind === AppFileStatusKind.Deleted
173
+ }
174
+
175
+ public isNew(): boolean {
176
+ return this.status.kind === AppFileStatusKind.New
177
+ }
178
+
179
+ public isModified(): boolean {
180
+ return this.status.kind === AppFileStatusKind.Modified
181
+ }
182
+
183
+ public isUntracked(): boolean {
184
+ return this.status.kind === AppFileStatusKind.Untracked
185
+ }
186
+ }
187
+
188
+ export class WorkingDirectoryFileChange extends FileChange {
189
+ public constructor(
190
+ path: string,
191
+ status: AppFileStatus,
192
+ public readonly selection: DiffSelection
193
+ ) {
194
+ super(path, status)
195
+ }
196
+
197
+ public withIncludeAll(include: boolean): WorkingDirectoryFileChange {
198
+ const newSelection = include
199
+ ? this.selection.withSelectAll()
200
+ : this.selection.withSelectNone()
201
+ return this.withSelection(newSelection)
202
+ }
203
+
204
+ public withSelection(selection: DiffSelection): WorkingDirectoryFileChange {
205
+ return new WorkingDirectoryFileChange(this.path, this.status, selection)
206
+ }
207
+
208
+ public isIncludedInCommit(): boolean {
209
+ return this.selection.getSelectionType() === DiffSelectionType.All
210
+ }
211
+
212
+ public isExcludedFromCommit(): boolean {
213
+ return this.selection.getSelectionType() === DiffSelectionType.None
214
+ }
215
+ }
216
+
217
+ export class CommittedFileChange extends FileChange {
218
+ public constructor(
219
+ path: string,
220
+ status: AppFileStatus,
221
+ public readonly commitish: string,
222
+ public readonly parentCommitish: string
223
+ ) {
224
+ super(path, status)
225
+ }
226
+ }
227
+
228
+ export class WorkingDirectoryStatus {
229
+ public static fromFiles(
230
+ files: ReadonlyArray<WorkingDirectoryFileChange>
231
+ ): WorkingDirectoryStatus {
232
+ return new WorkingDirectoryStatus(files, getIncludeAllState(files))
233
+ }
234
+
235
+ private readonly fileIxById = new Map<string, number>()
236
+
237
+ private constructor(
238
+ public readonly files: ReadonlyArray<WorkingDirectoryFileChange>,
239
+ public readonly includeAll: boolean | null = true
240
+ ) {
241
+ files.forEach((f, ix) => this.fileIxById.set(f.id, ix))
242
+ }
243
+
244
+ public withIncludeAllFiles(includeAll: boolean): WorkingDirectoryStatus {
245
+ const newFiles = this.files.map(f => f.withIncludeAll(includeAll))
246
+ return new WorkingDirectoryStatus(newFiles, includeAll)
247
+ }
248
+
249
+ public findFileWithID(id: string): WorkingDirectoryFileChange | null {
250
+ const ix = this.fileIxById.get(id)
251
+ return ix !== undefined ? this.files[ix] || null : null
252
+ }
253
+
254
+ public findFileIndexByID(id: string): number {
255
+ const ix = this.fileIxById.get(id)
256
+ return ix !== undefined ? ix : -1
257
+ }
258
+ }
259
+
260
+ function getIncludeAllState(
261
+ files: ReadonlyArray<WorkingDirectoryFileChange>
262
+ ): boolean | null {
263
+ if (!files.length) return true
264
+
265
+ const allSelected = files.every(
266
+ f => f.selection.getSelectionType() === DiffSelectionType.All
267
+ )
268
+ const noneSelected = files.every(
269
+ f => f.selection.getSelectionType() === DiffSelectionType.None
270
+ )
271
+
272
+ if (allSelected) return true
273
+ if (noneSelected) return false
274
+ return null
275
+ }
@@ -0,0 +1,13 @@
1
+ export type SubmoduleEntry = {
2
+ readonly path: string
3
+ readonly url: string
4
+ readonly describe?: string
5
+ readonly sha: string
6
+ readonly status: SubmoduleStatus
7
+ }
8
+
9
+ export type SubmoduleStatus = {
10
+ readonly commitChanged: boolean
11
+ readonly modifiedChanges: boolean
12
+ readonly untrackedChanges: boolean
13
+ }