diff --git a/packages/mermaid/src/config.type.ts b/packages/mermaid/src/config.type.ts index b48a9e04bc..c07766010d 100644 --- a/packages/mermaid/src/config.type.ts +++ b/packages/mermaid/src/config.type.ts @@ -1322,7 +1322,31 @@ export interface SankeyDiagramConfig extends BaseDiagramConfig { * via the `definition` "RailroadDiagramConfig". */ export interface RailroadDiagramConfig extends BaseDiagramConfig { - compressed?: boolean; + alignment?: 'left' | 'right' | 'center' | 'justify'; + /** + * Wrap long grammars similarly to wrapping long lines + * + */ + wrap?: boolean; + syntax?: 'mermaid' | 'w3c' | 'iso'; + /** + * Compress rules to get the smallest possible diagram + * + */ + compress?: boolean; + /** + * Draw grammar definitions inside diagram + * + */ + display_grammar?: boolean; + /** + * Print angular brackets around non-terminal symbols + * + */ + angle_brackets?: boolean; + draw_arrows?: boolean; + inline?: boolean; + inline_items?: string[]; } /** * This interface was referenced by `MermaidConfig`'s JSON-Schema diff --git a/packages/mermaid/src/diagrams/railroad/railroad.spec.ts b/packages/mermaid/src/diagrams/railroad/railroad.spec.ts index efbac44fcf..2c692d9f16 100644 --- a/packages/mermaid/src/diagrams/railroad/railroad.spec.ts +++ b/packages/mermaid/src/diagrams/railroad/railroad.spec.ts @@ -2,12 +2,15 @@ import railroad from './railroadGrammar.jison'; // import { prepareTextForParsing } from '../railroadUtils.js'; import { cleanupComments } from '../../diagram-api/comments.js'; -import { db } from './railroadDB.js'; +import { db, Rules } from './railroadDB.js'; describe('Railroad diagram', function () { - beforeEach(function () { - railroad.parser.yy = db; - railroad.parser.yy.clear(); + beforeAll(() => { + railroad.yy = db; + }); + + afterEach(() => { + railroad.yy.clear(); }); describe('fails to parse', () => { @@ -40,8 +43,8 @@ describe('Railroad diagram', function () { ['rule::=(id|id);'], ['rule::=[id|id];'], ['rule::={id|id};'], - ['rule = "term term";'], - ["rule = 'term term';"], + ['rule = "\'term term\'";'], + ['rule = \'"term term"\';'], ['rule = "";'], ['list = element list | ;'], ['list = element, list | ;'], @@ -53,7 +56,10 @@ describe('Railroad diagram', function () { [" ::= 'while' '(' ')' ;"], ])('%s', (grammar: string) => { grammar = cleanupComments('railroad-beta' + grammar); - expect(() => railroad.parser.parse(grammar)).not.toThrow(); + railroad.parser.parse(grammar); + const x = railroad.yy.getRules() as Rules; + console.log(Object.entries(x).map(([r, e]) => [r, e.toString()])); + // expect(() => railroad.parser.parse(grammar)).not.toThrow(); // railroad.parser.parse(grammar); }); }); diff --git a/packages/mermaid/src/diagrams/railroad/railroadDB.ts b/packages/mermaid/src/diagrams/railroad/railroadDB.ts index 00b2fe6e2e..d009df1504 100644 --- a/packages/mermaid/src/diagrams/railroad/railroadDB.ts +++ b/packages/mermaid/src/diagrams/railroad/railroadDB.ts @@ -6,8 +6,11 @@ import { clear as commonClear } from '../common/commonDb.js'; const clear = (): void => { commonClear(); + + rules = {}; }; +// TODO: move to style config // Styles // // unite rules @@ -31,22 +34,31 @@ const clear = (): void => { // null // type ruleID = string; -type Rules = Record; +export type Rules = Record; let rules: Rules = {}; const getConsole = () => console; -interface Chunk { - traverse(callback: (item: Chunk, nested?: T[]) => T): T; +type Callback = (item: Chunk, index: number, parent: Chunk | undefined, result: T[]) => T; +// type Traverse = (callback: Callback, index: number, parent?: Chunk) => T; + +interface Traversible { + traverse(callback: Callback, index?: number, parent?: Chunk): T; +} + +// TODO: rewrite toString using traverse +// +interface Chunk extends Traversible { toString(): string; } class Leaf implements Chunk { constructor(public label: string) {} - traverse(callback: (item: Chunk, nested?: T[]) => T): T { - return callback(this); + traverse(callback: Callback, index?: number, parent?: Chunk): T { + index ??= 0; + return callback(this, index, parent, []); } toString(): string { @@ -57,23 +69,31 @@ class Leaf implements Chunk { class Node implements Chunk { constructor(public child: Chunk) {} - traverse(callback: (item: Chunk, nested?: T[]) => T): T { - const nested = this.child.traverse(callback); + traverse(callback: Callback, index?: number, parent?: Chunk): T { + index ??= 0; + const nested = this.child.traverse(callback, index, this); - return callback(this, [nested]); + return callback(this, index, parent, [nested]); } } class Chain implements Chunk { constructor(public children: Chunk[]) {} - traverse(callback: (item: Chunk, nested?: T[]) => T): T { - const nested = this.children.map((child) => child.traverse(callback)); + traverse(callback: Callback, index?: number, parent?: Chunk): T { + index ??= 0; + const nested = this.children.map((child, child_index) => + child.traverse(callback, child_index, this) + ); - return callback(this, nested); + return callback(this, index, parent, nested); } } +class Rule { + constructor(public ID: string, public definition: Chunk) {} +} + // Epsilon represents empty transition // // It is implied that every chunk has `start` and `end` states @@ -104,38 +124,33 @@ class NonTerm extends Leaf { class Choice extends Chain { toString(): string { - // const content = '[a' + (this.needsWrapping() ? 'Y' : 'N') + this.chunks.join('|') + 'a]'; - const content = this.children.join('|'); - // if (this.needsWrapping()) - return '(a' + content + 'a)'; - // return content; + const content = this.children.map((c) => c.toString()).join('|'); + return '(' + content + ')'; } } class Sequence extends Chain { toString(): string { - // return '[d' + (this.needsWrapping() ? 'Y' : 'N') + this.chunks.join(',') + 'd]'; - const content = this.children.join(','); - // if (this.needsWrapping()) - return '(c' + content + 'c)'; + const content = this.children.map((c) => c.toString()).join(','); + return '[' + content + ']'; } } class OneOrMany extends Node { toString(): string { - return this.child + '+'; + return this.child.toString() + '+'; } } class ZeroOrOne extends Node { toString(): string { - return this.child + '?'; + return this.child.toString() + '?'; } } class ZeroOrMany extends Node { toString(): string { - return this.child + '?'; + return this.child.toString() + '*'; } } @@ -155,7 +170,7 @@ const addOneOrMany = (chunk: Chunk): Chunk => { const addZeroOrMany = (chunk: Chunk): Chunk => { return new ZeroOrMany(chunk); }; -const addRuleOrChoice = (ID: string, chunk: Chunk) => { +const addRuleOrChoice = (ID: string, chunk: Chunk): void => { if (rules[ID]) { const value = rules[ID]; const alternative = addChoice([value, chunk]); @@ -170,7 +185,7 @@ const addSequence = (chunks: Chunk[]): Chunk => { console.error('Sequence`s chunks are not array', chunks); } - if (configApi.getConfig().railroad?.compressed) { + if (configApi.getConfig().railroad?.compress) { chunks = chunks .map((chunk) => { if (chunk instanceof Sequence) { @@ -193,7 +208,7 @@ const addChoice = (chunks: Chunk[]): Chunk => { console.error('Alternative chunks are not array', chunks); } - if (configApi.getConfig().railroad?.compressed) { + if (configApi.getConfig().railroad?.compress) { chunks = chunks .map((chunk) => { if (chunk instanceof Choice) { @@ -215,8 +230,8 @@ const addEpsilon = (): Chunk => { return new Epsilon(); }; -const getRules = (): Rules => { - return rules; +const getRules = (): Rule[] => { + return Object.entries(rules).map(([ID, definition]) => new Rule(ID, definition)) }; export interface RailroadDB extends DiagramDB { @@ -231,7 +246,7 @@ export interface RailroadDB extends DiagramDB { addZeroOrOne: (chunk: Chunk) => Chunk; clear: () => void; getConsole: () => Console; - getRules: () => Rules; + getRules: () => Rule[]; } export const db: RailroadDB = { diff --git a/packages/mermaid/src/diagrams/railroad/railroadGrammar.jison b/packages/mermaid/src/diagrams/railroad/railroadGrammar.jison index 789742128d..2c2694156a 100644 --- a/packages/mermaid/src/diagrams/railroad/railroadGrammar.jison +++ b/packages/mermaid/src/diagrams/railroad/railroadGrammar.jison @@ -211,7 +211,6 @@ syntax: 'railroad-beta' rule* EOF; rule : rule_id\[rule_id_] '=' choice\[choice_] ';' { - yy.getConsole().log($rule_id_.toString(), '=', $choice_.toString()); yy.addRuleOrChoice($rule_id_, $choice_); }; diff --git a/packages/mermaid/src/diagrams/railroad/railroadRenderer.ts b/packages/mermaid/src/diagrams/railroad/railroadRenderer.ts index 22dfb63912..2b2f621683 100644 --- a/packages/mermaid/src/diagrams/railroad/railroadRenderer.ts +++ b/packages/mermaid/src/diagrams/railroad/railroadRenderer.ts @@ -52,18 +52,19 @@ export const draw: DrawDefinition = (_text, id, _version, diagObj): void => { const db = diagObj.db as RailroadDB; const rules = db.getRules(); - Object.entries(rules).forEach(([label, chunk], index) => { + rules.forEach((rule, index) => { + const {ID: label, definition: chunk} = rule; console.log(`Key: ${label}, Value:`, chunk); const g = svg.append('g').attr('transform', `translate(${0},${10 + index * 20})`); g.append('text').text(label); - chunk.traverse((_item, nested) => { - if (nested === undefined) { - nested = []; - } - const nestedDimensions = nested.reduce((acc, curr) => acc.add(curr), new Dimension(0, 0)); + chunk.traverse((item, index, parent, result) => { + debugger; + console.log(item, index, parent); + + const nestedDimensions = result.reduce((acc, curr) => acc.add(curr), new Dimension(0, 0)); return nestedDimensions; // item.toString() }); diff --git a/packages/mermaid/src/schemas/config.schema.yaml b/packages/mermaid/src/schemas/config.schema.yaml index 266a489324..0baa25d20a 100644 --- a/packages/mermaid/src/schemas/config.schema.yaml +++ b/packages/mermaid/src/schemas/config.schema.yaml @@ -1884,9 +1884,62 @@ $defs: # JSON Schema definition (maybe we should move these to a seperate file) type: object unevaluatedProperties: false properties: - compressed: + alignment: + type: string + enum: + - left + - right + - center + - justify + wrap: type: boolean default: true + description: | + Wrap long grammars similarly to wrapping long lines + syntax: + type: string + enum: + - mermaid + - w3c + - iso + compress: + type: boolean + default: true + description: | + Compress rules to get the smallest possible diagram + display_grammar: + type: boolean + default: true + description: | + Draw grammar definitions inside diagram + angle_brackets: + type: boolean + default: true + description: | + Print angular brackets around non-terminal symbols + draw_arrows: + type: boolean + default: false + inline: + type: boolean + default: false + inline_items: + type: array + items: + type: string + # shapes: + # type: object + # unevaluatedProperties: false + # properties: + # terminal: + # type: string + # enum: + # - left + # - right + # - center + # - justify + # non_terminal: + # type: string FontCalculator: title: Font Calculator diff --git a/run b/run index fbf4372631..c66a3ab398 100755 --- a/run +++ b/run @@ -78,7 +78,10 @@ $(bold ./$name cypress open --project .) Open cypress interactive GUI $(bold ./$name cypress run --spec cypress/integration/rendering/)$(underline test.spec.ts) - Run specific test in cypress\n + Run specific test in cypress + +$(bold ./$name pnpm --filter=mermaid types:build-config) + Update mermaid config based on config schema $(bold xhost +local:) Allow local connections for x11 server