mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-26 10:49:38 +02:00
added parser unit tests and organized config in gitGraphAst.ts
This commit is contained in:
@@ -1,74 +0,0 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { parser } from './gitGraphParser.js';
|
||||
import { db } from './gitGraphAst.js';
|
||||
|
||||
const parseInput = async (input: string) => {
|
||||
await parser.parse(input);
|
||||
};
|
||||
|
||||
const spyOn = vi.spyOn;
|
||||
|
||||
describe('GitGraph Parsing', function () {
|
||||
beforeEach(() => {
|
||||
db.clear();
|
||||
});
|
||||
it('should parse a default commit statement', async () => {
|
||||
const input = `gitGraph:
|
||||
commit
|
||||
`;
|
||||
const commitSpy = spyOn(db, 'commit');
|
||||
await parseInput(input);
|
||||
|
||||
expect(commitSpy).toHaveBeenCalledWith('', undefined, 0, []);
|
||||
commitSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should parse a basic branch statement with just a name', async () => {
|
||||
const input = `gitGraph:
|
||||
branch newBranch
|
||||
`;
|
||||
const branchSpy = spyOn(db, 'branch');
|
||||
await parseInput(input);
|
||||
expect(branchSpy).toHaveBeenCalledWith('newBranch', 0);
|
||||
branchSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should parse a basic checkout statement', async () => {
|
||||
const input = `gitGraph:
|
||||
branch newBranch
|
||||
checkout newBranch
|
||||
`;
|
||||
const checkoutSpy = spyOn(db, 'checkout');
|
||||
await parseInput(input);
|
||||
expect(checkoutSpy).toHaveBeenCalledWith('newBranch');
|
||||
checkoutSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should parse a basic merge statement', async () => {
|
||||
const input = `gitGraph:
|
||||
commit
|
||||
branch newBranch
|
||||
checkout newBranch
|
||||
commit
|
||||
checkout main
|
||||
merge newBranch`;
|
||||
const mergeSpy = spyOn(db, 'merge');
|
||||
await parseInput(input);
|
||||
expect(mergeSpy).toHaveBeenCalledWith('newBranch', '', undefined, []);
|
||||
mergeSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should parse cherry-picking', async () => {
|
||||
const input = `gitGraph
|
||||
commit id: "ZERO"
|
||||
branch develop
|
||||
commit id:"A"
|
||||
checkout main
|
||||
cherry-pick id:"A"
|
||||
`;
|
||||
const cherryPickSpy = spyOn(db, 'cherryPick');
|
||||
await parseInput(input);
|
||||
expect(cherryPickSpy).toHaveBeenCalledWith('A', '', undefined, undefined);
|
||||
cherryPickSpy.mockRestore();
|
||||
});
|
||||
});
|
@@ -11,9 +11,10 @@ import type {
|
||||
MergeAst,
|
||||
CommitAst,
|
||||
BranchAst,
|
||||
GitGraphDBProvider,
|
||||
} from './gitGraphTypes.js';
|
||||
|
||||
const populate = (ast: GitGraph) => {
|
||||
const populate = (ast: GitGraph, db: GitGraphDBProvider) => {
|
||||
populateCommonDb(ast, db);
|
||||
// @ts-ignore: this wont exist if the direction is not specified
|
||||
if (ast.dir) {
|
||||
@@ -21,71 +22,107 @@ const populate = (ast: GitGraph) => {
|
||||
db.setDirection(ast.dir);
|
||||
}
|
||||
for (const statement of ast.statements) {
|
||||
parseStatement(statement);
|
||||
parseStatement(statement, db);
|
||||
}
|
||||
};
|
||||
|
||||
const parseStatement = (statement: any) => {
|
||||
switch (statement.$type) {
|
||||
case 'Commit':
|
||||
parseCommit(statement);
|
||||
break;
|
||||
case 'Branch':
|
||||
parseBranch(statement);
|
||||
break;
|
||||
case 'Merge':
|
||||
parseMerge(statement);
|
||||
break;
|
||||
case 'Checkout':
|
||||
parseCheckout(statement);
|
||||
break;
|
||||
case 'CherryPicking':
|
||||
parseCherryPicking(statement);
|
||||
break;
|
||||
default:
|
||||
log.error(`Unknown statement type`);
|
||||
const parseStatement = (statement: any, db: GitGraphDBProvider) => {
|
||||
const parsers: Record<string, (stmt: any) => void> = {
|
||||
Commit: (stmt) => db.commit(...parseCommit(stmt)),
|
||||
Branch: (stmt) => db.branch(...parseBranch(stmt)),
|
||||
Merge: (stmt) => db.merge(...parseMerge(stmt)),
|
||||
Checkout: (stmt) => db.checkout(parseCheckout(stmt)),
|
||||
CherryPicking: (stmt) => db.cherryPick(...parseCherryPicking(stmt)),
|
||||
};
|
||||
|
||||
const parser = parsers[statement.$type];
|
||||
if (parser) {
|
||||
parser(statement);
|
||||
} else {
|
||||
log.error(`Unknown statement type: ${statement.$type}`);
|
||||
}
|
||||
};
|
||||
|
||||
const parseCommit = (commit: CommitAst) => {
|
||||
const parseCommit = (commit: CommitAst): [string, string, number, string[] | undefined] => {
|
||||
const id = commit.id;
|
||||
const message = commit.message ?? '';
|
||||
const type = commit.type !== undefined ? commitType[commit.type] : commitType.NORMAL;
|
||||
const tags = commit.tags ?? undefined;
|
||||
|
||||
db.commit(message, id, type, tags);
|
||||
return [message, id, type, tags];
|
||||
};
|
||||
|
||||
const parseBranch = (branch: BranchAst) => {
|
||||
const parseBranch = (branch: BranchAst): [string, number] => {
|
||||
const name = branch.name;
|
||||
const order = branch.order ?? 0;
|
||||
db.branch(name, order);
|
||||
return [name, order];
|
||||
};
|
||||
|
||||
const parseMerge = (merge: MergeAst) => {
|
||||
const parseMerge = (
|
||||
merge: MergeAst
|
||||
): [string, string, number | undefined, string[] | undefined] => {
|
||||
const branch = merge.branch;
|
||||
const id = merge.id ?? '';
|
||||
const type = merge.type !== undefined ? commitType[merge.type] : undefined;
|
||||
const tags = merge.tags ?? undefined;
|
||||
db.merge(branch, id, type, tags);
|
||||
return [branch, id, type, tags];
|
||||
};
|
||||
|
||||
const parseCheckout = (checkout: CheckoutAst) => {
|
||||
const parseCheckout = (checkout: CheckoutAst): string => {
|
||||
const branch = checkout.branch;
|
||||
db.checkout(branch);
|
||||
return branch;
|
||||
};
|
||||
|
||||
const parseCherryPicking = (cherryPicking: CherryPickingAst) => {
|
||||
const parseCherryPicking = (
|
||||
cherryPicking: CherryPickingAst
|
||||
): [string, string, string[] | undefined, string] => {
|
||||
const id = cherryPicking.id;
|
||||
const tags = cherryPicking.tags?.length === 0 ? undefined : cherryPicking.tags;
|
||||
const parent = cherryPicking.parent;
|
||||
db.cherryPick(id, '', tags, parent);
|
||||
return [id, '', tags, parent];
|
||||
};
|
||||
|
||||
export const parser: ParserDefinition = {
|
||||
parse: async (input: string): Promise<void> => {
|
||||
const ast: GitGraph = await parse('gitGraph', input);
|
||||
log.debug(ast);
|
||||
populate(ast);
|
||||
populate(ast, db);
|
||||
},
|
||||
};
|
||||
|
||||
if (import.meta.vitest) {
|
||||
const { it, expect, describe } = import.meta.vitest;
|
||||
|
||||
const mockDB: GitGraphDBProvider = {
|
||||
commitType: commitType,
|
||||
setDirection: vi.fn(),
|
||||
commit: vi.fn(),
|
||||
branch: vi.fn(),
|
||||
merge: vi.fn(),
|
||||
cherryPick: vi.fn(),
|
||||
checkout: vi.fn(),
|
||||
};
|
||||
|
||||
describe('GitGraph Parser', () => {
|
||||
it('should parse a commit statement', () => {
|
||||
const commit = {
|
||||
$type: 'Commit',
|
||||
id: '1',
|
||||
message: 'test',
|
||||
tags: ['tag1', 'tag2'],
|
||||
type: 'NORMAL',
|
||||
};
|
||||
parseStatement(commit, mockDB);
|
||||
expect(mockDB.commit).toHaveBeenCalledWith('test', '1', 0, ['tag1', 'tag2']);
|
||||
});
|
||||
it('should parse a branch statement', () => {
|
||||
const branch = {
|
||||
$type: 'Branch',
|
||||
name: 'newBranch',
|
||||
order: 1,
|
||||
};
|
||||
parseStatement(branch, mockDB);
|
||||
expect(mockDB.branch).toHaveBeenCalledWith('newBranch', 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@@ -4,7 +4,12 @@ import { log } from '../../logger.js';
|
||||
import utils from '../../utils.js';
|
||||
import type { DrawDefinition } from '../../diagram-api/types.js';
|
||||
import type d3 from 'd3';
|
||||
import type { CommitType, Commit, GitGraphDB, DiagramOrientation } from './gitGraphTypes.js';
|
||||
import type {
|
||||
CommitType,
|
||||
Commit,
|
||||
GitGraphDBRenderProvider,
|
||||
DiagramOrientation,
|
||||
} from './gitGraphTypes.js';
|
||||
import type { GitGraphDiagramConfig } from '../../config.type.js';
|
||||
|
||||
let allCommitsDict = new Map();
|
||||
@@ -770,7 +775,9 @@ const drawArrow = (
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lineDef === undefined) {
|
||||
throw new Error('Line definition not found');
|
||||
}
|
||||
svg
|
||||
.append('path')
|
||||
.attr('d', lineDef)
|
||||
@@ -889,7 +896,7 @@ export const draw: DrawDefinition = function (txt, id, ver, diagObj) {
|
||||
throw new Error('GitGraph config not found');
|
||||
}
|
||||
const rotateCommitLabel = gitGraphConfig.rotateCommitLabel ?? false;
|
||||
const db = diagObj.db as GitGraphDB;
|
||||
const db = diagObj.db as GitGraphDBRenderProvider;
|
||||
allCommitsDict = db.getCommits();
|
||||
const branches = db.getBranchesAsObjArray();
|
||||
dir = db.getDirection();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||
import type { GitGraphDiagramConfig } from '../../config.type.js';
|
||||
import type { DiagramDBBase } from '../../diagram-api/types.js';
|
||||
|
||||
export interface CommitType {
|
||||
NORMAL: number;
|
||||
@@ -66,27 +66,13 @@ export interface CherryPickingAst {
|
||||
parent: string;
|
||||
}
|
||||
|
||||
export interface GitGraphDB extends DiagramDB {
|
||||
// config
|
||||
getConfig: () => GitGraphDiagramConfig | undefined;
|
||||
|
||||
// common db
|
||||
clear: () => void;
|
||||
setDiagramTitle: (title: string) => void;
|
||||
getDiagramTitle: () => string;
|
||||
setAccTitle: (title: string) => void;
|
||||
getAccTitle: () => string;
|
||||
setAccDescription: (description: string) => void;
|
||||
getAccDescription: () => string;
|
||||
|
||||
// diagram db
|
||||
export interface GitGraphDB extends DiagramDBBase<GitGraphDiagramConfig> {
|
||||
commitType: CommitType;
|
||||
setDirection: (direction: DiagramOrientation) => void;
|
||||
getDirection: () => DiagramOrientation;
|
||||
setOptions: (options: string) => void;
|
||||
getOptions: () => string;
|
||||
commit: (msg: string, id: string, type: number, tags?: string[] | undefined) => void;
|
||||
branch: (name: string, order: number) => void;
|
||||
setDirection: (dir: DiagramOrientation) => void;
|
||||
setOptions: (rawOptString: string) => void;
|
||||
getOptions: () => any;
|
||||
commit: (msg: string, id: string, type: number, tags?: string[]) => void;
|
||||
branch: (name: string, order?: number) => void;
|
||||
merge: (
|
||||
otherBranch: string,
|
||||
customId?: string,
|
||||
@@ -101,12 +87,47 @@ export interface GitGraphDB extends DiagramDB {
|
||||
) => void;
|
||||
checkout: (branch: string) => void;
|
||||
prettyPrint: () => void;
|
||||
clear: () => void;
|
||||
getBranchesAsObjArray: () => { name: string }[];
|
||||
getBranches: () => Map<string, string | null>;
|
||||
getCommits: () => Map<string, Commit>;
|
||||
getCommitsArray: () => Commit[];
|
||||
getCurrentBranch: () => string;
|
||||
getDirection: () => DiagramOrientation;
|
||||
getHead: () => Commit | null;
|
||||
}
|
||||
|
||||
export interface GitGraphDBParseProvider extends Partial<GitGraphDB> {
|
||||
commitType: CommitType;
|
||||
setDirection: (dir: DiagramOrientation) => void;
|
||||
commit: (msg: string, id: string, type: number, tags?: string[]) => void;
|
||||
branch: (name: string, order?: number) => void;
|
||||
merge: (
|
||||
otherBranch: string,
|
||||
customId?: string,
|
||||
overrideType?: number,
|
||||
customTags?: string[]
|
||||
) => void;
|
||||
cherryPick: (
|
||||
sourceId: string,
|
||||
targetId: string,
|
||||
tags: string[] | undefined,
|
||||
parentCommitId: string
|
||||
) => void;
|
||||
checkout: (branch: string) => void;
|
||||
}
|
||||
|
||||
export interface GitGraphDBRenderProvider extends Partial<GitGraphDB> {
|
||||
prettyPrint: () => void;
|
||||
clear: () => void;
|
||||
getBranchesAsObjArray: () => { name: string }[];
|
||||
getBranches: () => Map<string, string | null>;
|
||||
getCommits: () => Map<string, Commit>;
|
||||
getCommitsArray: () => Commit[];
|
||||
getCurrentBranch: () => string;
|
||||
getDirection: () => DiagramOrientation;
|
||||
getHead: () => Commit | null;
|
||||
getDiagramTitle: () => string;
|
||||
}
|
||||
|
||||
export type DiagramOrientation = 'LR' | 'TB' | 'BT';
|
||||
|
Reference in New Issue
Block a user