addons/isl/src/UncommittedChangesUtils.tsblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import type {Set as ImSet} from 'immutable';
b69ab319import type {ChangedFile, ChangedFileStatus, RepoRelativePath} from './types';
b69ab3110import type {UIChangedFile, VisualChangedFileStatus} from './UncommittedChanges';
b69ab3111
b69ab3112import {minimalDisambiguousPaths} from 'shared/minimalDisambiguousPaths';
b69ab3113import {notEmpty} from 'shared/utils';
b69ab3114import {t} from './i18n';
b69ab3115import {ChangedFileMode} from './types';
b69ab3116
b69ab3117export function processChangedFiles(
b69ab3118 files: Array<ChangedFile>,
b69ab3119 submodulePaths: ImSet<RepoRelativePath> | undefined,
b69ab3120): Array<UIChangedFile> {
b69ab3121 const disambiguousPaths = minimalDisambiguousPaths(files.map(file => file.path));
b69ab3122 const copySources = new Set(files.map(file => file.copy).filter(notEmpty));
b69ab3123 const removedFiles = new Set(files.filter(file => file.status === 'R').map(file => file.path));
b69ab3124
b69ab3125 return (
b69ab3126 files
b69ab3127 .map((file, i) => {
b69ab3128 const minimalName = disambiguousPaths[i];
b69ab3129 const mode =
b69ab3130 submodulePaths && submodulePaths.has(file.path)
b69ab3131 ? ChangedFileMode.Submodule
b69ab3132 : ChangedFileMode.Regular;
b69ab3133 let fileLabel = minimalName;
b69ab3134 let tooltip = `${nameForStatus(file.status)}: ${file.path}`;
b69ab3135 let copiedFrom;
b69ab3136 let renamedFrom;
b69ab3137 let visualStatus: VisualChangedFileStatus = file.status;
b69ab3138 if (file.copy != null) {
b69ab3139 // Disambiguate between original file and the newly copy's name,
b69ab3140 // instead of disambiguating among all file names.
b69ab3141 const [originalName, copiedName] = minimalDisambiguousPaths([file.copy, file.path]);
b69ab3142 fileLabel = `${originalName} → ${copiedName}`;
b69ab3143 if (removedFiles.has(file.copy)) {
b69ab3144 renamedFrom = file.copy;
b69ab3145 tooltip = t('$newPath\n\nThis file was renamed from $originalPath', {
b69ab3146 replace: {$newPath: file.path, $originalPath: file.copy},
b69ab3147 });
b69ab3148 visualStatus = 'Renamed';
b69ab3149 } else {
b69ab3150 copiedFrom = file.copy;
b69ab3151 tooltip = t('$newPath\n\nThis file was copied from $originalPath', {
b69ab3152 replace: {$newPath: file.path, $originalPath: file.copy},
b69ab3153 });
b69ab3154 visualStatus = 'Copied';
b69ab3155 }
b69ab3156 }
b69ab3157
b69ab3158 return {
b69ab3159 path: file.path,
b69ab3160 label: fileLabel,
b69ab3161 status: file.status,
b69ab3162 mode,
b69ab3163 visualStatus,
b69ab3164 copiedFrom,
b69ab3165 renamedFrom,
b69ab3166 tooltip,
b69ab3167 };
b69ab3168 })
b69ab3169 // Hide files that were renamed. This comes after the map since we need to use the index to refer to minimalDisambiguousPaths
b69ab3170 .filter(file => !(file.status === 'R' && copySources.has(file.path)))
b69ab3171 .sort((a, b) =>
b69ab3172 a.visualStatus === b.visualStatus
b69ab3173 ? a.path.localeCompare(b.path)
b69ab3174 : sortKeyForStatus[a.visualStatus] - sortKeyForStatus[b.visualStatus],
b69ab3175 )
b69ab3176 );
b69ab3177}
b69ab3178
b69ab3179const sortKeyForStatus: Record<VisualChangedFileStatus, number> = {
b69ab3180 M: 0,
b69ab3181 Renamed: 1,
b69ab3182 A: 2,
b69ab3183 Copied: 3,
b69ab3184 R: 4,
b69ab3185 '!': 5,
b69ab3186 '?': 6,
b69ab3187 U: 7,
b69ab3188 Resolved: 8,
b69ab3189};
b69ab3190
b69ab3191function nameForStatus(status: ChangedFileStatus): string {
b69ab3192 switch (status) {
b69ab3193 case '!':
b69ab3194 return t('Missing');
b69ab3195 case '?':
b69ab3196 return t('Untracked');
b69ab3197 case 'A':
b69ab3198 return t('Added');
b69ab3199 case 'M':
b69ab31100 return t('Modified');
b69ab31101 case 'R':
b69ab31102 return t('Removed');
b69ab31103 case 'U':
b69ab31104 return t('Unresolved');
b69ab31105 case 'Resolved':
b69ab31106 return t('Resolved');
b69ab31107 }
b69ab31108}