gitGraphDiagram-LGD5RUNZ.mjs 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761
  1. import {
  2. populateCommonDb
  3. } from "./chunk-JJENOPKO.mjs";
  4. import {
  5. ImperativeState
  6. } from "./chunk-FBCX6ULS.mjs";
  7. import {
  8. cleanAndMerge,
  9. random,
  10. utils_default
  11. } from "./chunk-VKXSJROQ.mjs";
  12. import {
  13. __name,
  14. clear,
  15. common_default,
  16. defaultConfig_default,
  17. getAccDescription,
  18. getAccTitle,
  19. getConfig,
  20. getConfig2,
  21. getDiagramTitle,
  22. log,
  23. setAccDescription,
  24. setAccTitle,
  25. setDiagramTitle,
  26. setupGraphViewbox2 as setupGraphViewbox
  27. } from "./chunk-O2AGWWWV.mjs";
  28. // src/diagrams/git/gitGraphParser.ts
  29. import { parse } from "@mermaid-js/parser";
  30. // src/diagrams/git/gitGraphTypes.ts
  31. var commitType = {
  32. NORMAL: 0,
  33. REVERSE: 1,
  34. HIGHLIGHT: 2,
  35. MERGE: 3,
  36. CHERRY_PICK: 4
  37. };
  38. // src/diagrams/git/gitGraphAst.ts
  39. var DEFAULT_GITGRAPH_CONFIG = defaultConfig_default.gitGraph;
  40. var getConfig3 = /* @__PURE__ */ __name(() => {
  41. const config = cleanAndMerge({
  42. ...DEFAULT_GITGRAPH_CONFIG,
  43. ...getConfig().gitGraph
  44. });
  45. return config;
  46. }, "getConfig");
  47. var state = new ImperativeState(() => {
  48. const config = getConfig3();
  49. const mainBranchName = config.mainBranchName;
  50. const mainBranchOrder = config.mainBranchOrder;
  51. return {
  52. mainBranchName,
  53. commits: /* @__PURE__ */ new Map(),
  54. head: null,
  55. branchConfig: /* @__PURE__ */ new Map([[mainBranchName, { name: mainBranchName, order: mainBranchOrder }]]),
  56. branches: /* @__PURE__ */ new Map([[mainBranchName, null]]),
  57. currBranch: mainBranchName,
  58. direction: "LR",
  59. seq: 0,
  60. options: {}
  61. };
  62. });
  63. function getID() {
  64. return random({ length: 7 });
  65. }
  66. __name(getID, "getID");
  67. function uniqBy(list, fn) {
  68. const recordMap = /* @__PURE__ */ Object.create(null);
  69. return list.reduce((out, item) => {
  70. const key = fn(item);
  71. if (!recordMap[key]) {
  72. recordMap[key] = true;
  73. out.push(item);
  74. }
  75. return out;
  76. }, []);
  77. }
  78. __name(uniqBy, "uniqBy");
  79. var setDirection = /* @__PURE__ */ __name(function(dir2) {
  80. state.records.direction = dir2;
  81. }, "setDirection");
  82. var setOptions = /* @__PURE__ */ __name(function(rawOptString) {
  83. log.debug("options str", rawOptString);
  84. rawOptString = rawOptString?.trim();
  85. rawOptString = rawOptString || "{}";
  86. try {
  87. state.records.options = JSON.parse(rawOptString);
  88. } catch (e) {
  89. log.error("error while parsing gitGraph options", e.message);
  90. }
  91. }, "setOptions");
  92. var getOptions = /* @__PURE__ */ __name(function() {
  93. return state.records.options;
  94. }, "getOptions");
  95. var commit = /* @__PURE__ */ __name(function(commitDB) {
  96. let msg = commitDB.msg;
  97. let id = commitDB.id;
  98. const type = commitDB.type;
  99. let tags = commitDB.tags;
  100. log.info("commit", msg, id, type, tags);
  101. log.debug("Entering commit:", msg, id, type, tags);
  102. const config = getConfig3();
  103. id = common_default.sanitizeText(id, config);
  104. msg = common_default.sanitizeText(msg, config);
  105. tags = tags?.map((tag) => common_default.sanitizeText(tag, config));
  106. const newCommit = {
  107. id: id ? id : state.records.seq + "-" + getID(),
  108. message: msg,
  109. seq: state.records.seq++,
  110. type: type ?? commitType.NORMAL,
  111. tags: tags ?? [],
  112. parents: state.records.head == null ? [] : [state.records.head.id],
  113. branch: state.records.currBranch
  114. };
  115. state.records.head = newCommit;
  116. log.info("main branch", config.mainBranchName);
  117. state.records.commits.set(newCommit.id, newCommit);
  118. state.records.branches.set(state.records.currBranch, newCommit.id);
  119. log.debug("in pushCommit " + newCommit.id);
  120. }, "commit");
  121. var branch = /* @__PURE__ */ __name(function(branchDB) {
  122. let name = branchDB.name;
  123. const order = branchDB.order;
  124. name = common_default.sanitizeText(name, getConfig3());
  125. if (state.records.branches.has(name)) {
  126. throw new Error(
  127. `Trying to create an existing branch. (Help: Either use a new name if you want create a new branch or try using "checkout ${name}")`
  128. );
  129. }
  130. state.records.branches.set(name, state.records.head != null ? state.records.head.id : null);
  131. state.records.branchConfig.set(name, { name, order });
  132. checkout(name);
  133. log.debug("in createBranch");
  134. }, "branch");
  135. var merge = /* @__PURE__ */ __name((mergeDB) => {
  136. let otherBranch = mergeDB.branch;
  137. let customId = mergeDB.id;
  138. const overrideType = mergeDB.type;
  139. const customTags = mergeDB.tags;
  140. const config = getConfig3();
  141. otherBranch = common_default.sanitizeText(otherBranch, config);
  142. if (customId) {
  143. customId = common_default.sanitizeText(customId, config);
  144. }
  145. const currentBranchCheck = state.records.branches.get(state.records.currBranch);
  146. const otherBranchCheck = state.records.branches.get(otherBranch);
  147. const currentCommit = currentBranchCheck ? state.records.commits.get(currentBranchCheck) : void 0;
  148. const otherCommit = otherBranchCheck ? state.records.commits.get(otherBranchCheck) : void 0;
  149. if (currentCommit && otherCommit && currentCommit.branch === otherBranch) {
  150. throw new Error(`Cannot merge branch '${otherBranch}' into itself.`);
  151. }
  152. if (state.records.currBranch === otherBranch) {
  153. const error = new Error('Incorrect usage of "merge". Cannot merge a branch to itself');
  154. error.hash = {
  155. text: `merge ${otherBranch}`,
  156. token: `merge ${otherBranch}`,
  157. expected: ["branch abc"]
  158. };
  159. throw error;
  160. }
  161. if (currentCommit === void 0 || !currentCommit) {
  162. const error = new Error(
  163. `Incorrect usage of "merge". Current branch (${state.records.currBranch})has no commits`
  164. );
  165. error.hash = {
  166. text: `merge ${otherBranch}`,
  167. token: `merge ${otherBranch}`,
  168. expected: ["commit"]
  169. };
  170. throw error;
  171. }
  172. if (!state.records.branches.has(otherBranch)) {
  173. const error = new Error(
  174. 'Incorrect usage of "merge". Branch to be merged (' + otherBranch + ") does not exist"
  175. );
  176. error.hash = {
  177. text: `merge ${otherBranch}`,
  178. token: `merge ${otherBranch}`,
  179. expected: [`branch ${otherBranch}`]
  180. };
  181. throw error;
  182. }
  183. if (otherCommit === void 0 || !otherCommit) {
  184. const error = new Error(
  185. 'Incorrect usage of "merge". Branch to be merged (' + otherBranch + ") has no commits"
  186. );
  187. error.hash = {
  188. text: `merge ${otherBranch}`,
  189. token: `merge ${otherBranch}`,
  190. expected: ['"commit"']
  191. };
  192. throw error;
  193. }
  194. if (currentCommit === otherCommit) {
  195. const error = new Error('Incorrect usage of "merge". Both branches have same head');
  196. error.hash = {
  197. text: `merge ${otherBranch}`,
  198. token: `merge ${otherBranch}`,
  199. expected: ["branch abc"]
  200. };
  201. throw error;
  202. }
  203. if (customId && state.records.commits.has(customId)) {
  204. const error = new Error(
  205. 'Incorrect usage of "merge". Commit with id:' + customId + " already exists, use different custom Id"
  206. );
  207. error.hash = {
  208. text: `merge ${otherBranch} ${customId} ${overrideType} ${customTags?.join(" ")}`,
  209. token: `merge ${otherBranch} ${customId} ${overrideType} ${customTags?.join(" ")}`,
  210. expected: [
  211. `merge ${otherBranch} ${customId}_UNIQUE ${overrideType} ${customTags?.join(" ")}`
  212. ]
  213. };
  214. throw error;
  215. }
  216. const verifiedBranch = otherBranchCheck ? otherBranchCheck : "";
  217. const commit2 = {
  218. id: customId || `${state.records.seq}-${getID()}`,
  219. message: `merged branch ${otherBranch} into ${state.records.currBranch}`,
  220. seq: state.records.seq++,
  221. parents: state.records.head == null ? [] : [state.records.head.id, verifiedBranch],
  222. branch: state.records.currBranch,
  223. type: commitType.MERGE,
  224. customType: overrideType,
  225. customId: customId ? true : false,
  226. tags: customTags ?? []
  227. };
  228. state.records.head = commit2;
  229. state.records.commits.set(commit2.id, commit2);
  230. state.records.branches.set(state.records.currBranch, commit2.id);
  231. log.debug(state.records.branches);
  232. log.debug("in mergeBranch");
  233. }, "merge");
  234. var cherryPick = /* @__PURE__ */ __name(function(cherryPickDB) {
  235. let sourceId = cherryPickDB.id;
  236. let targetId = cherryPickDB.targetId;
  237. let tags = cherryPickDB.tags;
  238. let parentCommitId = cherryPickDB.parent;
  239. log.debug("Entering cherryPick:", sourceId, targetId, tags);
  240. const config = getConfig3();
  241. sourceId = common_default.sanitizeText(sourceId, config);
  242. targetId = common_default.sanitizeText(targetId, config);
  243. tags = tags?.map((tag) => common_default.sanitizeText(tag, config));
  244. parentCommitId = common_default.sanitizeText(parentCommitId, config);
  245. if (!sourceId || !state.records.commits.has(sourceId)) {
  246. const error = new Error(
  247. 'Incorrect usage of "cherryPick". Source commit id should exist and provided'
  248. );
  249. error.hash = {
  250. text: `cherryPick ${sourceId} ${targetId}`,
  251. token: `cherryPick ${sourceId} ${targetId}`,
  252. expected: ["cherry-pick abc"]
  253. };
  254. throw error;
  255. }
  256. const sourceCommit = state.records.commits.get(sourceId);
  257. if (sourceCommit === void 0 || !sourceCommit) {
  258. throw new Error('Incorrect usage of "cherryPick". Source commit id should exist and provided');
  259. }
  260. if (parentCommitId && !(Array.isArray(sourceCommit.parents) && sourceCommit.parents.includes(parentCommitId))) {
  261. const error = new Error(
  262. "Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit."
  263. );
  264. throw error;
  265. }
  266. const sourceCommitBranch = sourceCommit.branch;
  267. if (sourceCommit.type === commitType.MERGE && !parentCommitId) {
  268. const error = new Error(
  269. "Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified."
  270. );
  271. throw error;
  272. }
  273. if (!targetId || !state.records.commits.has(targetId)) {
  274. if (sourceCommitBranch === state.records.currBranch) {
  275. const error = new Error(
  276. 'Incorrect usage of "cherryPick". Source commit is already on current branch'
  277. );
  278. error.hash = {
  279. text: `cherryPick ${sourceId} ${targetId}`,
  280. token: `cherryPick ${sourceId} ${targetId}`,
  281. expected: ["cherry-pick abc"]
  282. };
  283. throw error;
  284. }
  285. const currentCommitId = state.records.branches.get(state.records.currBranch);
  286. if (currentCommitId === void 0 || !currentCommitId) {
  287. const error = new Error(
  288. `Incorrect usage of "cherry-pick". Current branch (${state.records.currBranch})has no commits`
  289. );
  290. error.hash = {
  291. text: `cherryPick ${sourceId} ${targetId}`,
  292. token: `cherryPick ${sourceId} ${targetId}`,
  293. expected: ["cherry-pick abc"]
  294. };
  295. throw error;
  296. }
  297. const currentCommit = state.records.commits.get(currentCommitId);
  298. if (currentCommit === void 0 || !currentCommit) {
  299. const error = new Error(
  300. `Incorrect usage of "cherry-pick". Current branch (${state.records.currBranch})has no commits`
  301. );
  302. error.hash = {
  303. text: `cherryPick ${sourceId} ${targetId}`,
  304. token: `cherryPick ${sourceId} ${targetId}`,
  305. expected: ["cherry-pick abc"]
  306. };
  307. throw error;
  308. }
  309. const commit2 = {
  310. id: state.records.seq + "-" + getID(),
  311. message: `cherry-picked ${sourceCommit?.message} into ${state.records.currBranch}`,
  312. seq: state.records.seq++,
  313. parents: state.records.head == null ? [] : [state.records.head.id, sourceCommit.id],
  314. branch: state.records.currBranch,
  315. type: commitType.CHERRY_PICK,
  316. tags: tags ? tags.filter(Boolean) : [
  317. `cherry-pick:${sourceCommit.id}${sourceCommit.type === commitType.MERGE ? `|parent:${parentCommitId}` : ""}`
  318. ]
  319. };
  320. state.records.head = commit2;
  321. state.records.commits.set(commit2.id, commit2);
  322. state.records.branches.set(state.records.currBranch, commit2.id);
  323. log.debug(state.records.branches);
  324. log.debug("in cherryPick");
  325. }
  326. }, "cherryPick");
  327. var checkout = /* @__PURE__ */ __name(function(branch2) {
  328. branch2 = common_default.sanitizeText(branch2, getConfig3());
  329. if (!state.records.branches.has(branch2)) {
  330. const error = new Error(
  331. `Trying to checkout branch which is not yet created. (Help try using "branch ${branch2}")`
  332. );
  333. error.hash = {
  334. text: `checkout ${branch2}`,
  335. token: `checkout ${branch2}`,
  336. expected: [`branch ${branch2}`]
  337. };
  338. throw error;
  339. } else {
  340. state.records.currBranch = branch2;
  341. const id = state.records.branches.get(state.records.currBranch);
  342. if (id === void 0 || !id) {
  343. state.records.head = null;
  344. } else {
  345. state.records.head = state.records.commits.get(id) ?? null;
  346. }
  347. }
  348. }, "checkout");
  349. function upsert(arr, key, newVal) {
  350. const index = arr.indexOf(key);
  351. if (index === -1) {
  352. arr.push(newVal);
  353. } else {
  354. arr.splice(index, 1, newVal);
  355. }
  356. }
  357. __name(upsert, "upsert");
  358. function prettyPrintCommitHistory(commitArr) {
  359. const commit2 = commitArr.reduce((out, commit3) => {
  360. if (out.seq > commit3.seq) {
  361. return out;
  362. }
  363. return commit3;
  364. }, commitArr[0]);
  365. let line = "";
  366. commitArr.forEach(function(c) {
  367. if (c === commit2) {
  368. line += " *";
  369. } else {
  370. line += " |";
  371. }
  372. });
  373. const label = [line, commit2.id, commit2.seq];
  374. for (const branch2 in state.records.branches) {
  375. if (state.records.branches.get(branch2) === commit2.id) {
  376. label.push(branch2);
  377. }
  378. }
  379. log.debug(label.join(" "));
  380. if (commit2.parents && commit2.parents.length == 2 && commit2.parents[0] && commit2.parents[1]) {
  381. const newCommit = state.records.commits.get(commit2.parents[0]);
  382. upsert(commitArr, commit2, newCommit);
  383. if (commit2.parents[1]) {
  384. commitArr.push(state.records.commits.get(commit2.parents[1]));
  385. }
  386. } else if (commit2.parents.length == 0) {
  387. return;
  388. } else {
  389. if (commit2.parents[0]) {
  390. const newCommit = state.records.commits.get(commit2.parents[0]);
  391. upsert(commitArr, commit2, newCommit);
  392. }
  393. }
  394. commitArr = uniqBy(commitArr, (c) => c.id);
  395. prettyPrintCommitHistory(commitArr);
  396. }
  397. __name(prettyPrintCommitHistory, "prettyPrintCommitHistory");
  398. var prettyPrint = /* @__PURE__ */ __name(function() {
  399. log.debug(state.records.commits);
  400. const node = getCommitsArray()[0];
  401. prettyPrintCommitHistory([node]);
  402. }, "prettyPrint");
  403. var clear2 = /* @__PURE__ */ __name(function() {
  404. state.reset();
  405. clear();
  406. }, "clear");
  407. var getBranchesAsObjArray = /* @__PURE__ */ __name(function() {
  408. const branchesArray = [...state.records.branchConfig.values()].map((branchConfig, i) => {
  409. if (branchConfig.order !== null && branchConfig.order !== void 0) {
  410. return branchConfig;
  411. }
  412. return {
  413. ...branchConfig,
  414. order: parseFloat(`0.${i}`)
  415. };
  416. }).sort((a, b) => (a.order ?? 0) - (b.order ?? 0)).map(({ name }) => ({ name }));
  417. return branchesArray;
  418. }, "getBranchesAsObjArray");
  419. var getBranches = /* @__PURE__ */ __name(function() {
  420. return state.records.branches;
  421. }, "getBranches");
  422. var getCommits = /* @__PURE__ */ __name(function() {
  423. return state.records.commits;
  424. }, "getCommits");
  425. var getCommitsArray = /* @__PURE__ */ __name(function() {
  426. const commitArr = [...state.records.commits.values()];
  427. commitArr.forEach(function(o) {
  428. log.debug(o.id);
  429. });
  430. commitArr.sort((a, b) => a.seq - b.seq);
  431. return commitArr;
  432. }, "getCommitsArray");
  433. var getCurrentBranch = /* @__PURE__ */ __name(function() {
  434. return state.records.currBranch;
  435. }, "getCurrentBranch");
  436. var getDirection = /* @__PURE__ */ __name(function() {
  437. return state.records.direction;
  438. }, "getDirection");
  439. var getHead = /* @__PURE__ */ __name(function() {
  440. return state.records.head;
  441. }, "getHead");
  442. var db = {
  443. commitType,
  444. getConfig: getConfig3,
  445. setDirection,
  446. setOptions,
  447. getOptions,
  448. commit,
  449. branch,
  450. merge,
  451. cherryPick,
  452. checkout,
  453. //reset,
  454. prettyPrint,
  455. clear: clear2,
  456. getBranchesAsObjArray,
  457. getBranches,
  458. getCommits,
  459. getCommitsArray,
  460. getCurrentBranch,
  461. getDirection,
  462. getHead,
  463. setAccTitle,
  464. getAccTitle,
  465. getAccDescription,
  466. setAccDescription,
  467. setDiagramTitle,
  468. getDiagramTitle
  469. };
  470. // src/diagrams/git/gitGraphParser.ts
  471. var populate = /* @__PURE__ */ __name((ast, db2) => {
  472. populateCommonDb(ast, db2);
  473. if (ast.dir) {
  474. db2.setDirection(ast.dir);
  475. }
  476. for (const statement of ast.statements) {
  477. parseStatement(statement, db2);
  478. }
  479. }, "populate");
  480. var parseStatement = /* @__PURE__ */ __name((statement, db2) => {
  481. const parsers = {
  482. Commit: /* @__PURE__ */ __name((stmt) => db2.commit(parseCommit(stmt)), "Commit"),
  483. Branch: /* @__PURE__ */ __name((stmt) => db2.branch(parseBranch(stmt)), "Branch"),
  484. Merge: /* @__PURE__ */ __name((stmt) => db2.merge(parseMerge(stmt)), "Merge"),
  485. Checkout: /* @__PURE__ */ __name((stmt) => db2.checkout(parseCheckout(stmt)), "Checkout"),
  486. CherryPicking: /* @__PURE__ */ __name((stmt) => db2.cherryPick(parseCherryPicking(stmt)), "CherryPicking")
  487. };
  488. const parser2 = parsers[statement.$type];
  489. if (parser2) {
  490. parser2(statement);
  491. } else {
  492. log.error(`Unknown statement type: ${statement.$type}`);
  493. }
  494. }, "parseStatement");
  495. var parseCommit = /* @__PURE__ */ __name((commit2) => {
  496. const commitDB = {
  497. id: commit2.id,
  498. msg: commit2.message ?? "",
  499. type: commit2.type !== void 0 ? commitType[commit2.type] : commitType.NORMAL,
  500. tags: commit2.tags ?? void 0
  501. };
  502. return commitDB;
  503. }, "parseCommit");
  504. var parseBranch = /* @__PURE__ */ __name((branch2) => {
  505. const branchDB = {
  506. name: branch2.name,
  507. order: branch2.order ?? 0
  508. };
  509. return branchDB;
  510. }, "parseBranch");
  511. var parseMerge = /* @__PURE__ */ __name((merge2) => {
  512. const mergeDB = {
  513. branch: merge2.branch,
  514. id: merge2.id ?? "",
  515. type: merge2.type !== void 0 ? commitType[merge2.type] : void 0,
  516. tags: merge2.tags ?? void 0
  517. };
  518. return mergeDB;
  519. }, "parseMerge");
  520. var parseCheckout = /* @__PURE__ */ __name((checkout2) => {
  521. const branch2 = checkout2.branch;
  522. return branch2;
  523. }, "parseCheckout");
  524. var parseCherryPicking = /* @__PURE__ */ __name((cherryPicking) => {
  525. const cherryPickDB = {
  526. id: cherryPicking.id,
  527. targetId: "",
  528. tags: cherryPicking.tags?.length === 0 ? void 0 : cherryPicking.tags,
  529. parent: cherryPicking.parent
  530. };
  531. return cherryPickDB;
  532. }, "parseCherryPicking");
  533. var parser = {
  534. parse: /* @__PURE__ */ __name(async (input) => {
  535. const ast = await parse("gitGraph", input);
  536. log.debug(ast);
  537. populate(ast, db);
  538. }, "parse")
  539. };
  540. if (void 0) {
  541. const { it, expect, describe } = void 0;
  542. const mockDB = {
  543. commitType,
  544. setDirection: vi.fn(),
  545. commit: vi.fn(),
  546. branch: vi.fn(),
  547. merge: vi.fn(),
  548. cherryPick: vi.fn(),
  549. checkout: vi.fn()
  550. };
  551. describe("GitGraph Parser", () => {
  552. it("should parse a commit statement", () => {
  553. const commit2 = {
  554. $type: "Commit",
  555. id: "1",
  556. message: "test",
  557. tags: ["tag1", "tag2"],
  558. type: "NORMAL"
  559. };
  560. parseStatement(commit2, mockDB);
  561. expect(mockDB.commit).toHaveBeenCalledWith({
  562. id: "1",
  563. msg: "test",
  564. tags: ["tag1", "tag2"],
  565. type: 0
  566. });
  567. });
  568. it("should parse a branch statement", () => {
  569. const branch2 = {
  570. $type: "Branch",
  571. name: "newBranch",
  572. order: 1
  573. };
  574. parseStatement(branch2, mockDB);
  575. expect(mockDB.branch).toHaveBeenCalledWith({ name: "newBranch", order: 1 });
  576. });
  577. it("should parse a checkout statement", () => {
  578. const checkout2 = {
  579. $type: "Checkout",
  580. branch: "newBranch"
  581. };
  582. parseStatement(checkout2, mockDB);
  583. expect(mockDB.checkout).toHaveBeenCalledWith("newBranch");
  584. });
  585. it("should parse a merge statement", () => {
  586. const merge2 = {
  587. $type: "Merge",
  588. branch: "newBranch",
  589. id: "1",
  590. tags: ["tag1", "tag2"],
  591. type: "NORMAL"
  592. };
  593. parseStatement(merge2, mockDB);
  594. expect(mockDB.merge).toHaveBeenCalledWith({
  595. branch: "newBranch",
  596. id: "1",
  597. tags: ["tag1", "tag2"],
  598. type: 0
  599. });
  600. });
  601. it("should parse a cherry picking statement", () => {
  602. const cherryPick2 = {
  603. $type: "CherryPicking",
  604. id: "1",
  605. tags: ["tag1", "tag2"],
  606. parent: "2"
  607. };
  608. parseStatement(cherryPick2, mockDB);
  609. expect(mockDB.cherryPick).toHaveBeenCalledWith({
  610. id: "1",
  611. targetId: "",
  612. parent: "2",
  613. tags: ["tag1", "tag2"]
  614. });
  615. });
  616. it("should parse a langium generated gitGraph ast", () => {
  617. const dummy = {
  618. $type: "GitGraph",
  619. statements: []
  620. };
  621. const gitGraphAst = {
  622. $type: "GitGraph",
  623. statements: [
  624. {
  625. $container: dummy,
  626. $type: "Commit",
  627. id: "1",
  628. message: "test",
  629. tags: ["tag1", "tag2"],
  630. type: "NORMAL"
  631. },
  632. {
  633. $container: dummy,
  634. $type: "Branch",
  635. name: "newBranch",
  636. order: 1
  637. },
  638. {
  639. $container: dummy,
  640. $type: "Merge",
  641. branch: "newBranch",
  642. id: "1",
  643. tags: ["tag1", "tag2"],
  644. type: "NORMAL"
  645. },
  646. {
  647. $container: dummy,
  648. $type: "Checkout",
  649. branch: "newBranch"
  650. },
  651. {
  652. $container: dummy,
  653. $type: "CherryPicking",
  654. id: "1",
  655. tags: ["tag1", "tag2"],
  656. parent: "2"
  657. }
  658. ]
  659. };
  660. populate(gitGraphAst, mockDB);
  661. expect(mockDB.commit).toHaveBeenCalledWith({
  662. id: "1",
  663. msg: "test",
  664. tags: ["tag1", "tag2"],
  665. type: 0
  666. });
  667. expect(mockDB.branch).toHaveBeenCalledWith({ name: "newBranch", order: 1 });
  668. expect(mockDB.merge).toHaveBeenCalledWith({
  669. branch: "newBranch",
  670. id: "1",
  671. tags: ["tag1", "tag2"],
  672. type: 0
  673. });
  674. expect(mockDB.checkout).toHaveBeenCalledWith("newBranch");
  675. });
  676. });
  677. }
  678. // src/diagrams/git/gitGraphRenderer.ts
  679. import { select } from "d3";
  680. var DEFAULT_CONFIG = getConfig2();
  681. var DEFAULT_GITGRAPH_CONFIG2 = DEFAULT_CONFIG?.gitGraph;
  682. var LAYOUT_OFFSET = 10;
  683. var COMMIT_STEP = 40;
  684. var PX = 4;
  685. var PY = 2;
  686. var THEME_COLOR_LIMIT = 8;
  687. var branchPos = /* @__PURE__ */ new Map();
  688. var commitPos = /* @__PURE__ */ new Map();
  689. var defaultPos = 30;
  690. var allCommitsDict = /* @__PURE__ */ new Map();
  691. var lanes = [];
  692. var maxPos = 0;
  693. var dir = "LR";
  694. var clear3 = /* @__PURE__ */ __name(() => {
  695. branchPos.clear();
  696. commitPos.clear();
  697. allCommitsDict.clear();
  698. maxPos = 0;
  699. lanes = [];
  700. dir = "LR";
  701. }, "clear");
  702. var drawText = /* @__PURE__ */ __name((txt) => {
  703. const svgLabel = document.createElementNS("http://www.w3.org/2000/svg", "text");
  704. const rows = typeof txt === "string" ? txt.split(/\\n|\n|<br\s*\/?>/gi) : txt;
  705. rows.forEach((row) => {
  706. const tspan = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
  707. tspan.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve");
  708. tspan.setAttribute("dy", "1em");
  709. tspan.setAttribute("x", "0");
  710. tspan.setAttribute("class", "row");
  711. tspan.textContent = row.trim();
  712. svgLabel.appendChild(tspan);
  713. });
  714. return svgLabel;
  715. }, "drawText");
  716. var findClosestParent = /* @__PURE__ */ __name((parents) => {
  717. let closestParent;
  718. let comparisonFunc;
  719. let targetPosition;
  720. if (dir === "BT") {
  721. comparisonFunc = /* @__PURE__ */ __name((a, b) => a <= b, "comparisonFunc");
  722. targetPosition = Infinity;
  723. } else {
  724. comparisonFunc = /* @__PURE__ */ __name((a, b) => a >= b, "comparisonFunc");
  725. targetPosition = 0;
  726. }
  727. parents.forEach((parent) => {
  728. const parentPosition = dir === "TB" || dir == "BT" ? commitPos.get(parent)?.y : commitPos.get(parent)?.x;
  729. if (parentPosition !== void 0 && comparisonFunc(parentPosition, targetPosition)) {
  730. closestParent = parent;
  731. targetPosition = parentPosition;
  732. }
  733. });
  734. return closestParent;
  735. }, "findClosestParent");
  736. var findClosestParentBT = /* @__PURE__ */ __name((parents) => {
  737. let closestParent = "";
  738. let maxPosition = Infinity;
  739. parents.forEach((parent) => {
  740. const parentPosition = commitPos.get(parent).y;
  741. if (parentPosition <= maxPosition) {
  742. closestParent = parent;
  743. maxPosition = parentPosition;
  744. }
  745. });
  746. return closestParent || void 0;
  747. }, "findClosestParentBT");
  748. var setParallelBTPos = /* @__PURE__ */ __name((sortedKeys, commits, defaultPos2) => {
  749. let curPos = defaultPos2;
  750. let maxPosition = defaultPos2;
  751. const roots = [];
  752. sortedKeys.forEach((key) => {
  753. const commit2 = commits.get(key);
  754. if (!commit2) {
  755. throw new Error(`Commit not found for key ${key}`);
  756. }
  757. if (commit2.parents.length) {
  758. curPos = calculateCommitPosition(commit2);
  759. maxPosition = Math.max(curPos, maxPosition);
  760. } else {
  761. roots.push(commit2);
  762. }
  763. setCommitPosition(commit2, curPos);
  764. });
  765. curPos = maxPosition;
  766. roots.forEach((commit2) => {
  767. setRootPosition(commit2, curPos, defaultPos2);
  768. });
  769. sortedKeys.forEach((key) => {
  770. const commit2 = commits.get(key);
  771. if (commit2?.parents.length) {
  772. const closestParent = findClosestParentBT(commit2.parents);
  773. curPos = commitPos.get(closestParent).y - COMMIT_STEP;
  774. if (curPos <= maxPosition) {
  775. maxPosition = curPos;
  776. }
  777. const x = branchPos.get(commit2.branch).pos;
  778. const y = curPos - LAYOUT_OFFSET;
  779. commitPos.set(commit2.id, { x, y });
  780. }
  781. });
  782. }, "setParallelBTPos");
  783. var findClosestParentPos = /* @__PURE__ */ __name((commit2) => {
  784. const closestParent = findClosestParent(commit2.parents.filter((p) => p !== null));
  785. if (!closestParent) {
  786. throw new Error(`Closest parent not found for commit ${commit2.id}`);
  787. }
  788. const closestParentPos = commitPos.get(closestParent)?.y;
  789. if (closestParentPos === void 0) {
  790. throw new Error(`Closest parent position not found for commit ${commit2.id}`);
  791. }
  792. return closestParentPos;
  793. }, "findClosestParentPos");
  794. var calculateCommitPosition = /* @__PURE__ */ __name((commit2) => {
  795. const closestParentPos = findClosestParentPos(commit2);
  796. return closestParentPos + COMMIT_STEP;
  797. }, "calculateCommitPosition");
  798. var setCommitPosition = /* @__PURE__ */ __name((commit2, curPos) => {
  799. const branch2 = branchPos.get(commit2.branch);
  800. if (!branch2) {
  801. throw new Error(`Branch not found for commit ${commit2.id}`);
  802. }
  803. const x = branch2.pos;
  804. const y = curPos + LAYOUT_OFFSET;
  805. commitPos.set(commit2.id, { x, y });
  806. return { x, y };
  807. }, "setCommitPosition");
  808. var setRootPosition = /* @__PURE__ */ __name((commit2, curPos, defaultPos2) => {
  809. const branch2 = branchPos.get(commit2.branch);
  810. if (!branch2) {
  811. throw new Error(`Branch not found for commit ${commit2.id}`);
  812. }
  813. const y = curPos + defaultPos2;
  814. const x = branch2.pos;
  815. commitPos.set(commit2.id, { x, y });
  816. }, "setRootPosition");
  817. var drawCommitBullet = /* @__PURE__ */ __name((gBullets, commit2, commitPosition, typeClass, branchIndex, commitSymbolType) => {
  818. if (commitSymbolType === commitType.HIGHLIGHT) {
  819. gBullets.append("rect").attr("x", commitPosition.x - 10).attr("y", commitPosition.y - 10).attr("width", 20).attr("height", 20).attr(
  820. "class",
  821. `commit ${commit2.id} commit-highlight${branchIndex % THEME_COLOR_LIMIT} ${typeClass}-outer`
  822. );
  823. gBullets.append("rect").attr("x", commitPosition.x - 6).attr("y", commitPosition.y - 6).attr("width", 12).attr("height", 12).attr(
  824. "class",
  825. `commit ${commit2.id} commit${branchIndex % THEME_COLOR_LIMIT} ${typeClass}-inner`
  826. );
  827. } else if (commitSymbolType === commitType.CHERRY_PICK) {
  828. gBullets.append("circle").attr("cx", commitPosition.x).attr("cy", commitPosition.y).attr("r", 10).attr("class", `commit ${commit2.id} ${typeClass}`);
  829. gBullets.append("circle").attr("cx", commitPosition.x - 3).attr("cy", commitPosition.y + 2).attr("r", 2.75).attr("fill", "#fff").attr("class", `commit ${commit2.id} ${typeClass}`);
  830. gBullets.append("circle").attr("cx", commitPosition.x + 3).attr("cy", commitPosition.y + 2).attr("r", 2.75).attr("fill", "#fff").attr("class", `commit ${commit2.id} ${typeClass}`);
  831. gBullets.append("line").attr("x1", commitPosition.x + 3).attr("y1", commitPosition.y + 1).attr("x2", commitPosition.x).attr("y2", commitPosition.y - 5).attr("stroke", "#fff").attr("class", `commit ${commit2.id} ${typeClass}`);
  832. gBullets.append("line").attr("x1", commitPosition.x - 3).attr("y1", commitPosition.y + 1).attr("x2", commitPosition.x).attr("y2", commitPosition.y - 5).attr("stroke", "#fff").attr("class", `commit ${commit2.id} ${typeClass}`);
  833. } else {
  834. const circle = gBullets.append("circle");
  835. circle.attr("cx", commitPosition.x);
  836. circle.attr("cy", commitPosition.y);
  837. circle.attr("r", commit2.type === commitType.MERGE ? 9 : 10);
  838. circle.attr("class", `commit ${commit2.id} commit${branchIndex % THEME_COLOR_LIMIT}`);
  839. if (commitSymbolType === commitType.MERGE) {
  840. const circle2 = gBullets.append("circle");
  841. circle2.attr("cx", commitPosition.x);
  842. circle2.attr("cy", commitPosition.y);
  843. circle2.attr("r", 6);
  844. circle2.attr(
  845. "class",
  846. `commit ${typeClass} ${commit2.id} commit${branchIndex % THEME_COLOR_LIMIT}`
  847. );
  848. }
  849. if (commitSymbolType === commitType.REVERSE) {
  850. const cross = gBullets.append("path");
  851. cross.attr(
  852. "d",
  853. `M ${commitPosition.x - 5},${commitPosition.y - 5}L${commitPosition.x + 5},${commitPosition.y + 5}M${commitPosition.x - 5},${commitPosition.y + 5}L${commitPosition.x + 5},${commitPosition.y - 5}`
  854. ).attr("class", `commit ${typeClass} ${commit2.id} commit${branchIndex % THEME_COLOR_LIMIT}`);
  855. }
  856. }
  857. }, "drawCommitBullet");
  858. var drawCommitLabel = /* @__PURE__ */ __name((gLabels, commit2, commitPosition, pos) => {
  859. if (commit2.type !== commitType.CHERRY_PICK && (commit2.customId && commit2.type === commitType.MERGE || commit2.type !== commitType.MERGE) && DEFAULT_GITGRAPH_CONFIG2?.showCommitLabel) {
  860. const wrapper = gLabels.append("g");
  861. const labelBkg = wrapper.insert("rect").attr("class", "commit-label-bkg");
  862. const text = wrapper.append("text").attr("x", pos).attr("y", commitPosition.y + 25).attr("class", "commit-label").text(commit2.id);
  863. const bbox = text.node()?.getBBox();
  864. if (bbox) {
  865. labelBkg.attr("x", commitPosition.posWithOffset - bbox.width / 2 - PY).attr("y", commitPosition.y + 13.5).attr("width", bbox.width + 2 * PY).attr("height", bbox.height + 2 * PY);
  866. if (dir === "TB" || dir === "BT") {
  867. labelBkg.attr("x", commitPosition.x - (bbox.width + 4 * PX + 5)).attr("y", commitPosition.y - 12);
  868. text.attr("x", commitPosition.x - (bbox.width + 4 * PX)).attr("y", commitPosition.y + bbox.height - 12);
  869. } else {
  870. text.attr("x", commitPosition.posWithOffset - bbox.width / 2);
  871. }
  872. if (DEFAULT_GITGRAPH_CONFIG2.rotateCommitLabel) {
  873. if (dir === "TB" || dir === "BT") {
  874. text.attr(
  875. "transform",
  876. "rotate(-45, " + commitPosition.x + ", " + commitPosition.y + ")"
  877. );
  878. labelBkg.attr(
  879. "transform",
  880. "rotate(-45, " + commitPosition.x + ", " + commitPosition.y + ")"
  881. );
  882. } else {
  883. const r_x = -7.5 - (bbox.width + 10) / 25 * 9.5;
  884. const r_y = 10 + bbox.width / 25 * 8.5;
  885. wrapper.attr(
  886. "transform",
  887. "translate(" + r_x + ", " + r_y + ") rotate(-45, " + pos + ", " + commitPosition.y + ")"
  888. );
  889. }
  890. }
  891. }
  892. }
  893. }, "drawCommitLabel");
  894. var drawCommitTags = /* @__PURE__ */ __name((gLabels, commit2, commitPosition, pos) => {
  895. if (commit2.tags.length > 0) {
  896. let yOffset = 0;
  897. let maxTagBboxWidth = 0;
  898. let maxTagBboxHeight = 0;
  899. const tagElements = [];
  900. for (const tagValue of commit2.tags.reverse()) {
  901. const rect = gLabels.insert("polygon");
  902. const hole = gLabels.append("circle");
  903. const tag = gLabels.append("text").attr("y", commitPosition.y - 16 - yOffset).attr("class", "tag-label").text(tagValue);
  904. const tagBbox = tag.node()?.getBBox();
  905. if (!tagBbox) {
  906. throw new Error("Tag bbox not found");
  907. }
  908. maxTagBboxWidth = Math.max(maxTagBboxWidth, tagBbox.width);
  909. maxTagBboxHeight = Math.max(maxTagBboxHeight, tagBbox.height);
  910. tag.attr("x", commitPosition.posWithOffset - tagBbox.width / 2);
  911. tagElements.push({
  912. tag,
  913. hole,
  914. rect,
  915. yOffset
  916. });
  917. yOffset += 20;
  918. }
  919. for (const { tag, hole, rect, yOffset: yOffset2 } of tagElements) {
  920. const h2 = maxTagBboxHeight / 2;
  921. const ly = commitPosition.y - 19.2 - yOffset2;
  922. rect.attr("class", "tag-label-bkg").attr(
  923. "points",
  924. `
  925. ${pos - maxTagBboxWidth / 2 - PX / 2},${ly + PY}
  926. ${pos - maxTagBboxWidth / 2 - PX / 2},${ly - PY}
  927. ${commitPosition.posWithOffset - maxTagBboxWidth / 2 - PX},${ly - h2 - PY}
  928. ${commitPosition.posWithOffset + maxTagBboxWidth / 2 + PX},${ly - h2 - PY}
  929. ${commitPosition.posWithOffset + maxTagBboxWidth / 2 + PX},${ly + h2 + PY}
  930. ${commitPosition.posWithOffset - maxTagBboxWidth / 2 - PX},${ly + h2 + PY}`
  931. );
  932. hole.attr("cy", ly).attr("cx", pos - maxTagBboxWidth / 2 + PX / 2).attr("r", 1.5).attr("class", "tag-hole");
  933. if (dir === "TB" || dir === "BT") {
  934. const yOrigin = pos + yOffset2;
  935. rect.attr("class", "tag-label-bkg").attr(
  936. "points",
  937. `
  938. ${commitPosition.x},${yOrigin + 2}
  939. ${commitPosition.x},${yOrigin - 2}
  940. ${commitPosition.x + LAYOUT_OFFSET},${yOrigin - h2 - 2}
  941. ${commitPosition.x + LAYOUT_OFFSET + maxTagBboxWidth + 4},${yOrigin - h2 - 2}
  942. ${commitPosition.x + LAYOUT_OFFSET + maxTagBboxWidth + 4},${yOrigin + h2 + 2}
  943. ${commitPosition.x + LAYOUT_OFFSET},${yOrigin + h2 + 2}`
  944. ).attr("transform", "translate(12,12) rotate(45, " + commitPosition.x + "," + pos + ")");
  945. hole.attr("cx", commitPosition.x + PX / 2).attr("cy", yOrigin).attr("transform", "translate(12,12) rotate(45, " + commitPosition.x + "," + pos + ")");
  946. tag.attr("x", commitPosition.x + 5).attr("y", yOrigin + 3).attr("transform", "translate(14,14) rotate(45, " + commitPosition.x + "," + pos + ")");
  947. }
  948. }
  949. }
  950. }, "drawCommitTags");
  951. var getCommitClassType = /* @__PURE__ */ __name((commit2) => {
  952. const commitSymbolType = commit2.customType ?? commit2.type;
  953. switch (commitSymbolType) {
  954. case commitType.NORMAL:
  955. return "commit-normal";
  956. case commitType.REVERSE:
  957. return "commit-reverse";
  958. case commitType.HIGHLIGHT:
  959. return "commit-highlight";
  960. case commitType.MERGE:
  961. return "commit-merge";
  962. case commitType.CHERRY_PICK:
  963. return "commit-cherry-pick";
  964. default:
  965. return "commit-normal";
  966. }
  967. }, "getCommitClassType");
  968. var calculatePosition = /* @__PURE__ */ __name((commit2, dir2, pos, commitPos2) => {
  969. const defaultCommitPosition = { x: 0, y: 0 };
  970. if (commit2.parents.length > 0) {
  971. const closestParent = findClosestParent(commit2.parents);
  972. if (closestParent) {
  973. const parentPosition = commitPos2.get(closestParent) ?? defaultCommitPosition;
  974. if (dir2 === "TB") {
  975. return parentPosition.y + COMMIT_STEP;
  976. } else if (dir2 === "BT") {
  977. const currentPosition = commitPos2.get(commit2.id) ?? defaultCommitPosition;
  978. return currentPosition.y - COMMIT_STEP;
  979. } else {
  980. return parentPosition.x + COMMIT_STEP;
  981. }
  982. }
  983. } else {
  984. if (dir2 === "TB") {
  985. return defaultPos;
  986. } else if (dir2 === "BT") {
  987. const currentPosition = commitPos2.get(commit2.id) ?? defaultCommitPosition;
  988. return currentPosition.y - COMMIT_STEP;
  989. } else {
  990. return 0;
  991. }
  992. }
  993. return 0;
  994. }, "calculatePosition");
  995. var getCommitPosition = /* @__PURE__ */ __name((commit2, pos, isParallelCommits) => {
  996. const posWithOffset = dir === "BT" && isParallelCommits ? pos : pos + LAYOUT_OFFSET;
  997. const y = dir === "TB" || dir === "BT" ? posWithOffset : branchPos.get(commit2.branch)?.pos;
  998. const x = dir === "TB" || dir === "BT" ? branchPos.get(commit2.branch)?.pos : posWithOffset;
  999. if (x === void 0 || y === void 0) {
  1000. throw new Error(`Position were undefined for commit ${commit2.id}`);
  1001. }
  1002. return { x, y, posWithOffset };
  1003. }, "getCommitPosition");
  1004. var drawCommits = /* @__PURE__ */ __name((svg, commits, modifyGraph) => {
  1005. if (!DEFAULT_GITGRAPH_CONFIG2) {
  1006. throw new Error("GitGraph config not found");
  1007. }
  1008. const gBullets = svg.append("g").attr("class", "commit-bullets");
  1009. const gLabels = svg.append("g").attr("class", "commit-labels");
  1010. let pos = dir === "TB" || dir === "BT" ? defaultPos : 0;
  1011. const keys = [...commits.keys()];
  1012. const isParallelCommits = DEFAULT_GITGRAPH_CONFIG2?.parallelCommits ?? false;
  1013. const sortKeys = /* @__PURE__ */ __name((a, b) => {
  1014. const seqA = commits.get(a)?.seq;
  1015. const seqB = commits.get(b)?.seq;
  1016. return seqA !== void 0 && seqB !== void 0 ? seqA - seqB : 0;
  1017. }, "sortKeys");
  1018. let sortedKeys = keys.sort(sortKeys);
  1019. if (dir === "BT") {
  1020. if (isParallelCommits) {
  1021. setParallelBTPos(sortedKeys, commits, pos);
  1022. }
  1023. sortedKeys = sortedKeys.reverse();
  1024. }
  1025. sortedKeys.forEach((key) => {
  1026. const commit2 = commits.get(key);
  1027. if (!commit2) {
  1028. throw new Error(`Commit not found for key ${key}`);
  1029. }
  1030. if (isParallelCommits) {
  1031. pos = calculatePosition(commit2, dir, pos, commitPos);
  1032. }
  1033. const commitPosition = getCommitPosition(commit2, pos, isParallelCommits);
  1034. if (modifyGraph) {
  1035. const typeClass = getCommitClassType(commit2);
  1036. const commitSymbolType = commit2.customType ?? commit2.type;
  1037. const branchIndex = branchPos.get(commit2.branch)?.index ?? 0;
  1038. drawCommitBullet(gBullets, commit2, commitPosition, typeClass, branchIndex, commitSymbolType);
  1039. drawCommitLabel(gLabels, commit2, commitPosition, pos);
  1040. drawCommitTags(gLabels, commit2, commitPosition, pos);
  1041. }
  1042. if (dir === "TB" || dir === "BT") {
  1043. commitPos.set(commit2.id, { x: commitPosition.x, y: commitPosition.posWithOffset });
  1044. } else {
  1045. commitPos.set(commit2.id, { x: commitPosition.posWithOffset, y: commitPosition.y });
  1046. }
  1047. pos = dir === "BT" && isParallelCommits ? pos + COMMIT_STEP : pos + COMMIT_STEP + LAYOUT_OFFSET;
  1048. if (pos > maxPos) {
  1049. maxPos = pos;
  1050. }
  1051. });
  1052. }, "drawCommits");
  1053. var shouldRerouteArrow = /* @__PURE__ */ __name((commitA, commitB, p1, p2, allCommits) => {
  1054. const commitBIsFurthest = dir === "TB" || dir === "BT" ? p1.x < p2.x : p1.y < p2.y;
  1055. const branchToGetCurve = commitBIsFurthest ? commitB.branch : commitA.branch;
  1056. const isOnBranchToGetCurve = /* @__PURE__ */ __name((x) => x.branch === branchToGetCurve, "isOnBranchToGetCurve");
  1057. const isBetweenCommits = /* @__PURE__ */ __name((x) => x.seq > commitA.seq && x.seq < commitB.seq, "isBetweenCommits");
  1058. return [...allCommits.values()].some((commitX) => {
  1059. return isBetweenCommits(commitX) && isOnBranchToGetCurve(commitX);
  1060. });
  1061. }, "shouldRerouteArrow");
  1062. var findLane = /* @__PURE__ */ __name((y1, y2, depth = 0) => {
  1063. const candidate = y1 + Math.abs(y1 - y2) / 2;
  1064. if (depth > 5) {
  1065. return candidate;
  1066. }
  1067. const ok = lanes.every((lane) => Math.abs(lane - candidate) >= 10);
  1068. if (ok) {
  1069. lanes.push(candidate);
  1070. return candidate;
  1071. }
  1072. const diff = Math.abs(y1 - y2);
  1073. return findLane(y1, y2 - diff / 5, depth + 1);
  1074. }, "findLane");
  1075. var drawArrow = /* @__PURE__ */ __name((svg, commitA, commitB, allCommits) => {
  1076. const p1 = commitPos.get(commitA.id);
  1077. const p2 = commitPos.get(commitB.id);
  1078. if (p1 === void 0 || p2 === void 0) {
  1079. throw new Error(`Commit positions not found for commits ${commitA.id} and ${commitB.id}`);
  1080. }
  1081. const arrowNeedsRerouting = shouldRerouteArrow(commitA, commitB, p1, p2, allCommits);
  1082. let arc = "";
  1083. let arc2 = "";
  1084. let radius = 0;
  1085. let offset = 0;
  1086. let colorClassNum = branchPos.get(commitB.branch)?.index;
  1087. if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
  1088. colorClassNum = branchPos.get(commitA.branch)?.index;
  1089. }
  1090. let lineDef;
  1091. if (arrowNeedsRerouting) {
  1092. arc = "A 10 10, 0, 0, 0,";
  1093. arc2 = "A 10 10, 0, 0, 1,";
  1094. radius = 10;
  1095. offset = 10;
  1096. const lineY = p1.y < p2.y ? findLane(p1.y, p2.y) : findLane(p2.y, p1.y);
  1097. const lineX = p1.x < p2.x ? findLane(p1.x, p2.x) : findLane(p2.x, p1.x);
  1098. if (dir === "TB") {
  1099. if (p1.x < p2.x) {
  1100. lineDef = `M ${p1.x} ${p1.y} L ${lineX - radius} ${p1.y} ${arc2} ${lineX} ${p1.y + offset} L ${lineX} ${p2.y - radius} ${arc} ${lineX + offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1101. } else {
  1102. colorClassNum = branchPos.get(commitA.branch)?.index;
  1103. lineDef = `M ${p1.x} ${p1.y} L ${lineX + radius} ${p1.y} ${arc} ${lineX} ${p1.y + offset} L ${lineX} ${p2.y - radius} ${arc2} ${lineX - offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1104. }
  1105. } else if (dir === "BT") {
  1106. if (p1.x < p2.x) {
  1107. lineDef = `M ${p1.x} ${p1.y} L ${lineX - radius} ${p1.y} ${arc} ${lineX} ${p1.y - offset} L ${lineX} ${p2.y + radius} ${arc2} ${lineX + offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1108. } else {
  1109. colorClassNum = branchPos.get(commitA.branch)?.index;
  1110. lineDef = `M ${p1.x} ${p1.y} L ${lineX + radius} ${p1.y} ${arc2} ${lineX} ${p1.y - offset} L ${lineX} ${p2.y + radius} ${arc} ${lineX - offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1111. }
  1112. } else {
  1113. if (p1.y < p2.y) {
  1114. lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY - radius} ${arc} ${p1.x + offset} ${lineY} L ${p2.x - radius} ${lineY} ${arc2} ${p2.x} ${lineY + offset} L ${p2.x} ${p2.y}`;
  1115. } else {
  1116. colorClassNum = branchPos.get(commitA.branch)?.index;
  1117. lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${lineY + radius} ${arc2} ${p1.x + offset} ${lineY} L ${p2.x - radius} ${lineY} ${arc} ${p2.x} ${lineY - offset} L ${p2.x} ${p2.y}`;
  1118. }
  1119. }
  1120. } else {
  1121. arc = "A 20 20, 0, 0, 0,";
  1122. arc2 = "A 20 20, 0, 0, 1,";
  1123. radius = 20;
  1124. offset = 20;
  1125. if (dir === "TB") {
  1126. if (p1.x < p2.x) {
  1127. if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
  1128. lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1129. } else {
  1130. lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc2} ${p2.x} ${p1.y + offset} L ${p2.x} ${p2.y}`;
  1131. }
  1132. }
  1133. if (p1.x > p2.x) {
  1134. arc = "A 20 20, 0, 0, 0,";
  1135. arc2 = "A 20 20, 0, 0, 1,";
  1136. radius = 20;
  1137. offset = 20;
  1138. if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
  1139. lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc2} ${p1.x - offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1140. } else {
  1141. lineDef = `M ${p1.x} ${p1.y} L ${p2.x + radius} ${p1.y} ${arc} ${p2.x} ${p1.y + offset} L ${p2.x} ${p2.y}`;
  1142. }
  1143. }
  1144. if (p1.x === p2.x) {
  1145. lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
  1146. }
  1147. } else if (dir === "BT") {
  1148. if (p1.x < p2.x) {
  1149. if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
  1150. lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y + radius} ${arc2} ${p1.x + offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1151. } else {
  1152. lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${p1.y - offset} L ${p2.x} ${p2.y}`;
  1153. }
  1154. }
  1155. if (p1.x > p2.x) {
  1156. arc = "A 20 20, 0, 0, 0,";
  1157. arc2 = "A 20 20, 0, 0, 1,";
  1158. radius = 20;
  1159. offset = 20;
  1160. if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
  1161. lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y + radius} ${arc} ${p1.x - offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1162. } else {
  1163. lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${p1.y - offset} L ${p2.x} ${p2.y}`;
  1164. }
  1165. }
  1166. if (p1.x === p2.x) {
  1167. lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
  1168. }
  1169. } else {
  1170. if (p1.y < p2.y) {
  1171. if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
  1172. lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc2} ${p2.x} ${p1.y + offset} L ${p2.x} ${p2.y}`;
  1173. } else {
  1174. lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y - radius} ${arc} ${p1.x + offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1175. }
  1176. }
  1177. if (p1.y > p2.y) {
  1178. if (commitB.type === commitType.MERGE && commitA.id !== commitB.parents[0]) {
  1179. lineDef = `M ${p1.x} ${p1.y} L ${p2.x - radius} ${p1.y} ${arc} ${p2.x} ${p1.y - offset} L ${p2.x} ${p2.y}`;
  1180. } else {
  1181. lineDef = `M ${p1.x} ${p1.y} L ${p1.x} ${p2.y + radius} ${arc2} ${p1.x + offset} ${p2.y} L ${p2.x} ${p2.y}`;
  1182. }
  1183. }
  1184. if (p1.y === p2.y) {
  1185. lineDef = `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`;
  1186. }
  1187. }
  1188. }
  1189. if (lineDef === void 0) {
  1190. throw new Error("Line definition not found");
  1191. }
  1192. svg.append("path").attr("d", lineDef).attr("class", "arrow arrow" + colorClassNum % THEME_COLOR_LIMIT);
  1193. }, "drawArrow");
  1194. var drawArrows = /* @__PURE__ */ __name((svg, commits) => {
  1195. const gArrows = svg.append("g").attr("class", "commit-arrows");
  1196. [...commits.keys()].forEach((key) => {
  1197. const commit2 = commits.get(key);
  1198. if (commit2.parents && commit2.parents.length > 0) {
  1199. commit2.parents.forEach((parent) => {
  1200. drawArrow(gArrows, commits.get(parent), commit2, commits);
  1201. });
  1202. }
  1203. });
  1204. }, "drawArrows");
  1205. var drawBranches = /* @__PURE__ */ __name((svg, branches) => {
  1206. const g = svg.append("g");
  1207. branches.forEach((branch2, index) => {
  1208. const adjustIndexForTheme = index % THEME_COLOR_LIMIT;
  1209. const pos = branchPos.get(branch2.name)?.pos;
  1210. if (pos === void 0) {
  1211. throw new Error(`Position not found for branch ${branch2.name}`);
  1212. }
  1213. const line = g.append("line");
  1214. line.attr("x1", 0);
  1215. line.attr("y1", pos);
  1216. line.attr("x2", maxPos);
  1217. line.attr("y2", pos);
  1218. line.attr("class", "branch branch" + adjustIndexForTheme);
  1219. if (dir === "TB") {
  1220. line.attr("y1", defaultPos);
  1221. line.attr("x1", pos);
  1222. line.attr("y2", maxPos);
  1223. line.attr("x2", pos);
  1224. } else if (dir === "BT") {
  1225. line.attr("y1", maxPos);
  1226. line.attr("x1", pos);
  1227. line.attr("y2", defaultPos);
  1228. line.attr("x2", pos);
  1229. }
  1230. lanes.push(pos);
  1231. const name = branch2.name;
  1232. const labelElement = drawText(name);
  1233. const bkg = g.insert("rect");
  1234. const branchLabel = g.insert("g").attr("class", "branchLabel");
  1235. const label = branchLabel.insert("g").attr("class", "label branch-label" + adjustIndexForTheme);
  1236. label.node().appendChild(labelElement);
  1237. const bbox = labelElement.getBBox();
  1238. bkg.attr("class", "branchLabelBkg label" + adjustIndexForTheme).attr("rx", 4).attr("ry", 4).attr("x", -bbox.width - 4 - (DEFAULT_GITGRAPH_CONFIG2?.rotateCommitLabel === true ? 30 : 0)).attr("y", -bbox.height / 2 + 8).attr("width", bbox.width + 18).attr("height", bbox.height + 4);
  1239. label.attr(
  1240. "transform",
  1241. "translate(" + (-bbox.width - 14 - (DEFAULT_GITGRAPH_CONFIG2?.rotateCommitLabel === true ? 30 : 0)) + ", " + (pos - bbox.height / 2 - 1) + ")"
  1242. );
  1243. if (dir === "TB") {
  1244. bkg.attr("x", pos - bbox.width / 2 - 10).attr("y", 0);
  1245. label.attr("transform", "translate(" + (pos - bbox.width / 2 - 5) + ", 0)");
  1246. } else if (dir === "BT") {
  1247. bkg.attr("x", pos - bbox.width / 2 - 10).attr("y", maxPos);
  1248. label.attr("transform", "translate(" + (pos - bbox.width / 2 - 5) + ", " + maxPos + ")");
  1249. } else {
  1250. bkg.attr("transform", "translate(-19, " + (pos - bbox.height / 2) + ")");
  1251. }
  1252. });
  1253. }, "drawBranches");
  1254. var setBranchPosition = /* @__PURE__ */ __name(function(name, pos, index, bbox, rotateCommitLabel) {
  1255. branchPos.set(name, { pos, index });
  1256. pos += 50 + (rotateCommitLabel ? 40 : 0) + (dir === "TB" || dir === "BT" ? bbox.width / 2 : 0);
  1257. return pos;
  1258. }, "setBranchPosition");
  1259. var draw = /* @__PURE__ */ __name(function(txt, id, ver, diagObj) {
  1260. clear3();
  1261. log.debug("in gitgraph renderer", txt + "\n", "id:", id, ver);
  1262. if (!DEFAULT_GITGRAPH_CONFIG2) {
  1263. throw new Error("GitGraph config not found");
  1264. }
  1265. const rotateCommitLabel = DEFAULT_GITGRAPH_CONFIG2.rotateCommitLabel ?? false;
  1266. const db2 = diagObj.db;
  1267. allCommitsDict = db2.getCommits();
  1268. const branches = db2.getBranchesAsObjArray();
  1269. dir = db2.getDirection();
  1270. const diagram2 = select(`[id="${id}"]`);
  1271. let pos = 0;
  1272. branches.forEach((branch2, index) => {
  1273. const labelElement = drawText(branch2.name);
  1274. const g = diagram2.append("g");
  1275. const branchLabel = g.insert("g").attr("class", "branchLabel");
  1276. const label = branchLabel.insert("g").attr("class", "label branch-label");
  1277. label.node()?.appendChild(labelElement);
  1278. const bbox = labelElement.getBBox();
  1279. pos = setBranchPosition(branch2.name, pos, index, bbox, rotateCommitLabel);
  1280. label.remove();
  1281. branchLabel.remove();
  1282. g.remove();
  1283. });
  1284. drawCommits(diagram2, allCommitsDict, false);
  1285. if (DEFAULT_GITGRAPH_CONFIG2.showBranches) {
  1286. drawBranches(diagram2, branches);
  1287. }
  1288. drawArrows(diagram2, allCommitsDict);
  1289. drawCommits(diagram2, allCommitsDict, true);
  1290. utils_default.insertTitle(
  1291. diagram2,
  1292. "gitTitleText",
  1293. DEFAULT_GITGRAPH_CONFIG2.titleTopMargin ?? 0,
  1294. db2.getDiagramTitle()
  1295. );
  1296. setupGraphViewbox(
  1297. void 0,
  1298. diagram2,
  1299. DEFAULT_GITGRAPH_CONFIG2.diagramPadding,
  1300. DEFAULT_GITGRAPH_CONFIG2.useMaxWidth
  1301. );
  1302. }, "draw");
  1303. var gitGraphRenderer_default = {
  1304. draw
  1305. };
  1306. if (void 0) {
  1307. const { it, expect, describe } = void 0;
  1308. describe("drawText", () => {
  1309. it("should drawText", () => {
  1310. const svgLabel = drawText("main");
  1311. expect(svgLabel).toBeDefined();
  1312. expect(svgLabel.children[0].innerHTML).toBe("main");
  1313. });
  1314. });
  1315. describe("branchPosition", () => {
  1316. const bbox = {
  1317. x: 0,
  1318. y: 0,
  1319. width: 10,
  1320. height: 10,
  1321. top: 0,
  1322. right: 0,
  1323. bottom: 0,
  1324. left: 0,
  1325. toJSON: /* @__PURE__ */ __name(() => "", "toJSON")
  1326. };
  1327. it("should setBranchPositions LR with two branches", () => {
  1328. dir = "LR";
  1329. const pos = setBranchPosition("main", 0, 0, bbox, true);
  1330. expect(pos).toBe(90);
  1331. expect(branchPos.get("main")).toEqual({ pos: 0, index: 0 });
  1332. const posNext = setBranchPosition("develop", pos, 1, bbox, true);
  1333. expect(posNext).toBe(180);
  1334. expect(branchPos.get("develop")).toEqual({ pos, index: 1 });
  1335. });
  1336. it("should setBranchPositions TB with two branches", () => {
  1337. dir = "TB";
  1338. bbox.width = 34.9921875;
  1339. const pos = setBranchPosition("main", 0, 0, bbox, true);
  1340. expect(pos).toBe(107.49609375);
  1341. expect(branchPos.get("main")).toEqual({ pos: 0, index: 0 });
  1342. bbox.width = 56.421875;
  1343. const posNext = setBranchPosition("develop", pos, 1, bbox, true);
  1344. expect(posNext).toBe(225.70703125);
  1345. expect(branchPos.get("develop")).toEqual({ pos, index: 1 });
  1346. });
  1347. });
  1348. describe("commitPosition", () => {
  1349. const commits = /* @__PURE__ */ new Map([
  1350. [
  1351. "commitZero",
  1352. {
  1353. id: "ZERO",
  1354. message: "",
  1355. seq: 0,
  1356. type: commitType.NORMAL,
  1357. tags: [],
  1358. parents: [],
  1359. branch: "main"
  1360. }
  1361. ],
  1362. [
  1363. "commitA",
  1364. {
  1365. id: "A",
  1366. message: "",
  1367. seq: 1,
  1368. type: commitType.NORMAL,
  1369. tags: [],
  1370. parents: ["ZERO"],
  1371. branch: "feature"
  1372. }
  1373. ],
  1374. [
  1375. "commitB",
  1376. {
  1377. id: "B",
  1378. message: "",
  1379. seq: 2,
  1380. type: commitType.NORMAL,
  1381. tags: [],
  1382. parents: ["A"],
  1383. branch: "feature"
  1384. }
  1385. ],
  1386. [
  1387. "commitM",
  1388. {
  1389. id: "M",
  1390. message: "merged branch feature into main",
  1391. seq: 3,
  1392. type: commitType.MERGE,
  1393. tags: [],
  1394. parents: ["ZERO", "B"],
  1395. branch: "main",
  1396. customId: true
  1397. }
  1398. ],
  1399. [
  1400. "commitC",
  1401. {
  1402. id: "C",
  1403. message: "",
  1404. seq: 4,
  1405. type: commitType.NORMAL,
  1406. tags: [],
  1407. parents: ["ZERO"],
  1408. branch: "release"
  1409. }
  1410. ],
  1411. [
  1412. "commit5_8928ea0",
  1413. {
  1414. id: "5-8928ea0",
  1415. message: "cherry-picked [object Object] into release",
  1416. seq: 5,
  1417. type: commitType.CHERRY_PICK,
  1418. tags: [],
  1419. parents: ["C", "M"],
  1420. branch: "release"
  1421. }
  1422. ],
  1423. [
  1424. "commitD",
  1425. {
  1426. id: "D",
  1427. message: "",
  1428. seq: 6,
  1429. type: commitType.NORMAL,
  1430. tags: [],
  1431. parents: ["5-8928ea0"],
  1432. branch: "release"
  1433. }
  1434. ],
  1435. [
  1436. "commit7_ed848ba",
  1437. {
  1438. id: "7-ed848ba",
  1439. message: "cherry-picked [object Object] into release",
  1440. seq: 7,
  1441. type: commitType.CHERRY_PICK,
  1442. tags: [],
  1443. parents: ["D", "M"],
  1444. branch: "release"
  1445. }
  1446. ]
  1447. ]);
  1448. let pos = 0;
  1449. branchPos.set("main", { pos: 0, index: 0 });
  1450. branchPos.set("feature", { pos: 107.49609375, index: 1 });
  1451. branchPos.set("release", { pos: 224.03515625, index: 2 });
  1452. describe("TB", () => {
  1453. pos = 30;
  1454. dir = "TB";
  1455. const expectedCommitPositionTB = /* @__PURE__ */ new Map([
  1456. ["commitZero", { x: 0, y: 40, posWithOffset: 40 }],
  1457. ["commitA", { x: 107.49609375, y: 90, posWithOffset: 90 }],
  1458. ["commitB", { x: 107.49609375, y: 140, posWithOffset: 140 }],
  1459. ["commitM", { x: 0, y: 190, posWithOffset: 190 }],
  1460. ["commitC", { x: 224.03515625, y: 240, posWithOffset: 240 }],
  1461. ["commit5_8928ea0", { x: 224.03515625, y: 290, posWithOffset: 290 }],
  1462. ["commitD", { x: 224.03515625, y: 340, posWithOffset: 340 }],
  1463. ["commit7_ed848ba", { x: 224.03515625, y: 390, posWithOffset: 390 }]
  1464. ]);
  1465. commits.forEach((commit2, key) => {
  1466. it(`should give the correct position for commit ${key}`, () => {
  1467. const position = getCommitPosition(commit2, pos, false);
  1468. expect(position).toEqual(expectedCommitPositionTB.get(key));
  1469. pos += 50;
  1470. });
  1471. });
  1472. });
  1473. describe("LR", () => {
  1474. let pos2 = 30;
  1475. dir = "LR";
  1476. const expectedCommitPositionLR = /* @__PURE__ */ new Map([
  1477. ["commitZero", { x: 0, y: 40, posWithOffset: 40 }],
  1478. ["commitA", { x: 107.49609375, y: 90, posWithOffset: 90 }],
  1479. ["commitB", { x: 107.49609375, y: 140, posWithOffset: 140 }],
  1480. ["commitM", { x: 0, y: 190, posWithOffset: 190 }],
  1481. ["commitC", { x: 224.03515625, y: 240, posWithOffset: 240 }],
  1482. ["commit5_8928ea0", { x: 224.03515625, y: 290, posWithOffset: 290 }],
  1483. ["commitD", { x: 224.03515625, y: 340, posWithOffset: 340 }],
  1484. ["commit7_ed848ba", { x: 224.03515625, y: 390, posWithOffset: 390 }]
  1485. ]);
  1486. commits.forEach((commit2, key) => {
  1487. it(`should give the correct position for commit ${key}`, () => {
  1488. const position = getCommitPosition(commit2, pos2, false);
  1489. expect(position).toEqual(expectedCommitPositionLR.get(key));
  1490. pos2 += 50;
  1491. });
  1492. });
  1493. });
  1494. describe("getCommitClassType", () => {
  1495. const expectedCommitClassType = /* @__PURE__ */ new Map([
  1496. ["commitZero", "commit-normal"],
  1497. ["commitA", "commit-normal"],
  1498. ["commitB", "commit-normal"],
  1499. ["commitM", "commit-merge"],
  1500. ["commitC", "commit-normal"],
  1501. ["commit5_8928ea0", "commit-cherry-pick"],
  1502. ["commitD", "commit-normal"],
  1503. ["commit7_ed848ba", "commit-cherry-pick"]
  1504. ]);
  1505. commits.forEach((commit2, key) => {
  1506. it(`should give the correct class type for commit ${key}`, () => {
  1507. const classType = getCommitClassType(commit2);
  1508. expect(classType).toBe(expectedCommitClassType.get(key));
  1509. });
  1510. });
  1511. });
  1512. });
  1513. describe("building BT parallel commit diagram", () => {
  1514. const commits = /* @__PURE__ */ new Map([
  1515. [
  1516. "1-abcdefg",
  1517. {
  1518. id: "1-abcdefg",
  1519. message: "",
  1520. seq: 0,
  1521. type: 0,
  1522. tags: [],
  1523. parents: [],
  1524. branch: "main"
  1525. }
  1526. ],
  1527. [
  1528. "2-abcdefg",
  1529. {
  1530. id: "2-abcdefg",
  1531. message: "",
  1532. seq: 1,
  1533. type: 0,
  1534. tags: [],
  1535. parents: ["1-abcdefg"],
  1536. branch: "main"
  1537. }
  1538. ],
  1539. [
  1540. "3-abcdefg",
  1541. {
  1542. id: "3-abcdefg",
  1543. message: "",
  1544. seq: 2,
  1545. type: 0,
  1546. tags: [],
  1547. parents: ["2-abcdefg"],
  1548. branch: "develop"
  1549. }
  1550. ],
  1551. [
  1552. "4-abcdefg",
  1553. {
  1554. id: "4-abcdefg",
  1555. message: "",
  1556. seq: 3,
  1557. type: 0,
  1558. tags: [],
  1559. parents: ["3-abcdefg"],
  1560. branch: "develop"
  1561. }
  1562. ],
  1563. [
  1564. "5-abcdefg",
  1565. {
  1566. id: "5-abcdefg",
  1567. message: "",
  1568. seq: 4,
  1569. type: 0,
  1570. tags: [],
  1571. parents: ["2-abcdefg"],
  1572. branch: "feature"
  1573. }
  1574. ],
  1575. [
  1576. "6-abcdefg",
  1577. {
  1578. id: "6-abcdefg",
  1579. message: "",
  1580. seq: 5,
  1581. type: 0,
  1582. tags: [],
  1583. parents: ["5-abcdefg"],
  1584. branch: "feature"
  1585. }
  1586. ],
  1587. [
  1588. "7-abcdefg",
  1589. {
  1590. id: "7-abcdefg",
  1591. message: "",
  1592. seq: 6,
  1593. type: 0,
  1594. tags: [],
  1595. parents: ["2-abcdefg"],
  1596. branch: "main"
  1597. }
  1598. ],
  1599. [
  1600. "8-abcdefg",
  1601. {
  1602. id: "8-abcdefg",
  1603. message: "",
  1604. seq: 7,
  1605. type: 0,
  1606. tags: [],
  1607. parents: ["7-abcdefg"],
  1608. branch: "main"
  1609. }
  1610. ]
  1611. ]);
  1612. const expectedCommitPosition = /* @__PURE__ */ new Map([
  1613. ["1-abcdefg", { x: 0, y: 40 }],
  1614. ["2-abcdefg", { x: 0, y: 90 }],
  1615. ["3-abcdefg", { x: 107.49609375, y: 140 }],
  1616. ["4-abcdefg", { x: 107.49609375, y: 190 }],
  1617. ["5-abcdefg", { x: 225.70703125, y: 140 }],
  1618. ["6-abcdefg", { x: 225.70703125, y: 190 }],
  1619. ["7-abcdefg", { x: 0, y: 140 }],
  1620. ["8-abcdefg", { x: 0, y: 190 }]
  1621. ]);
  1622. const expectedCommitPositionAfterParallel = /* @__PURE__ */ new Map([
  1623. ["1-abcdefg", { x: 0, y: 210 }],
  1624. ["2-abcdefg", { x: 0, y: 160 }],
  1625. ["3-abcdefg", { x: 107.49609375, y: 110 }],
  1626. ["4-abcdefg", { x: 107.49609375, y: 60 }],
  1627. ["5-abcdefg", { x: 225.70703125, y: 110 }],
  1628. ["6-abcdefg", { x: 225.70703125, y: 60 }],
  1629. ["7-abcdefg", { x: 0, y: 110 }],
  1630. ["8-abcdefg", { x: 0, y: 60 }]
  1631. ]);
  1632. const expectedCommitCurrentPosition = /* @__PURE__ */ new Map([
  1633. ["1-abcdefg", 30],
  1634. ["2-abcdefg", 80],
  1635. ["3-abcdefg", 130],
  1636. ["4-abcdefg", 180],
  1637. ["5-abcdefg", 130],
  1638. ["6-abcdefg", 180],
  1639. ["7-abcdefg", 130],
  1640. ["8-abcdefg", 180]
  1641. ]);
  1642. const sortedKeys = [...expectedCommitPosition.keys()];
  1643. it("should get the correct commit position and current position", () => {
  1644. dir = "BT";
  1645. let curPos = 30;
  1646. commitPos.clear();
  1647. branchPos.clear();
  1648. branchPos.set("main", { pos: 0, index: 0 });
  1649. branchPos.set("develop", { pos: 107.49609375, index: 1 });
  1650. branchPos.set("feature", { pos: 225.70703125, index: 2 });
  1651. DEFAULT_GITGRAPH_CONFIG2.parallelCommits = true;
  1652. commits.forEach((commit2, key) => {
  1653. if (commit2.parents.length > 0) {
  1654. curPos = calculateCommitPosition(commit2);
  1655. }
  1656. const position = setCommitPosition(commit2, curPos);
  1657. expect(position).toEqual(expectedCommitPosition.get(key));
  1658. expect(curPos).toEqual(expectedCommitCurrentPosition.get(key));
  1659. });
  1660. });
  1661. it("should get the correct commit position after parallel commits", () => {
  1662. commitPos.clear();
  1663. branchPos.clear();
  1664. dir = "BT";
  1665. const curPos = 30;
  1666. commitPos.clear();
  1667. branchPos.clear();
  1668. branchPos.set("main", { pos: 0, index: 0 });
  1669. branchPos.set("develop", { pos: 107.49609375, index: 1 });
  1670. branchPos.set("feature", { pos: 225.70703125, index: 2 });
  1671. setParallelBTPos(sortedKeys, commits, curPos);
  1672. sortedKeys.forEach((commit2) => {
  1673. const position = commitPos.get(commit2);
  1674. expect(position).toEqual(expectedCommitPositionAfterParallel.get(commit2));
  1675. });
  1676. });
  1677. });
  1678. DEFAULT_GITGRAPH_CONFIG2.parallelCommits = false;
  1679. it("add", () => {
  1680. commitPos.set("parent1", { x: 1, y: 1 });
  1681. commitPos.set("parent2", { x: 2, y: 2 });
  1682. commitPos.set("parent3", { x: 3, y: 3 });
  1683. dir = "LR";
  1684. const parents = ["parent1", "parent2", "parent3"];
  1685. const closestParent = findClosestParent(parents);
  1686. expect(closestParent).toBe("parent3");
  1687. commitPos.clear();
  1688. });
  1689. }
  1690. // src/diagrams/git/styles.js
  1691. var getStyles = /* @__PURE__ */ __name((options) => `
  1692. .commit-id,
  1693. .commit-msg,
  1694. .branch-label {
  1695. fill: lightgrey;
  1696. color: lightgrey;
  1697. font-family: 'trebuchet ms', verdana, arial, sans-serif;
  1698. font-family: var(--mermaid-font-family);
  1699. }
  1700. ${[0, 1, 2, 3, 4, 5, 6, 7].map(
  1701. (i) => `
  1702. .branch-label${i} { fill: ${options["gitBranchLabel" + i]}; }
  1703. .commit${i} { stroke: ${options["git" + i]}; fill: ${options["git" + i]}; }
  1704. .commit-highlight${i} { stroke: ${options["gitInv" + i]}; fill: ${options["gitInv" + i]}; }
  1705. .label${i} { fill: ${options["git" + i]}; }
  1706. .arrow${i} { stroke: ${options["git" + i]}; }
  1707. `
  1708. ).join("\n")}
  1709. .branch {
  1710. stroke-width: 1;
  1711. stroke: ${options.lineColor};
  1712. stroke-dasharray: 2;
  1713. }
  1714. .commit-label { font-size: ${options.commitLabelFontSize}; fill: ${options.commitLabelColor};}
  1715. .commit-label-bkg { font-size: ${options.commitLabelFontSize}; fill: ${options.commitLabelBackground}; opacity: 0.5; }
  1716. .tag-label { font-size: ${options.tagLabelFontSize}; fill: ${options.tagLabelColor};}
  1717. .tag-label-bkg { fill: ${options.tagLabelBackground}; stroke: ${options.tagLabelBorder}; }
  1718. .tag-hole { fill: ${options.textColor}; }
  1719. .commit-merge {
  1720. stroke: ${options.primaryColor};
  1721. fill: ${options.primaryColor};
  1722. }
  1723. .commit-reverse {
  1724. stroke: ${options.primaryColor};
  1725. fill: ${options.primaryColor};
  1726. stroke-width: 3;
  1727. }
  1728. .commit-highlight-outer {
  1729. }
  1730. .commit-highlight-inner {
  1731. stroke: ${options.primaryColor};
  1732. fill: ${options.primaryColor};
  1733. }
  1734. .arrow { stroke-width: 8; stroke-linecap: round; fill: none}
  1735. .gitTitleText {
  1736. text-anchor: middle;
  1737. font-size: 18px;
  1738. fill: ${options.textColor};
  1739. }
  1740. `, "getStyles");
  1741. var styles_default = getStyles;
  1742. // src/diagrams/git/gitGraphDiagram.ts
  1743. var diagram = {
  1744. parser,
  1745. db,
  1746. renderer: gitGraphRenderer_default,
  1747. styles: styles_default
  1748. };
  1749. export {
  1750. diagram
  1751. };