1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
import { commitActionForFile } from '~/ide/stores/utils';
import { commitActionTypes } from '~/ide/constants';
import createFileDiff from './create_file_diff';
const getDeletedParents = (entries, file) => {
const parent = file.parentPath && entries[file.parentPath];
if (parent && parent.deleted) {
return [parent, ...getDeletedParents(entries, parent)];
}
return [];
};
const filesWithChanges = ({ stagedFiles = [], changedFiles = [], entries = {} }) => {
// We need changed files to overwrite staged, so put them at the end.
const changes = stagedFiles.concat(changedFiles).reduce((acc, file) => {
const key = file.path;
const action = commitActionForFile(file);
const prev = acc[key];
// If a file was deleted, which was previously added, then we should do nothing.
if (action === commitActionTypes.delete && prev && prev.action === commitActionTypes.create) {
delete acc[key];
} else {
acc[key] = { action, file };
}
return acc;
}, {});
// We need to clean "move" actions, because we can only support 100% similarity moves at the moment.
// This is because the previous file's content might not be loaded.
Object.values(changes)
.filter(change => change.action === commitActionTypes.move)
.forEach(change => {
const prev = changes[change.file.prevPath];
if (!prev) {
return;
}
if (change.file.content === prev.file.content) {
// If content is the same, continue with the move but don't do the prevPath's delete.
delete changes[change.file.prevPath];
} else {
// Otherwise, treat the move as a delete / create.
Object.assign(change, { action: commitActionTypes.create });
}
});
// Next, we need to add deleted directories by looking at the parents
Object.values(changes)
.filter(change => change.action === commitActionTypes.delete && change.file.parentPath)
.forEach(({ file }) => {
// Do nothing if we've already visited this directory.
if (changes[file.parentPath]) {
return;
}
getDeletedParents(entries, file).forEach(parent => {
changes[parent.path] = { action: commitActionTypes.delete, file: parent };
});
});
return Object.values(changes);
};
const createDiff = state => {
const changes = filesWithChanges(state);
const toDelete = changes.filter(x => x.action === commitActionTypes.delete).map(x => x.file.path);
const patch = changes
.filter(x => x.action !== commitActionTypes.delete)
.map(({ file, action }) => createFileDiff(file, action))
.join('');
return {
patch,
toDelete,
};
};
export default createDiff;
|