Skip to content

Commit

Permalink
Added traverse functions to railroad db
Browse files Browse the repository at this point in the history
  • Loading branch information
nirname committed Sep 16, 2023
1 parent 438d23e commit c386d49
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 46 deletions.
26 changes: 25 additions & 1 deletion packages/mermaid/src/config.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 13 additions & 7 deletions packages/mermaid/src/diagrams/railroad/railroad.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Check failure on line 5 in packages/mermaid/src/diagrams/railroad/railroad.spec.ts

View workflow job for this annotation

GitHub Actions / lint (18.x)

Import "Rules" is only used as types

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', () => {
Expand Down Expand Up @@ -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 | ;'],
Expand All @@ -53,7 +56,10 @@ describe('Railroad diagram', function () {
["<while-loop> ::= 'while' '(' <condition> ')' <statement>;"],
])('%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()]));

Check failure on line 61 in packages/mermaid/src/diagrams/railroad/railroad.spec.ts

View workflow job for this annotation

GitHub Actions / lint (18.x)

Unexpected console statement
// expect(() => railroad.parser.parse(grammar)).not.toThrow();
// railroad.parser.parse(grammar);
});
});
Expand Down
73 changes: 44 additions & 29 deletions packages/mermaid/src/diagrams/railroad/railroadDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -31,22 +34,31 @@ const clear = (): void => {
// null
// type ruleID = string;

type Rules = Record<string, Chunk>;
export type Rules = Record<string, Chunk>;

let rules: Rules = {};

const getConsole = () => console;

interface Chunk {
traverse<T>(callback: (item: Chunk, nested?: T[]) => T): T;
type Callback<T> = (item: Chunk, index: number, parent: Chunk | undefined, result: T[]) => T;
// type Traverse<T> = (callback: Callback<T>, index: number, parent?: Chunk) => T;

interface Traversible {
traverse<T>(callback: Callback<T>, 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<T>(callback: (item: Chunk, nested?: T[]) => T): T {
return callback(this);
traverse<T>(callback: Callback<T>, index?: number, parent?: Chunk): T {
index ??= 0;
return callback(this, index, parent, []);
}

toString(): string {
Expand All @@ -57,23 +69,31 @@ class Leaf implements Chunk {
class Node implements Chunk {
constructor(public child: Chunk) {}

traverse<T>(callback: (item: Chunk, nested?: T[]) => T): T {
const nested = this.child.traverse(callback);
traverse<T>(callback: Callback<T>, 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<T>(callback: (item: Chunk, nested?: T[]) => T): T {
const nested = this.children.map((child) => child.traverse(callback));
traverse<T>(callback: Callback<T>, 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
Expand Down Expand Up @@ -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() + '*';
}
}

Expand All @@ -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]);
Expand All @@ -170,7 +185,7 @@ const addSequence = (chunks: Chunk[]): Chunk => {
console.error('Sequence`s chunks are not array', chunks);

Check failure on line 185 in packages/mermaid/src/diagrams/railroad/railroadDB.ts

View workflow job for this annotation

GitHub Actions / lint (18.x)

Unexpected console statement
}

if (configApi.getConfig().railroad?.compressed) {
if (configApi.getConfig().railroad?.compress) {
chunks = chunks
.map((chunk) => {

Check failure on line 190 in packages/mermaid/src/diagrams/railroad/railroadDB.ts

View workflow job for this annotation

GitHub Actions / lint (18.x)

Prefer `.flatMap(…)` over `.map(…).flat()`
if (chunk instanceof Sequence) {
Expand All @@ -193,7 +208,7 @@ const addChoice = (chunks: Chunk[]): Chunk => {
console.error('Alternative chunks are not array', chunks);

Check failure on line 208 in packages/mermaid/src/diagrams/railroad/railroadDB.ts

View workflow job for this annotation

GitHub Actions / lint (18.x)

Unexpected console statement
}

if (configApi.getConfig().railroad?.compressed) {
if (configApi.getConfig().railroad?.compress) {
chunks = chunks
.map((chunk) => {

Check failure on line 213 in packages/mermaid/src/diagrams/railroad/railroadDB.ts

View workflow job for this annotation

GitHub Actions / lint (18.x)

Prefer `.flatMap(…)` over `.map(…).flat()`
if (chunk instanceof Choice) {
Expand All @@ -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 {
Expand All @@ -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 = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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_);
};

Expand Down
13 changes: 7 additions & 6 deletions packages/mermaid/src/diagrams/railroad/railroadRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Check failure on line 57 in packages/mermaid/src/diagrams/railroad/railroadRenderer.ts

View workflow job for this annotation

GitHub Actions / lint (18.x)

Unexpected console statement

const g = svg.append('g').attr('transform', `translate(${0},${10 + index * 20})`);

g.append('text').text(label);

chunk.traverse<Dimension>((_item, nested) => {
if (nested === undefined) {
nested = [];
}
const nestedDimensions = nested.reduce((acc, curr) => acc.add(curr), new Dimension(0, 0));
chunk.traverse<Dimension>((item, index, parent, result) => {
debugger;

Check failure on line 64 in packages/mermaid/src/diagrams/railroad/railroadRenderer.ts

View workflow job for this annotation

GitHub Actions / lint (18.x)

Unexpected 'debugger' statement
console.log(item, index, parent);

const nestedDimensions = result.reduce((acc, curr) => acc.add(curr), new Dimension(0, 0));
return nestedDimensions;
// item.toString()
});
Expand Down
55 changes: 54 additions & 1 deletion packages/mermaid/src/schemas/config.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion run
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit c386d49

Please sign in to comment.