mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-22 01:36:43 +02:00
Update: Added folder structure for usecase diagram
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
This commit is contained in:
@@ -143,6 +143,7 @@ typeof
|
|||||||
typestr
|
typestr
|
||||||
unshift
|
unshift
|
||||||
urlsafe
|
urlsafe
|
||||||
|
usecase
|
||||||
verifymethod
|
verifymethod
|
||||||
VERIFYMTHD
|
VERIFYMTHD
|
||||||
WARN_DOCSDIR_DOESNT_MATCH
|
WARN_DOCSDIR_DOESNT_MATCH
|
||||||
|
@@ -28,6 +28,7 @@ import architecture from '../diagrams/architecture/architectureDetector.js';
|
|||||||
import { registerLazyLoadedDiagrams } from './detectType.js';
|
import { registerLazyLoadedDiagrams } from './detectType.js';
|
||||||
import { registerDiagram } from './diagramAPI.js';
|
import { registerDiagram } from './diagramAPI.js';
|
||||||
import { treemap } from '../diagrams/treemap/detector.js';
|
import { treemap } from '../diagrams/treemap/detector.js';
|
||||||
|
import { usecase } from '../diagrams/usecase/detector.js';
|
||||||
import '../type.d.ts';
|
import '../type.d.ts';
|
||||||
|
|
||||||
let hasLoadedDiagrams = false;
|
let hasLoadedDiagrams = false;
|
||||||
@@ -101,6 +102,7 @@ export const addDiagrams = () => {
|
|||||||
xychart,
|
xychart,
|
||||||
block,
|
block,
|
||||||
radar,
|
radar,
|
||||||
treemap
|
treemap,
|
||||||
|
usecase
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
38
packages/mermaid/src/diagrams/usecase/db.ts
Normal file
38
packages/mermaid/src/diagrams/usecase/db.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||||
|
import type { UsecaseDiagramConfig, UsecaseNode } from './types.js';
|
||||||
|
import { cleanAndMerge } from '../../utils.js';
|
||||||
|
|
||||||
|
export class UsecaseDiagramDB implements DiagramDB {
|
||||||
|
public getNodes() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getConfig() {
|
||||||
|
return cleanAndMerge({}) as Required<UsecaseDiagramConfig>;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addNode(node: UsecaseNode, level: number) {
|
||||||
|
if (level === 0) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRoot() {
|
||||||
|
return { name: '', children: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
public addClass(_id: string, _style: string) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
public getClasses() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public getStylesForClass(_classSelector: string) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear() {
|
||||||
|
// commonClear();
|
||||||
|
}
|
||||||
|
}
|
22
packages/mermaid/src/diagrams/usecase/detector.ts
Normal file
22
packages/mermaid/src/diagrams/usecase/detector.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import type {
|
||||||
|
DiagramDetector,
|
||||||
|
DiagramLoader,
|
||||||
|
ExternalDiagramDefinition,
|
||||||
|
} from '../../diagram-api/types.js';
|
||||||
|
|
||||||
|
const id = 'usecase';
|
||||||
|
|
||||||
|
const detector: DiagramDetector = (txt) => {
|
||||||
|
return /^\s*usecase/.test(txt);
|
||||||
|
};
|
||||||
|
|
||||||
|
const loader: DiagramLoader = async () => {
|
||||||
|
const { diagram } = await import('./diagram.js');
|
||||||
|
return { id, diagram };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usecase: ExternalDiagramDefinition = {
|
||||||
|
id,
|
||||||
|
detector,
|
||||||
|
loader,
|
||||||
|
};
|
14
packages/mermaid/src/diagrams/usecase/diagram.ts
Normal file
14
packages/mermaid/src/diagrams/usecase/diagram.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||||
|
import { UsecaseDiagramDB } from './db.js';
|
||||||
|
import { parser } from './parser.js';
|
||||||
|
import { renderer } from './renderer.js';
|
||||||
|
import styles from './styles.js';
|
||||||
|
|
||||||
|
export const diagram: DiagramDefinition = {
|
||||||
|
parser,
|
||||||
|
get db() {
|
||||||
|
return new UsecaseDiagramDB();
|
||||||
|
},
|
||||||
|
renderer,
|
||||||
|
styles,
|
||||||
|
};
|
40
packages/mermaid/src/diagrams/usecase/parser.ts
Normal file
40
packages/mermaid/src/diagrams/usecase/parser.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { parse } from '@mermaid-js/parser';
|
||||||
|
import type { ParserDefinition } from '../../diagram-api/types.js';
|
||||||
|
import { log } from '../../logger.js';
|
||||||
|
import { populateCommonDb } from '../common/populateCommonDb.js';
|
||||||
|
import type { UsecaseAst } from './types.js';
|
||||||
|
import { UsecaseDiagramDB } from './db.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the database with data from the Usecase AST
|
||||||
|
* @param ast - The Usecase AST
|
||||||
|
*/
|
||||||
|
const populate = (ast: UsecaseAst, db: UsecaseDiagramDB) => {
|
||||||
|
// We need to bypass the type checking for populateCommonDb
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
populateCommonDb(ast as any, db);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const parser: ParserDefinition = {
|
||||||
|
// @ts-expect-error - UsecaseDB is not assignable to DiagramDB
|
||||||
|
parser: { yy: undefined },
|
||||||
|
parse: async (text: string): Promise<void> => {
|
||||||
|
try {
|
||||||
|
// Use a generic parse that accepts any diagram type
|
||||||
|
|
||||||
|
const parseFunc = parse as (diagramType: string, text: string) => Promise<UsecaseAst>;
|
||||||
|
const ast = await parseFunc('usecase', text);
|
||||||
|
log.debug('Usecase AST:', ast);
|
||||||
|
const db = parser.parser?.yy;
|
||||||
|
if (!(db instanceof UsecaseDiagramDB)) {
|
||||||
|
throw new Error(
|
||||||
|
'parser.parser?.yy was not a UsecaseDiagramDB. This is due to a bug within Mermaid, please report this issue at https://github.com/mermaid-js/mermaid/issues.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
populate(ast, db);
|
||||||
|
} catch (error) {
|
||||||
|
log.error('Error parsing usecase:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
21
packages/mermaid/src/diagrams/usecase/renderer.ts
Normal file
21
packages/mermaid/src/diagrams/usecase/renderer.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type { Diagram } from '../../Diagram.js';
|
||||||
|
import type {
|
||||||
|
DiagramRenderer,
|
||||||
|
DiagramStyleClassDef,
|
||||||
|
DrawDefinition,
|
||||||
|
} from '../../diagram-api/types.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the Usecase diagram
|
||||||
|
*/
|
||||||
|
const draw: DrawDefinition = (_text, _id, _version, _diagram: Diagram) => {
|
||||||
|
// TODO: Implement the draw function for the usecase diagram
|
||||||
|
};
|
||||||
|
|
||||||
|
const getClasses = function (
|
||||||
|
_text: string,
|
||||||
|
_diagramObj: Pick<Diagram, 'db'>
|
||||||
|
): Map<string, DiagramStyleClassDef> {
|
||||||
|
return new Map<string, DiagramStyleClassDef>();
|
||||||
|
};
|
||||||
|
export const renderer: DiagramRenderer = { draw, getClasses };
|
51
packages/mermaid/src/diagrams/usecase/styles.ts
Normal file
51
packages/mermaid/src/diagrams/usecase/styles.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import type { DiagramStylesProvider } from '../../diagram-api/types.js';
|
||||||
|
import { cleanAndMerge } from '../../utils.js';
|
||||||
|
import type { UsecaseStyleOptions } from './types.js';
|
||||||
|
|
||||||
|
const defaultUsecaseStyleOptions: UsecaseStyleOptions = {
|
||||||
|
sectionStrokeColor: 'black',
|
||||||
|
sectionStrokeWidth: '1',
|
||||||
|
sectionFillColor: '#efefef',
|
||||||
|
leafStrokeColor: 'black',
|
||||||
|
leafStrokeWidth: '1',
|
||||||
|
leafFillColor: '#efefef',
|
||||||
|
labelColor: 'black',
|
||||||
|
labelFontSize: '12px',
|
||||||
|
valueFontSize: '10px',
|
||||||
|
valueColor: 'black',
|
||||||
|
titleColor: 'black',
|
||||||
|
titleFontSize: '14px',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getStyles: DiagramStylesProvider = ({
|
||||||
|
usecase,
|
||||||
|
}: { usecase?: UsecaseStyleOptions } = {}) => {
|
||||||
|
const options = cleanAndMerge(defaultUsecaseStyleOptions, usecase);
|
||||||
|
|
||||||
|
return `
|
||||||
|
.usecaseNode.section {
|
||||||
|
stroke: ${options.sectionStrokeColor};
|
||||||
|
stroke-width: ${options.sectionStrokeWidth};
|
||||||
|
fill: ${options.sectionFillColor};
|
||||||
|
}
|
||||||
|
.usecaseNode.leaf {
|
||||||
|
stroke: ${options.leafStrokeColor};
|
||||||
|
stroke-width: ${options.leafStrokeWidth};
|
||||||
|
fill: ${options.leafFillColor};
|
||||||
|
}
|
||||||
|
.usecaseLabel {
|
||||||
|
fill: ${options.labelColor};
|
||||||
|
font-size: ${options.labelFontSize};
|
||||||
|
}
|
||||||
|
.usecaseValue {
|
||||||
|
fill: ${options.valueColor};
|
||||||
|
font-size: ${options.valueFontSize};
|
||||||
|
}
|
||||||
|
.usecaseTitle {
|
||||||
|
fill: ${options.titleColor};
|
||||||
|
font-size: ${options.titleFontSize};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getStyles;
|
68
packages/mermaid/src/diagrams/usecase/types.ts
Normal file
68
packages/mermaid/src/diagrams/usecase/types.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import type { DiagramDBBase, DiagramStyleClassDef } from '../../diagram-api/types.js';
|
||||||
|
import type { BaseDiagramConfig } from '../../config.type.js';
|
||||||
|
|
||||||
|
export interface UsecaseNode {
|
||||||
|
name: string;
|
||||||
|
children?: UsecaseNode[];
|
||||||
|
value?: number;
|
||||||
|
parent?: UsecaseNode;
|
||||||
|
classSelector?: string;
|
||||||
|
cssCompiledStyles?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UsecaseDiagramDB extends DiagramDBBase<UsecaseDiagramConfig> {
|
||||||
|
getNodes: () => UsecaseNode[];
|
||||||
|
addNode: (node: UsecaseNode, level: number) => void;
|
||||||
|
getRoot: () => UsecaseNode | undefined;
|
||||||
|
getClasses: () => Map<string, DiagramStyleClassDef>;
|
||||||
|
addClass: (className: string, style: string) => void;
|
||||||
|
getStylesForClass: (classSelector: string) => string[];
|
||||||
|
// Update
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UsecaseStyleOptions {
|
||||||
|
sectionStrokeColor?: string;
|
||||||
|
sectionStrokeWidth?: string;
|
||||||
|
sectionFillColor?: string;
|
||||||
|
leafStrokeColor?: string;
|
||||||
|
leafStrokeWidth?: string;
|
||||||
|
leafFillColor?: string;
|
||||||
|
labelColor?: string;
|
||||||
|
labelFontSize?: string;
|
||||||
|
valueFontSize?: string;
|
||||||
|
valueColor?: string;
|
||||||
|
titleColor?: string;
|
||||||
|
titleFontSize?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UsecaseData {
|
||||||
|
nodes: UsecaseNode[];
|
||||||
|
levels: Map<UsecaseNode, number>;
|
||||||
|
root?: UsecaseNode;
|
||||||
|
outerNodes: UsecaseNode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UsecaseItem {
|
||||||
|
$type: string;
|
||||||
|
name: string;
|
||||||
|
value?: number;
|
||||||
|
classSelector?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UsecaseAst {
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the UsecaseDiagramConfig interface
|
||||||
|
export interface UsecaseDiagramConfig extends BaseDiagramConfig {
|
||||||
|
padding?: number;
|
||||||
|
diagramPadding?: number;
|
||||||
|
showValues?: boolean;
|
||||||
|
nodeWidth?: number;
|
||||||
|
nodeHeight?: number;
|
||||||
|
borderWidth?: number;
|
||||||
|
valueFontSize?: number;
|
||||||
|
labelFontSize?: number;
|
||||||
|
valueFormat?: string;
|
||||||
|
}
|
@@ -35,6 +35,11 @@
|
|||||||
"id": "treemap",
|
"id": "treemap",
|
||||||
"grammar": "src/language/treemap/treemap.langium",
|
"grammar": "src/language/treemap/treemap.langium",
|
||||||
"fileExtensions": [".mmd", ".mermaid"]
|
"fileExtensions": [".mmd", ".mermaid"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "usecase",
|
||||||
|
"grammar": "src/language/usecase/usecase.langium",
|
||||||
|
"fileExtensions": [".mmd", ".mermaid"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"mode": "production",
|
"mode": "production",
|
||||||
|
@@ -9,6 +9,7 @@ export {
|
|||||||
GitGraph,
|
GitGraph,
|
||||||
Radar,
|
Radar,
|
||||||
Treemap,
|
Treemap,
|
||||||
|
Usecase,
|
||||||
Branch,
|
Branch,
|
||||||
Commit,
|
Commit,
|
||||||
Merge,
|
Merge,
|
||||||
@@ -24,6 +25,7 @@ export {
|
|||||||
isBranch,
|
isBranch,
|
||||||
isCommit,
|
isCommit,
|
||||||
isMerge,
|
isMerge,
|
||||||
|
isUsecase,
|
||||||
} from './generated/ast.js';
|
} from './generated/ast.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -35,6 +37,7 @@ export {
|
|||||||
GitGraphGeneratedModule,
|
GitGraphGeneratedModule,
|
||||||
RadarGeneratedModule,
|
RadarGeneratedModule,
|
||||||
TreemapGeneratedModule,
|
TreemapGeneratedModule,
|
||||||
|
UsecaseGeneratedModule,
|
||||||
} from './generated/module.js';
|
} from './generated/module.js';
|
||||||
|
|
||||||
export * from './gitGraph/index.js';
|
export * from './gitGraph/index.js';
|
||||||
@@ -45,3 +48,4 @@ export * from './pie/index.js';
|
|||||||
export * from './architecture/index.js';
|
export * from './architecture/index.js';
|
||||||
export * from './radar/index.js';
|
export * from './radar/index.js';
|
||||||
export * from './treemap/index.js';
|
export * from './treemap/index.js';
|
||||||
|
export * from './usecase/index.js';
|
||||||
|
1
packages/parser/src/language/usecase/index.ts
Normal file
1
packages/parser/src/language/usecase/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './module.js';
|
35
packages/parser/src/language/usecase/module.ts
Normal file
35
packages/parser/src/language/usecase/module.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { type DefaultSharedCoreModuleContext, type LangiumCoreServices } from 'langium';
|
||||||
|
import type { Module, PartialLangiumCoreServices } from 'langium';
|
||||||
|
import { EmptyFileSystem } from 'langium';
|
||||||
|
import { UsecaseTokenBuilder } from './tokenBuilder.js';
|
||||||
|
import { UsecaseValueConverter } from './valueConverter.js';
|
||||||
|
import { UsecaseValidator } from './usecase-validator.js';
|
||||||
|
|
||||||
|
interface UsecaseAddedServices {
|
||||||
|
parser: {
|
||||||
|
TokenBuilder: UsecaseTokenBuilder;
|
||||||
|
ValueConverter: UsecaseValueConverter;
|
||||||
|
};
|
||||||
|
validation: {
|
||||||
|
UsecaseValidator: UsecaseValidator;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UsecaseServices = LangiumCoreServices & UsecaseAddedServices;
|
||||||
|
|
||||||
|
export const UsecaseModule: Module<
|
||||||
|
UsecaseServices,
|
||||||
|
PartialLangiumCoreServices & UsecaseAddedServices
|
||||||
|
> = {
|
||||||
|
parser: {
|
||||||
|
TokenBuilder: () => new UsecaseTokenBuilder(),
|
||||||
|
ValueConverter: () => new UsecaseValueConverter(),
|
||||||
|
},
|
||||||
|
validation: {
|
||||||
|
UsecaseValidator: () => new UsecaseValidator(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createUsecaseServices(_context: DefaultSharedCoreModuleContext = EmptyFileSystem) {
|
||||||
|
// TODO
|
||||||
|
}
|
7
packages/parser/src/language/usecase/tokenBuilder.ts
Normal file
7
packages/parser/src/language/usecase/tokenBuilder.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { AbstractMermaidTokenBuilder } from '../common/index.js';
|
||||||
|
|
||||||
|
export class UsecaseTokenBuilder extends AbstractMermaidTokenBuilder {
|
||||||
|
public constructor() {
|
||||||
|
super(['usecase']);
|
||||||
|
}
|
||||||
|
}
|
12
packages/parser/src/language/usecase/usecase-validator.ts
Normal file
12
packages/parser/src/language/usecase/usecase-validator.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import type { UsecaseServices } from './module.js';
|
||||||
|
/**
|
||||||
|
* Register custom validation checks.
|
||||||
|
*/
|
||||||
|
export function registerValidationChecks(_services: UsecaseServices) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of custom validations.
|
||||||
|
*/
|
||||||
|
export class UsecaseValidator {}
|
1
packages/parser/src/language/usecase/usecase.langium
Normal file
1
packages/parser/src/language/usecase/usecase.langium
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// TODO
|
12
packages/parser/src/language/usecase/valueConverter.ts
Normal file
12
packages/parser/src/language/usecase/valueConverter.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import type { CstNode, GrammarAST, ValueType } from 'langium';
|
||||||
|
import { AbstractMermaidValueConverter } from '../common/index.js';
|
||||||
|
|
||||||
|
export class UsecaseValueConverter extends AbstractMermaidValueConverter {
|
||||||
|
protected runCustomConverter(
|
||||||
|
_rule: GrammarAST.AbstractRule,
|
||||||
|
_input: string,
|
||||||
|
_cstNode: CstNode
|
||||||
|
): ValueType | undefined {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,15 @@
|
|||||||
import type { LangiumParser, ParseResult } from 'langium';
|
import type { LangiumParser, ParseResult } from 'langium';
|
||||||
|
|
||||||
import type { Info, Packet, Pie, Architecture, GitGraph, Radar, Treemap } from './index.js';
|
import type {
|
||||||
|
Info,
|
||||||
|
Packet,
|
||||||
|
Pie,
|
||||||
|
Architecture,
|
||||||
|
GitGraph,
|
||||||
|
Radar,
|
||||||
|
Treemap,
|
||||||
|
// Usecase,
|
||||||
|
} from './index.js';
|
||||||
|
|
||||||
export type DiagramAST = Info | Packet | Pie | Architecture | GitGraph | Radar;
|
export type DiagramAST = Info | Packet | Pie | Architecture | GitGraph | Radar;
|
||||||
|
|
||||||
@@ -41,6 +50,11 @@ const initializers = {
|
|||||||
const parser = createTreemapServices().Treemap.parser.LangiumParser;
|
const parser = createTreemapServices().Treemap.parser.LangiumParser;
|
||||||
parsers.treemap = parser;
|
parsers.treemap = parser;
|
||||||
},
|
},
|
||||||
|
// usecase: async () => {
|
||||||
|
// const { createUsecaseServices } = await import('./language/usecase/index.js');
|
||||||
|
// const parser = createUsecaseServices().Usecase.parser.LangiumParser;
|
||||||
|
// parsers.usecase = parser;
|
||||||
|
// },
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export async function parse(diagramType: 'info', text: string): Promise<Info>;
|
export async function parse(diagramType: 'info', text: string): Promise<Info>;
|
||||||
@@ -50,6 +64,7 @@ export async function parse(diagramType: 'architecture', text: string): Promise<
|
|||||||
export async function parse(diagramType: 'gitGraph', text: string): Promise<GitGraph>;
|
export async function parse(diagramType: 'gitGraph', text: string): Promise<GitGraph>;
|
||||||
export async function parse(diagramType: 'radar', text: string): Promise<Radar>;
|
export async function parse(diagramType: 'radar', text: string): Promise<Radar>;
|
||||||
export async function parse(diagramType: 'treemap', text: string): Promise<Treemap>;
|
export async function parse(diagramType: 'treemap', text: string): Promise<Treemap>;
|
||||||
|
// export async function parse(diagramType: 'usecase', text: string): Promise<Usecase>;
|
||||||
|
|
||||||
export async function parse<T extends DiagramAST>(
|
export async function parse<T extends DiagramAST>(
|
||||||
diagramType: keyof typeof initializers,
|
diagramType: keyof typeof initializers,
|
||||||
|
Reference in New Issue
Block a user