Skip to content

Commit

Permalink
Merge pull request #44 from matthijsgroen/create-overview
Browse files Browse the repository at this point in the history
Create overview diagrams
  • Loading branch information
matthijsgroen authored Sep 23, 2020
2 parents 5823f31 + 6e697c0 commit dccd941
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 21 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ and this project adheres to

### Added

- Support for optimizing source diagram using `--rewrite`
- Support for generation overview diagrams on root elements, skippable with
`--no-overview-diagram`
- Support for optimizing source definition file using `--rewrite`
- Skip only diagram wrapping with `--no-diagram-wrap`
- Breaking of long elements over multiple lines in optional items `[]`
- Plain text will now also be optimized when reasonable: Text will not be
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ based on the ISO/IEC 14977 specification
- Validates if document is complete and has no duplicate declarations
- Shows pretty printed text syntax in the document
- Pretty printing of the sourcefile
- Table of contents indicating root elements, character sets, common elements
and recursion
- Generation of large overview diagrams for root elements

## Installation

Expand All @@ -41,6 +44,7 @@ Options:
--lint exit with status code 2 if EBNF document has warnings
--write-style rewrites the source document with styled text
--no-optimizations does not try to optimize the diagrams
--no-overview-diagram skip creating overview diagrams for root elements
--no-diagram-wrap does not wrap diagrams for width minimization
--no-text-formatting does not format the output text version (becomes single line)
--dump-ast dump EBNF file AST to target destination for further processing
Expand Down
6 changes: 6 additions & 0 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ program
"--no-optimizations",
"does not try to optimize the diagrams and texts"
)
.option(
"--no-overview-diagram",
"skip creating overview diagrams for root elements"
)
.option("--no-diagram-wrap", "does not wrap diagrams for width minimization")
.option(
"--no-text-formatting",
Expand All @@ -46,6 +50,7 @@ async function run(args) {
}
const allowOutput = !program.quiet;
const optimizeDiagrams = program.optimizations;
const overviewDiagram = program.overviewDiagram;
const optimizeText = program.optimizations;
const textFormatting = program.textFormatting;
const diagramWrap = program.diagramWrap;
Expand Down Expand Up @@ -112,6 +117,7 @@ async function run(args) {
optimizeDiagrams,
optimizeText,
textFormatting,
overviewDiagram,
diagramWrap
});
await writeFile(targetFilename, report, "utf8");
Expand Down
77 changes: 75 additions & 2 deletions src/extra-diagram-elements.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
const { FakeSVG, Path, Diagram } = require("railroad-diagrams");
const {
FakeSVG,
Path,
Diagram,
Comment,
Terminal
} = require("railroad-diagrams");

const subclassOf = (baseClass, superClass) => {
baseClass.prototype = Object.create(superClass.prototype);
Expand Down Expand Up @@ -61,6 +67,73 @@ CommentWithLine.prototype.format = function(x, y, width) {
return this;
};

function wrapString(value) {
return value instanceof FakeSVG ? value : new Terminal("" + value);
}

const Group = function Group(item, label) {
if (!(this instanceof Group)) return new Group(item, label);
FakeSVG.call(this, "g");
this.item = wrapString(item);
this.label =
label instanceof FakeSVG ? label : label ? new Comment(label) : undefined;

this.width = Math.max(
this.item.width + (this.item.needsSpace ? 20 : 0),
this.label ? this.label.width : 0,
Diagram.ARC_RADIUS * 2
);
this.height = this.item.height;
this.boxUp = this.up = Math.max(
this.item.up + Diagram.VERTICAL_SEPARATION,
Diagram.ARC_RADIUS
);
if (this.label) {
this.up += this.label.up + this.label.height + this.label.down;
}
this.down = Math.max(
this.item.down + Diagram.VERTICAL_SEPARATION,
Diagram.ARC_RADIUS
);
this.needsSpace = true;
if (Diagram.DEBUG) {
this.attrs["data-updown"] = this.up + " " + this.height + " " + this.down;
this.attrs["data-type"] = "group";
}
};
subclassOf(Group, FakeSVG);
Group.prototype.needsSpace = true;
Group.prototype.format = function(x, y, width) {
var gaps = determineGaps(width, this.width);
new Path(x, y).h(gaps[0]).addTo(this);
new Path(x + gaps[0] + this.width, y + this.height).h(gaps[1]).addTo(this);
x += gaps[0];

new FakeSVG("rect", {
x,
y: y - this.boxUp,
width: this.width,
height: this.boxUp + this.height + this.down,
rx: Diagram.ARC_RADIUS,
ry: Diagram.ARC_RADIUS,
class: "group-box"
}).addTo(this);

this.item.format(x, y, this.width).addTo(this);
if (this.label) {
this.label
.format(
x,
y - (this.boxUp + this.label.down + this.label.height),
this.label.width
)
.addTo(this);
}

return this;
};

module.exports = {
CommentWithLine
CommentWithLine,
Group
};
78 changes: 60 additions & 18 deletions src/report-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const {
createDefinitionMetadata
} = require("./toc");
const { productionToEBNF } = require("./ebnf-builder");
const { CommentWithLine } = require("./extra-diagram-elements");
const { CommentWithLine, Group } = require("./extra-diagram-elements");

const dasherize = str => str.replace(/\s+/g, "-");

Expand Down Expand Up @@ -94,6 +94,9 @@ const productionToDiagram = (production, options) => {
return Terminal(production.terminal);
}
if (production.nonTerminal) {
if (options.renderNonTerminal) {
return options.renderNonTerminal(production.nonTerminal);
}
return NonTerminal(production.nonTerminal, {
href: `#${dasherize(production.nonTerminal)}`
});
Expand Down Expand Up @@ -247,6 +250,54 @@ const createTocStructure = (tocData, metadata) =>
)
.join("");

const createDiagram = (production, metadata, ast, options) => {
const renderProduction =
options.optimizeDiagrams === false
? production
: optimizeProduction(production);

const baseOptions = {
maxChoiceLength: options.optimizeDiagrams ? MAX_CHOICE_LENGTH : Infinity,
optimizeSequenceLength: options.diagramWrap && options.optimizeDiagrams
};

const expanded = [];

const renderNonTerminal = item => {
if (options.overview) {
const expand = !expanded.includes(item) && !metadata[item].characterSet;

if (expand) {
const nested = ast.find(node => node.identifier === item);
expanded.push(item);
return Group(
productionToDiagram(nested.definition, {
...baseOptions,
renderNonTerminal
}),
Comment(item, { href: `#${dasherize(item)}` })
);
}
}
return NonTerminal(item, {
href: `#${dasherize(item)}`
});
};

const diagram = productionToDiagram(
{
...renderProduction,
complex: options.complex
},
{
...baseOptions,
renderNonTerminal
}
);

return diagram;
};

const createDocumentation = (ast, options) => {
const structuralToc = createStructuralToc(ast);
const metadata = createDefinitionMetadata(structuralToc);
Expand All @@ -256,28 +307,19 @@ const createDocumentation = (ast, options) => {
if (production.comment) {
return commentTemplate(production.comment);
}

const outgoingReferences = searchReferencesFromIdentifier(
production.identifier,
ast
);
const renderProduction =
options.optimizeDiagrams === false
? production
: optimizeProduction(production);

const diagram = productionToDiagram(
{
...renderProduction,
complex: outgoingReferences.length > 0
},
{
maxChoiceLength: options.optimizeDiagrams
? MAX_CHOICE_LENGTH
: Infinity,
optimizeSequenceLength:
options.diagramWrap && options.optimizeDiagrams
}
);
const diagram = createDiagram(production, metadata, ast, {
...options,
overview:
metadata[production.identifier].root && options.overviewDiagram,
complex: outgoingReferences.length > 0
});

return ebnfTemplate({
identifier: production.identifier,
ebnf: productionToEBNF(
Expand Down
5 changes: 5 additions & 0 deletions src/report-html-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,11 @@ svg.railroad-diagram g.special-sequence text {
svg.railroad-diagram rect {
stroke-width: 3;
}
svg.railroad-diagram rect.group-box {
stroke: gray;
stroke-dasharray: 10 5;
fill: none;
}
svg.railroad-diagram g.non-terminal rect {
fill: var(--nonTerminalFill);
stroke: var(--nonTerminalLines);
Expand Down

0 comments on commit dccd941

Please sign in to comment.