mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-15 06:19:24 +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
|
||||
unshift
|
||||
urlsafe
|
||||
usecase
|
||||
verifymethod
|
||||
VERIFYMTHD
|
||||
WARN_DOCSDIR_DOESNT_MATCH
|
||||
|
@@ -28,6 +28,7 @@ import architecture from '../diagrams/architecture/architectureDetector.js';
|
||||
import { registerLazyLoadedDiagrams } from './detectType.js';
|
||||
import { registerDiagram } from './diagramAPI.js';
|
||||
import { treemap } from '../diagrams/treemap/detector.js';
|
||||
import { usecase } from '../diagrams/usecase/detector.js';
|
||||
import '../type.d.ts';
|
||||
|
||||
let hasLoadedDiagrams = false;
|
||||
@@ -101,6 +102,7 @@ export const addDiagrams = () => {
|
||||
xychart,
|
||||
block,
|
||||
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",
|
||||
"grammar": "src/language/treemap/treemap.langium",
|
||||
"fileExtensions": [".mmd", ".mermaid"]
|
||||
},
|
||||
{
|
||||
"id": "usecase",
|
||||
"grammar": "src/language/usecase/usecase.langium",
|
||||
"fileExtensions": [".mmd", ".mermaid"]
|
||||
}
|
||||
],
|
||||
"mode": "production",
|
||||
|
@@ -9,6 +9,7 @@ export {
|
||||
GitGraph,
|
||||
Radar,
|
||||
Treemap,
|
||||
Usecase,
|
||||
Branch,
|
||||
Commit,
|
||||
Merge,
|
||||
@@ -24,6 +25,7 @@ export {
|
||||
isBranch,
|
||||
isCommit,
|
||||
isMerge,
|
||||
isUsecase,
|
||||
} from './generated/ast.js';
|
||||
|
||||
export {
|
||||
@@ -35,6 +37,7 @@ export {
|
||||
GitGraphGeneratedModule,
|
||||
RadarGeneratedModule,
|
||||
TreemapGeneratedModule,
|
||||
UsecaseGeneratedModule,
|
||||
} from './generated/module.js';
|
||||
|
||||
export * from './gitGraph/index.js';
|
||||
@@ -45,3 +48,4 @@ export * from './pie/index.js';
|
||||
export * from './architecture/index.js';
|
||||
export * from './radar/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 { 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;
|
||||
|
||||
@@ -41,6 +50,11 @@ const initializers = {
|
||||
const parser = createTreemapServices().Treemap.parser.LangiumParser;
|
||||
parsers.treemap = parser;
|
||||
},
|
||||
// usecase: async () => {
|
||||
// const { createUsecaseServices } = await import('./language/usecase/index.js');
|
||||
// const parser = createUsecaseServices().Usecase.parser.LangiumParser;
|
||||
// parsers.usecase = parser;
|
||||
// },
|
||||
} as const;
|
||||
|
||||
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: 'radar', text: string): Promise<Radar>;
|
||||
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>(
|
||||
diagramType: keyof typeof initializers,
|
||||
|
Reference in New Issue
Block a user