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;