Skip to content

Commit

Permalink
Extended railroad config
Browse files Browse the repository at this point in the history
  • Loading branch information
nirname committed Sep 24, 2023
1 parent dd5fa3e commit 681d8c9
Show file tree
Hide file tree
Showing 9 changed files with 279 additions and 228 deletions.
1 change: 1 addition & 0 deletions .vite/jsonSchemaPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
'gitGraph',
'c4',
'sankey',
'railroad',
] as const;

/**
Expand Down
1 change: 1 addition & 0 deletions packages/mermaid/scripts/create-types-from-json-schema.mts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ async function generateTypescript(mermaidConfigSchema: JSONSchemaType<MermaidCon
assert.ok(mermaidConfigSchema.$defs);
const modifiedSchema = {
...unrefSubschemas(removeRequired(mermaidConfigSchema)),
//...removeRequired(mermaidConfigSchema),

$defs: Object.fromEntries(
Object.entries(mermaidConfigSchema.$defs).map(([key, subSchema]) => {
Expand Down
144 changes: 81 additions & 63 deletions packages/mermaid/src/config.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@
* Configuration options to pass to the `dompurify` library.
*/
export type DOMPurifyConfiguration = import('dompurify').Config;
/**
* Shapes of the first and the last state in the diagram
*
*
* This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "RailroadDiagramBoundaryShape".
*/
export type RailroadDiagramBoundaryShape = 'dot' | 'circle' | 'forward' | 'backward';
export type RailroadDiagramFormat1 = RailroadDiagramFormat;
/**
* JavaScript function that returns a `FontConfig`.
*
Expand Down Expand Up @@ -50,14 +59,6 @@ export type SankeyLinkColor = 'source' | 'target' | 'gradient';
* via the `definition` "SankeyNodeAlignment".
*/
export type SankeyNodeAlignment = 'left' | 'right' | 'center' | 'justify';
/**
* Shapes of the first and the last state in the diagram
*
*
* This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "RailroadDiagramBoundaryShape".
*/
export type RailroadDiagramBoundaryShape = 'dot' | 'circle' | 'forward' | 'backward';
/**
* The font size to use
*/
Expand Down Expand Up @@ -182,6 +183,78 @@ export interface BaseDiagramConfig {
*/
useMaxWidth?: boolean;
}
/**
* This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "RailroadDiagramFormat".
*/
export interface RailroadDiagramFormat {
/**
* Force angular brackets around non-terminal symbols
*
*/
forceAngleBrackets?: boolean;
/**
* Force comma as a concatenation symbol in the rule definition
*
*/
forceComma?: boolean;
}
/**
* The object containing configurations specific for railroad diagrams.
*
* This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "RailroadDiagramConfig".
*/
export interface RailroadDiagramConfig extends BaseDiagramConfig {
alignment?: 'left' | 'right' | 'center' | 'justify';
verticalAlignment?: 'top' | 'bottom' | 'center' | 'justify';
/**
* Wrap long grammars similarly to wrapping long lines
*
*/
wrapDiagram?: boolean;
/**
* Specify which standart would be applied
*
*/
syntax?: 'mermaid' | 'w3c' | 'iso';
/**
* Compress rules to get the smallest possible diagram
*
*/
compress?: boolean;
/**
* List of things to render
*
*/
render?: ('railroad' | 'ebnf' | 'bnf' | 'dfa' | 'nfa')[];
format?: RailroadDiagramFormat1;
drawArrows?: boolean;
inline?: boolean;
inlineItems?: string[];
/**
* Name of the initial rule in grammar
* First rule will be initial if it is null
*
*/
start?: string | null;
shapes?: {
terminal?: string;
non_terminal?: string;
/**
* Shape or list of shapes for the start element
* They will be applied in the order of occurrence
*
*/
start?: RailroadDiagramBoundaryShape[] | RailroadDiagramBoundaryShape;
/**
* Shape or list of shapes for the end element
* They will be applied in the order of occurrence
*
*/
end?: RailroadDiagramBoundaryShape[] | RailroadDiagramBoundaryShape;
};
}
/**
* The object containing configurations specific for c4 diagrams
*
Expand Down Expand Up @@ -1323,61 +1396,6 @@ export interface SankeyDiagramConfig extends BaseDiagramConfig {
*/
suffix?: string;
}
/**
* The object containing configurations specific for railroad diagrams.
*
* This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "RailroadDiagramConfig".
*/
export interface RailroadDiagramConfig extends BaseDiagramConfig {
alignment?: 'left' | 'right' | 'center' | 'justify';
verticalAlignment?: 'top' | 'bottom' | 'center' | 'justify';
/**
* Wrap long grammars similarly to wrapping long lines
*
*/
wrapDiagram?: boolean;
/**
* Compress rules to get the smallest possible diagram
*
*/
compress?: boolean;
/**
* List of things to render
*
*/
render?: ('railroad' | 'ebnf' | 'bnf' | 'dfa' | 'nfa')[];
/**
* Force angular brackets around non-terminal symbols
*
*/
angleBrackets?: boolean;
drawArrows?: boolean;
inline?: boolean;
inlineItems?: string[];
/**
* Name of the initial rule in grammar
* First rule will be initial if it is null
*
*/
start?: string | null;
shapes?: {
terminal?: string;
non_terminal?: string;
/**
* Shape or list of shapes for the start element
* They will be applied in the order of occurrence
*
*/
start?: RailroadDiagramBoundaryShape[] | RailroadDiagramBoundaryShape;
/**
* Shape or list of shapes for the end element
* They will be applied in the order of occurrence
*
*/
end?: RailroadDiagramBoundaryShape[] | RailroadDiagramBoundaryShape;
};
}
/**
* This interface was referenced by `MermaidConfig`'s JSON-Schema
* via the `definition` "FontConfig".
Expand Down
3 changes: 2 additions & 1 deletion packages/mermaid/src/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,8 @@ const config: RequiredDeep<MermaidConfig> = {
},
railroad: {
...defaultConfigJson.railroad,
}
useMaxWidth: true,
},
};

const keyify = (obj: any, prefix = ''): string[] =>
Expand Down
15 changes: 8 additions & 7 deletions packages/mermaid/src/diagrams/railroad/railroad.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
import railroad from './railroadGrammar.jison';
// import { prepareTextForParsing } from '../railroadUtils.js';
import { cleanupComments } from '../../diagram-api/comments.js';
import { db, Rules } from './railroadDB.js';
// import defaultConfigJson from '../../schemas/config.schema.yaml?only-defaults=true';
import { db, Rule } from './railroadDB.js';
// @ts-ignore: yaml
import defaultConfigJson from '../../schemas/config.schema.yaml?only-defaults=true';

describe('Railroad diagram', function () {
beforeAll(() => {
// console.log(defaultConfigJson);
console.log(defaultConfigJson);

railroad.yy = db;
});

Expand Down Expand Up @@ -60,9 +61,9 @@ describe('Railroad diagram', function () {
])('%s', (grammar: string) => {
grammar = cleanupComments('railroad-beta' + grammar);
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();
const x = railroad.yy.getRules() as Rule[];
console.log(x.map((r) => r.toEBNF()));
// expect(() => { railroad.parser.parse(grammar); }).not.toThrow();
// railroad.parser.parse(grammar);
});
});
Expand Down
62 changes: 37 additions & 25 deletions packages/mermaid/src/diagrams/railroad/railroadDB.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// import type { RailroadDB } from './railroadTypes.js';
import { config } from 'process';
import * as configApi from '../../config.js';
import type { DiagramDB } from '../../diagram-api/types.js';

import { clear as commonClear } from '../common/commonDb.js';

const railroadConfig = configApi.getConfig().railroad;

const clear = (): void => {
commonClear();

Expand Down Expand Up @@ -47,16 +50,17 @@ type Callback<T> = (item: Chunk, index: number, parent: Chunk | undefined, resul
// traverse<T>(callback: Callback<T>, index?: number, parent?: Chunk): T;
// }

// TODO: rewrite toString using traverse
// TODO: rewrite toEBNF using traverse
//
// interface Chunk extends Traversible {
// toString(): string;
// }
// toEBNF(): string;
// }

abstract class Chunk {
// static staticMethod(): void;
static display: ((instance: Chunk) => void) | undefined;
abstract traverse<T>(callback: Callback<T>, index?: number, parent?: Chunk): T;
abstract toEBNF(): string;
}

class Leaf implements Chunk {
Expand All @@ -67,12 +71,12 @@ class Leaf implements Chunk {
return callback(this, index, parent, []);
}

toString(): string {
toEBNF(): string {
return this.label;
}
}

class Node implements Chunk {
abstract class Node implements Chunk {
constructor(public child: Chunk) {}

traverse<T>(callback: Callback<T>, index?: number, parent?: Chunk): T {
Expand All @@ -81,9 +85,11 @@ class Node implements Chunk {

return callback(this, index, parent, [nested]);
}

abstract toEBNF(): string;
}

class Chain implements Chunk {
abstract class Chain implements Chunk {
constructor(public children: Chunk[]) {}

traverse<T>(callback: Callback<T>, index?: number, parent?: Chunk): T {
Expand All @@ -94,10 +100,15 @@ class Chain implements Chunk {

return callback(this, index, parent, nested);
}

abstract toEBNF(): string;
}

class Rule {
export class Rule {
constructor(public ID: string, public definition: Chunk) {}
toEBNF() {
return `${this.ID} ::= ${this.definition.toEBNF()}`;
}
}

// Epsilon represents empty transition
Expand All @@ -117,46 +128,47 @@ class Term extends Leaf {
super(label);
}

toString(): string {
return this.quote + super.toString() + this.quote;
toEBNF(): string {
return this.quote + super.toEBNF() + this.quote;
}
}

class NonTerm extends Leaf {
toString(): string {
return '<' + super.toString() + '>';
toEBNF(): string {
return '<' + super.toEBNF() + '>';
}
}

class Choice extends Chain {
toString(): string {
const content = this.children.map((c) => c.toString()).join('|');
toEBNF(): string {
const content = this.children.map((c) => c.toEBNF()).join('|');
return '(' + content + ')';
}
}

class Sequence extends Chain {
toString(): string {
const content = this.children.map((c) => c.toString()).join(',');
return '[' + content + ']';
toEBNF(): string {
const delimiter = railroadConfig?.format?.forceComma ? ', ' : ' ';
const content = this.children.map((c) => c.toEBNF()).join(delimiter);
return content;
}
}

class OneOrMany extends Node {
toString(): string {
return this.child.toString() + '+';
toEBNF(): string {
return this.child.toEBNF() + '+';
}
}

class ZeroOrOne extends Node {
toString(): string {
return this.child.toString() + '?';
toEBNF(): string {
return this.child.toEBNF() + '?';
}
}

class ZeroOrMany extends Node {
toString(): string {
return this.child.toString() + '*';
toEBNF(): string {
return this.child.toEBNF() + '*';
}
}

Expand Down Expand Up @@ -191,7 +203,7 @@ const addSequence = (chunks: Chunk[]): Chunk => {
console.error('Sequence`s chunks are not array', chunks);
}

if (configApi.getConfig().railroad?.compress) {
if (railroadConfig?.compress) {
chunks = chunks
.map((chunk) => {
if (chunk instanceof Sequence) {
Expand Down Expand Up @@ -237,7 +249,7 @@ const addEpsilon = (): Chunk => {
};

const getRules = (): Rule[] => {
return Object.entries(rules).map(([ID, definition]) => new Rule(ID, definition))
return Object.entries(rules).map(([ID, definition]) => new Rule(ID, definition));
};

export interface RailroadDB extends DiagramDB {
Expand Down
Loading

0 comments on commit 681d8c9

Please sign in to comment.