addons/isl/src/stackEdit/stackDag.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 {CommitStackState} from './commitStackState';
b69ab319
b69ab3110import {cached} from 'shared/LRU';
b69ab3111import {firstLine, nullthrows} from 'shared/utils';
b69ab3112import {Dag, DagCommitInfo} from '../dag/dag';
b69ab3113import {WDIR_NODE, YOU_ARE_HERE_VIRTUAL_COMMIT} from '../dag/virtualCommit';
b69ab3114
b69ab3115/**
b69ab3116 * Calculate a virtual "Dag" purely from "stack".
b69ab3117 * The virtual "Dag" does not have to be a subset of the main dag being displayed.
b69ab3118 * This avoids race conditions and various issues when the "stack" does not
b69ab3119 * match the main dag.
b69ab3120 * The nodes (commit hashes) of the returned dag is the "key" of commits in
b69ab3121 * the "stack", not real commit hashes. This is to support various stack edit
b69ab3122 * operations like splitting, inserting new commits, etc.
b69ab3123 */
b69ab3124function calculateDagFromStackImpl(stack: CommitStackState): Dag {
b69ab3125 let dag = new Dag();
b69ab3126
b69ab3127 // Figure out the "dot" from the initial exported stack.
b69ab3128 // "dot" is the parent of "wdir()".
b69ab3129 // The exported stack might not have "wdir()" if not requested.
b69ab3130 // Run `sl debugexportstack -r '.+wdir()' | python3 -m json.tool` to get a sense of the output.
b69ab3131 let dotNode: string | undefined = undefined;
b69ab3132 let dotKey: string | undefined = undefined;
b69ab3133 for (const exportedCommit of stack.originalStack) {
b69ab3134 if (exportedCommit.node === WDIR_NODE) {
b69ab3135 dotNode = exportedCommit.parents?.at(0);
b69ab3136 break;
b69ab3137 }
b69ab3138 }
b69ab3139
b69ab3140 if (dotNode != null) {
b69ab3141 const maybeDotCommit = stack.stack.findLast(commit => commit.originalNodes.contains(dotNode));
b69ab3142 if (maybeDotCommit != null) {
b69ab3143 dotKey = maybeDotCommit.key;
b69ab3144 const wdirRev = stack.findLastRev(commit => commit.originalNodes.contains(WDIR_NODE));
b69ab3145 dag = dag.add([YOU_ARE_HERE_VIRTUAL_COMMIT.merge({parents: [dotKey], stackRev: wdirRev})]);
b69ab3146 }
b69ab3147 }
b69ab3148
b69ab3149 // Insert commits from the stack.
b69ab3150 // Since we've already inserted the "wdir()" commit, skip it from the stack.
b69ab3151 dag = dag.add(
b69ab3152 stack
b69ab3153 .revs()
b69ab3154 .filter(rev => !stack.get(rev)?.originalNodes?.contains(WDIR_NODE))
b69ab3155 .map(rev => {
b69ab3156 const commit = nullthrows(stack.get(rev));
b69ab3157 return DagCommitInfo.fromCommitInfo({
b69ab3158 title: firstLine(commit.text),
b69ab3159 hash: commit.key,
b69ab3160 parents: commit.parents
b69ab3161 .flatMap(parentRev => {
b69ab3162 const parent = stack.get(parentRev);
b69ab3163 return parent == null ? [] : [parent.key];
b69ab3164 })
b69ab3165 .toArray(),
b69ab3166 phase: commit.immutableKind === 'hash' ? 'public' : 'draft',
b69ab3167 author: commit.author,
b69ab3168 date: new Date(commit.date.unix),
b69ab3169 isDot: commit.key === dotKey,
b69ab3170 stackRev: rev,
b69ab3171 // Other fields are omitted for now, since nobody uses them yet.
b69ab3172 });
b69ab3173 }),
b69ab3174 );
b69ab3175
b69ab3176 return dag;
b69ab3177}
b69ab3178
b69ab3179/**
b69ab3180 * Provides a `Dag` that just contains the `stack`.
b69ab3181 * If `dotRev` is set, add a "YouAreHere" virtual commit as a child of the rev.
b69ab3182 */
b69ab3183export const calculateDagFromStack = cached(calculateDagFromStackImpl);