mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-11-04 21:04:12 +01:00
Update requirementDb to class to encapsulate data
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||||
|
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||||
import { log } from '../../logger.js';
|
import { log } from '../../logger.js';
|
||||||
import type { Node, Edge } from '../../rendering-util/types.js';
|
import type { Node, Edge } from '../../rendering-util/types.js';
|
||||||
|
|
||||||
@@ -22,29 +23,38 @@ import type {
|
|||||||
VerifyType,
|
VerifyType,
|
||||||
} from './types.js';
|
} from './types.js';
|
||||||
|
|
||||||
const RequirementType = {
|
export class RequirementDB implements DiagramDB {
|
||||||
|
private relations: Relation[] = [];
|
||||||
|
private latestRequirement: Requirement = this.getInitialRequirement();
|
||||||
|
private requirements = new Map<string, Requirement>();
|
||||||
|
private latestElement: Element = this.getInitialElement();
|
||||||
|
private elements = new Map<string, Element>();
|
||||||
|
private classes = new Map<string, RequirementClass>();
|
||||||
|
private direction = 'TB';
|
||||||
|
|
||||||
|
private RequirementType = {
|
||||||
REQUIREMENT: 'Requirement',
|
REQUIREMENT: 'Requirement',
|
||||||
FUNCTIONAL_REQUIREMENT: 'Functional Requirement',
|
FUNCTIONAL_REQUIREMENT: 'Functional Requirement',
|
||||||
INTERFACE_REQUIREMENT: 'Interface Requirement',
|
INTERFACE_REQUIREMENT: 'Interface Requirement',
|
||||||
PERFORMANCE_REQUIREMENT: 'Performance Requirement',
|
PERFORMANCE_REQUIREMENT: 'Performance Requirement',
|
||||||
PHYSICAL_REQUIREMENT: 'Physical Requirement',
|
PHYSICAL_REQUIREMENT: 'Physical Requirement',
|
||||||
DESIGN_CONSTRAINT: 'Design Constraint',
|
DESIGN_CONSTRAINT: 'Design Constraint',
|
||||||
};
|
};
|
||||||
|
|
||||||
const RiskLevel = {
|
private RiskLevel = {
|
||||||
LOW_RISK: 'Low',
|
LOW_RISK: 'Low',
|
||||||
MED_RISK: 'Medium',
|
MED_RISK: 'Medium',
|
||||||
HIGH_RISK: 'High',
|
HIGH_RISK: 'High',
|
||||||
};
|
};
|
||||||
|
|
||||||
const VerifyType = {
|
private VerifyType = {
|
||||||
VERIFY_ANALYSIS: 'Analysis',
|
VERIFY_ANALYSIS: 'Analysis',
|
||||||
VERIFY_DEMONSTRATION: 'Demonstration',
|
VERIFY_DEMONSTRATION: 'Demonstration',
|
||||||
VERIFY_INSPECTION: 'Inspection',
|
VERIFY_INSPECTION: 'Inspection',
|
||||||
VERIFY_TEST: 'Test',
|
VERIFY_TEST: 'Test',
|
||||||
};
|
};
|
||||||
|
|
||||||
const Relationships = {
|
private Relationships = {
|
||||||
CONTAINS: 'contains',
|
CONTAINS: 'contains',
|
||||||
COPIES: 'copies',
|
COPIES: 'copies',
|
||||||
DERIVES: 'derives',
|
DERIVES: 'derives',
|
||||||
@@ -52,15 +62,46 @@ const Relationships = {
|
|||||||
VERIFIES: 'verifies',
|
VERIFIES: 'verifies',
|
||||||
REFINES: 'refines',
|
REFINES: 'refines',
|
||||||
TRACES: 'traces',
|
TRACES: 'traces',
|
||||||
};
|
};
|
||||||
|
|
||||||
let direction = 'TB';
|
constructor() {
|
||||||
const getDirection = () => direction;
|
this.clear();
|
||||||
const setDirection = (dir: string) => {
|
|
||||||
direction = dir;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getInitialRequirement = (): Requirement => ({
|
// Needed for JISON since it only supports direct properties
|
||||||
|
this.setDirection = this.setDirection.bind(this);
|
||||||
|
this.addRequirement = this.addRequirement.bind(this);
|
||||||
|
this.setNewReqId = this.setNewReqId.bind(this);
|
||||||
|
this.setNewReqRisk = this.setNewReqRisk.bind(this);
|
||||||
|
this.setNewReqText = this.setNewReqText.bind(this);
|
||||||
|
this.setNewReqVerifyMethod = this.setNewReqVerifyMethod.bind(this);
|
||||||
|
this.addElement = this.addElement.bind(this);
|
||||||
|
this.setNewElementType = this.setNewElementType.bind(this);
|
||||||
|
this.setNewElementDocRef = this.setNewElementDocRef.bind(this);
|
||||||
|
this.addRelationship = this.addRelationship.bind(this);
|
||||||
|
this.setCssStyle = this.setCssStyle.bind(this);
|
||||||
|
this.setClass = this.setClass.bind(this);
|
||||||
|
this.defineClass = this.defineClass.bind(this);
|
||||||
|
this.setAccTitle = this.setAccTitle.bind(this);
|
||||||
|
this.setAccDescription = this.setAccDescription.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDirection() {
|
||||||
|
return this.direction;
|
||||||
|
}
|
||||||
|
public setDirection(dir: string) {
|
||||||
|
this.direction = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetLatestRequirement() {
|
||||||
|
this.latestRequirement = this.getInitialRequirement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetLatestElement() {
|
||||||
|
this.latestElement = this.getInitialElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getInitialRequirement(): Requirement {
|
||||||
|
return {
|
||||||
requirementId: '',
|
requirementId: '',
|
||||||
text: '',
|
text: '',
|
||||||
risk: '' as RiskLevel,
|
risk: '' as RiskLevel,
|
||||||
@@ -69,130 +110,122 @@ const getInitialRequirement = (): Requirement => ({
|
|||||||
type: '' as RequirementType,
|
type: '' as RequirementType,
|
||||||
cssStyles: [],
|
cssStyles: [],
|
||||||
classes: ['default'],
|
classes: ['default'],
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const getInitialElement = (): Element => ({
|
private getInitialElement(): Element {
|
||||||
|
return {
|
||||||
name: '',
|
name: '',
|
||||||
type: '',
|
type: '',
|
||||||
docRef: '',
|
docRef: '',
|
||||||
cssStyles: [],
|
cssStyles: [],
|
||||||
classes: ['default'],
|
classes: ['default'],
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Update initial declarations
|
public addRequirement(name: string, type: RequirementType) {
|
||||||
let relations: Relation[] = [];
|
if (!this.requirements.has(name)) {
|
||||||
let latestRequirement: Requirement = getInitialRequirement();
|
this.requirements.set(name, {
|
||||||
let requirements = new Map<string, Requirement>();
|
|
||||||
let latestElement: Element = getInitialElement();
|
|
||||||
let elements = new Map<string, Element>();
|
|
||||||
let classes = new Map<string, RequirementClass>();
|
|
||||||
|
|
||||||
// Add reset functions
|
|
||||||
const resetLatestRequirement = () => {
|
|
||||||
latestRequirement = getInitialRequirement();
|
|
||||||
};
|
|
||||||
|
|
||||||
const resetLatestElement = () => {
|
|
||||||
latestElement = getInitialElement();
|
|
||||||
};
|
|
||||||
|
|
||||||
const addRequirement = (name: string, type: RequirementType) => {
|
|
||||||
if (!requirements.has(name)) {
|
|
||||||
requirements.set(name, {
|
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
requirementId: latestRequirement.requirementId,
|
requirementId: this.latestRequirement.requirementId,
|
||||||
text: latestRequirement.text,
|
text: this.latestRequirement.text,
|
||||||
risk: latestRequirement.risk,
|
risk: this.latestRequirement.risk,
|
||||||
verifyMethod: latestRequirement.verifyMethod,
|
verifyMethod: this.latestRequirement.verifyMethod,
|
||||||
cssStyles: [],
|
cssStyles: [],
|
||||||
classes: ['default'],
|
classes: ['default'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
resetLatestRequirement();
|
this.resetLatestRequirement();
|
||||||
|
|
||||||
return requirements.get(name);
|
return this.requirements.get(name);
|
||||||
};
|
|
||||||
|
|
||||||
const getRequirements = () => requirements;
|
|
||||||
|
|
||||||
const setNewReqId = (id: string) => {
|
|
||||||
if (latestRequirement !== undefined) {
|
|
||||||
latestRequirement.requirementId = id;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const setNewReqText = (text: string) => {
|
public getRequirements() {
|
||||||
if (latestRequirement !== undefined) {
|
return this.requirements;
|
||||||
latestRequirement.text = text;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const setNewReqRisk = (risk: RiskLevel) => {
|
public setNewReqId(id: string) {
|
||||||
if (latestRequirement !== undefined) {
|
if (this.latestRequirement !== undefined) {
|
||||||
latestRequirement.risk = risk;
|
this.latestRequirement.requirementId = id;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const setNewReqVerifyMethod = (verifyMethod: VerifyType) => {
|
|
||||||
if (latestRequirement !== undefined) {
|
|
||||||
latestRequirement.verifyMethod = verifyMethod;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const addElement = (name: string) => {
|
public setNewReqText(text: string) {
|
||||||
if (!elements.has(name)) {
|
if (this.latestRequirement !== undefined) {
|
||||||
elements.set(name, {
|
this.latestRequirement.text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setNewReqRisk(risk: RiskLevel) {
|
||||||
|
if (this.latestRequirement !== undefined) {
|
||||||
|
this.latestRequirement.risk = risk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setNewReqVerifyMethod(verifyMethod: VerifyType) {
|
||||||
|
if (this.latestRequirement !== undefined) {
|
||||||
|
this.latestRequirement.verifyMethod = verifyMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public addElement(name: string) {
|
||||||
|
if (!this.elements.has(name)) {
|
||||||
|
this.elements.set(name, {
|
||||||
name,
|
name,
|
||||||
type: latestElement.type,
|
type: this.latestElement.type,
|
||||||
docRef: latestElement.docRef,
|
docRef: this.latestElement.docRef,
|
||||||
cssStyles: [],
|
cssStyles: [],
|
||||||
classes: ['default'],
|
classes: ['default'],
|
||||||
});
|
});
|
||||||
log.info('Added new element: ', name);
|
log.info('Added new element: ', name);
|
||||||
}
|
}
|
||||||
resetLatestElement();
|
this.resetLatestElement();
|
||||||
|
|
||||||
return elements.get(name);
|
return this.elements.get(name);
|
||||||
};
|
|
||||||
|
|
||||||
const getElements = () => elements;
|
|
||||||
|
|
||||||
const setNewElementType = (type: string) => {
|
|
||||||
if (latestElement !== undefined) {
|
|
||||||
latestElement.type = type;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const setNewElementDocRef = (docRef: string) => {
|
public getElements() {
|
||||||
if (latestElement !== undefined) {
|
return this.elements;
|
||||||
latestElement.docRef = docRef;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const addRelationship = (type: RelationshipType, src: string, dst: string) => {
|
public setNewElementType(type: string) {
|
||||||
relations.push({
|
if (this.latestElement !== undefined) {
|
||||||
|
this.latestElement.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setNewElementDocRef(docRef: string) {
|
||||||
|
if (this.latestElement !== undefined) {
|
||||||
|
this.latestElement.docRef = docRef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public addRelationship(type: RelationshipType, src: string, dst: string) {
|
||||||
|
this.relations.push({
|
||||||
type,
|
type,
|
||||||
src,
|
src,
|
||||||
dst,
|
dst,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
const getRelationships = () => relations;
|
public getRelationships() {
|
||||||
|
return this.relations;
|
||||||
|
}
|
||||||
|
|
||||||
const clear = () => {
|
public clear() {
|
||||||
relations = [];
|
this.relations = [];
|
||||||
resetLatestRequirement();
|
this.resetLatestRequirement();
|
||||||
requirements = new Map();
|
this.requirements = new Map();
|
||||||
resetLatestElement();
|
this.resetLatestElement();
|
||||||
elements = new Map();
|
this.elements = new Map();
|
||||||
classes = new Map();
|
this.classes = new Map();
|
||||||
commonClear();
|
commonClear();
|
||||||
};
|
}
|
||||||
|
|
||||||
export const setCssStyle = function (ids: string[], styles: string[]) {
|
public setCssStyle(ids: string[], styles: string[]) {
|
||||||
for (const id of ids) {
|
for (const id of ids) {
|
||||||
const node = requirements.get(id) ?? elements.get(id);
|
const node = this.requirements.get(id) ?? this.elements.get(id);
|
||||||
if (!styles || !node) {
|
if (!styles || !node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -204,29 +237,29 @@ export const setCssStyle = function (ids: string[], styles: string[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const setClass = function (ids: string[], classNames: string[]) {
|
public setClass(ids: string[], classNames: string[]) {
|
||||||
for (const id of ids) {
|
for (const id of ids) {
|
||||||
const node = requirements.get(id) ?? elements.get(id);
|
const node = this.requirements.get(id) ?? this.elements.get(id);
|
||||||
if (node) {
|
if (node) {
|
||||||
for (const _class of classNames) {
|
for (const _class of classNames) {
|
||||||
node.classes.push(_class);
|
node.classes.push(_class);
|
||||||
const styles = classes.get(_class)?.styles;
|
const styles = this.classes.get(_class)?.styles;
|
||||||
if (styles) {
|
if (styles) {
|
||||||
node.cssStyles.push(...styles);
|
node.cssStyles.push(...styles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const defineClass = function (ids: string[], style: string[]) {
|
public defineClass(ids: string[], style: string[]) {
|
||||||
for (const id of ids) {
|
for (const id of ids) {
|
||||||
let styleClass = classes.get(id);
|
let styleClass = this.classes.get(id);
|
||||||
if (styleClass === undefined) {
|
if (styleClass === undefined) {
|
||||||
styleClass = { id, styles: [], textStyles: [] };
|
styleClass = { id, styles: [], textStyles: [] };
|
||||||
classes.set(id, styleClass);
|
this.classes.set(id, styleClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style) {
|
if (style) {
|
||||||
@@ -239,28 +272,28 @@ export const defineClass = function (ids: string[], style: string[]) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
requirements.forEach((value) => {
|
this.requirements.forEach((value) => {
|
||||||
if (value.classes.includes(id)) {
|
if (value.classes.includes(id)) {
|
||||||
value.cssStyles.push(...style.flatMap((s) => s.split(',')));
|
value.cssStyles.push(...style.flatMap((s) => s.split(',')));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
elements.forEach((value) => {
|
this.elements.forEach((value) => {
|
||||||
if (value.classes.includes(id)) {
|
if (value.classes.includes(id)) {
|
||||||
value.cssStyles.push(...style.flatMap((s) => s.split(',')));
|
value.cssStyles.push(...style.flatMap((s) => s.split(',')));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const getClasses = () => {
|
public getClasses() {
|
||||||
return classes;
|
return this.classes;
|
||||||
};
|
}
|
||||||
|
|
||||||
const getData = () => {
|
public getData() {
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
const nodes: Node[] = [];
|
const nodes: Node[] = [];
|
||||||
const edges: Edge[] = [];
|
const edges: Edge[] = [];
|
||||||
for (const requirement of requirements.values()) {
|
for (const requirement of this.requirements.values()) {
|
||||||
const node = requirement as unknown as Node;
|
const node = requirement as unknown as Node;
|
||||||
node.id = requirement.name;
|
node.id = requirement.name;
|
||||||
node.cssStyles = requirement.cssStyles;
|
node.cssStyles = requirement.cssStyles;
|
||||||
@@ -270,7 +303,7 @@ const getData = () => {
|
|||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const element of elements.values()) {
|
for (const element of this.elements.values()) {
|
||||||
const node = element as unknown as Node;
|
const node = element as unknown as Node;
|
||||||
node.shape = 'requirementBox';
|
node.shape = 'requirementBox';
|
||||||
node.look = config.look;
|
node.look = config.look;
|
||||||
@@ -281,13 +314,13 @@ const getData = () => {
|
|||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const relation of relations) {
|
for (const relation of this.relations) {
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
const isContains = relation.type === Relationships.CONTAINS;
|
const isContains = relation.type === this.Relationships.CONTAINS;
|
||||||
const edge: Edge = {
|
const edge: Edge = {
|
||||||
id: `${relation.src}-${relation.dst}-${counter}`,
|
id: `${relation.src}-${relation.dst}-${counter}`,
|
||||||
start: requirements.get(relation.src)?.name ?? elements.get(relation.src)?.name,
|
start: this.requirements.get(relation.src)?.name ?? this.elements.get(relation.src)?.name,
|
||||||
end: requirements.get(relation.dst)?.name ?? elements.get(relation.dst)?.name,
|
end: this.requirements.get(relation.dst)?.name ?? this.elements.get(relation.dst)?.name,
|
||||||
label: `<<${relation.type}>>`,
|
label: `<<${relation.type}>>`,
|
||||||
classes: 'relationshipLine',
|
classes: 'relationshipLine',
|
||||||
style: ['fill:none', isContains ? '' : 'stroke-dasharray: 10,7'],
|
style: ['fill:none', isContains ? '' : 'stroke-dasharray: 10,7'],
|
||||||
@@ -303,39 +336,14 @@ const getData = () => {
|
|||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { nodes, edges, other: {}, config, direction: getDirection() };
|
return { nodes, edges, other: {}, config, direction: this.getDirection() };
|
||||||
};
|
}
|
||||||
|
|
||||||
export default {
|
public setAccTitle = setAccTitle;
|
||||||
Relationships,
|
public getAccTitle = getAccTitle;
|
||||||
RequirementType,
|
public setAccDescription = setAccDescription;
|
||||||
RiskLevel,
|
public getAccDescription = getAccDescription;
|
||||||
VerifyType,
|
public setDiagramTitle = setDiagramTitle;
|
||||||
getConfig: () => getConfig().requirement,
|
public getDiagramTitle = getDiagramTitle;
|
||||||
addRequirement,
|
public getConfig = () => getConfig().class;
|
||||||
getRequirements,
|
}
|
||||||
setNewReqId,
|
|
||||||
setNewReqText,
|
|
||||||
setNewReqRisk,
|
|
||||||
setNewReqVerifyMethod,
|
|
||||||
setAccTitle,
|
|
||||||
getAccTitle,
|
|
||||||
setAccDescription,
|
|
||||||
getAccDescription,
|
|
||||||
setDiagramTitle,
|
|
||||||
getDiagramTitle,
|
|
||||||
getDirection,
|
|
||||||
setDirection,
|
|
||||||
addElement,
|
|
||||||
getElements,
|
|
||||||
setNewElementType,
|
|
||||||
setNewElementDocRef,
|
|
||||||
addRelationship,
|
|
||||||
getRelationships,
|
|
||||||
clear,
|
|
||||||
setCssStyle,
|
|
||||||
setClass,
|
|
||||||
defineClass,
|
|
||||||
getClasses,
|
|
||||||
getData,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||||
// @ts-ignore: JISON doesn't support types
|
// @ts-ignore: JISON doesn't support types
|
||||||
import parser from './parser/requirementDiagram.jison';
|
import parser from './parser/requirementDiagram.jison';
|
||||||
import db from './requirementDb.js';
|
import { RequirementDB } from './requirementDb.js';
|
||||||
import styles from './styles.js';
|
import styles from './styles.js';
|
||||||
import renderer from './requirementRenderer.js';
|
import renderer from './requirementRenderer.js';
|
||||||
|
|
||||||
export const diagram: DiagramDefinition = {
|
export const diagram: DiagramDefinition = {
|
||||||
parser,
|
parser,
|
||||||
db,
|
get db() {
|
||||||
|
return new RequirementDB();
|
||||||
|
},
|
||||||
renderer,
|
renderer,
|
||||||
styles,
|
styles,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user