Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ebnf2railroad

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ebnf2railroad - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

hsl.html

18

CHANGELOG.md

@@ -7,2 +7,20 @@ # Changelog

## [1.2.0] - 2018-11-01
### Added
- Show validation warnings for duplicate declarations
- Show validation warnings for missing references
- Option `--validate` to exit with status code 2 if document has
warnings
- Option `--quite` to suppress output to console
- Optimize EBNF syntax as `( a ), { a }` in diagram as `a+` (one or more)
- Optimize EBNF syntax as `a | { b }` in diagram as choice with "skip",
"a", or one or more "b"
- Optimize EBNF syntax as `a | [ b ]` in diagram as choice with "skip",
"a", or "b"
### Changed
- Long choice lists are now spread over multiple columns, if the
length exceeds 10.
- Updated styling of document
## [1.1.0] - 2018-10-30

@@ -9,0 +27,0 @@ ### Added

4

package.json
{
"name": "ebnf2railroad",
"version": "1.1.0",
"version": "1.2.0",
"description": "EBNF to Railroad diagram",

@@ -29,3 +29,3 @@ "keywords": [

"commander": "^2.19.0",
"railroad-diagrams": "https://github.com/tabatkins/railroad-diagrams.git",
"railroad-diagrams": "https://github.com/matthijsgroen/railroad-diagrams.git#add-horizontal-choice",
"showdown": "^1.8.7"

@@ -32,0 +32,0 @@ },

@@ -17,3 +17,12 @@ # EBNF 2 RailRoad

```
ebnf2railroad my-definition.ebnf
Usage: ebnf2railroad [options] <file>
Converts an ISO/IEC 14977 EBNF file to a HTML file with SVG railroad diagrams
Options:
-V, --version output the version number
-o, --target [target] output the file to target destination.
-q, --quiet suppress output to STDOUT
--validate exit with status code 2 if ebnf document has warnings
-h, --help output usage information
```

@@ -20,0 +29,0 @@

@@ -6,3 +6,3 @@ const program = require("commander");

const { parser } = require("./ebnf-parser");
const { createDocumentation, optimizeAst } = require("./report-builder");
const { createDocumentation, valididateEbnf } = require("./report-builder");

@@ -14,2 +14,4 @@ program.version("1.0.0");

.option("-o, --target [target]", "output the file to target destination.")
.option("-q, --quiet", "suppress output to STDOUT")
.option("--validate", "exit with status code 2 if ebnf document has warnings")
.description(

@@ -25,2 +27,3 @@ "Converts an ISO/IEC 14977 EBNF file to a HTML file with SVG railroad diagrams"

}
const allowOutput = !program.quiet;

@@ -39,9 +42,17 @@ try {

const ast = parser.parse(ebnf);
const optimizedAst = optimizeAst(ast);
const report = createDocumentation(optimizedAst, {
const warnings = valididateEbnf(ast);
warnings.length > 0 &&
allowOutput &&
warnings.forEach(warning => console.warn(warning));
const report = createDocumentation(ast, {
title: basename
});
await writeFile(targetFilename, report, "utf8");
allowOutput && console.log(`📜 Document created at ${targetFilename}`);
warnings.length > 0 && program.validate && process.exit(2);
} catch (e) {
console.error(e.message);
if (allowOutput) console.error(e.message);
process.exit(1);

@@ -48,0 +59,0 @@ }

@@ -96,3 +96,3 @@ /* parser generated by jison 0.4.18 */

case 4:
this.$ = { identifier: $$[$0-3].trim(), definition: $$[$0-1] };
this.$ = { identifier: $$[$0-3].trim(), definition: $$[$0-1], location: _$[$0-3].first_line };
break;

@@ -99,0 +99,0 @@ case 6:

@@ -5,2 +5,3 @@ const {

Diagram,
HorizontalChoice,
NonTerminal,

@@ -73,2 +74,4 @@ OneOrMore,

const SHRINK_CHOICE = 10;
const productionToDiagram = production => {

@@ -84,2 +87,5 @@ if (production.identifier) {

}
if (production.skip) {
return Skip();
}
if (production.specialSequence) {

@@ -91,4 +97,13 @@ const sequence = Terminal(" " + production.specialSequence + " ");

if (production.choice) {
const makeChoice = items => new Choice(0, items);
const options = production.choice.map(productionToDiagram);
return Choice(0, ...options);
const choiceLists = [];
while (options.length > SHRINK_CHOICE) {
const subList = options.splice(0, SHRINK_CHOICE);
choiceLists.push(makeChoice(subList));
}
choiceLists.push(makeChoice(options));
return choiceLists.length > 1
? HorizontalChoice(...choiceLists)
: choiceLists[0];
}

@@ -195,3 +210,3 @@ if (production.sequence) {

}
const diagram = productionToDiagram(production);
const diagram = productionToDiagram(optimizeProduction(production));
return ebnfTemplate({

@@ -216,2 +231,8 @@ identifier: production.identifier,

const skipFirst = list =>
[
list.some(e => e === "skip") && { skip: true },
...list.filter(e => e !== "skip")
].filter(Boolean);
const optimizeProduction = production => {

@@ -227,3 +248,23 @@ if (production.definition) {

...production,
choice: production.choice.map(optimizeProduction)
choice: skipFirst(
production.choice
.map((item, idx, list) => {
const optimizedItem = optimizeProduction(item);
if (optimizedItem.repetition && optimizedItem.skippable) {
return [
"skip",
{
...optimizedItem,
skippable: false
}
];
} else if (optimizedItem.optional) {
return ["skip", optimizedItem.optional];
} else {
return [optimizedItem];
}
})
.reduce((acc, item) => acc.concat(item), [])
.filter((item, index, list) => list.indexOf(item) === index)
)
};

@@ -239,8 +280,18 @@ }

const isSame =
JSON.stringify(ahead.repetition) === JSON.stringify(item);
JSON.stringify(ahead.repetition) === JSON.stringify(item) ||
(item.group &&
JSON.stringify(ahead.repetition) ===
JSON.stringify(item.group));
if (isSame) {
ahead.skippable = false;
ahead.changeSkippable = true;
return false;
}
}
if (item.changeSkippable) {
delete item["changeSkippable"];
return {
...optimizeProduction(item),
skippable: false
};
}
return optimizeProduction(item);

@@ -273,7 +324,36 @@ })

const optimizeAst = ast => ast.map(line => optimizeProduction(line));
const valididateEbnf = ast => {
const identifiers = ast.map(production => production.identifier);
const doubleDeclarations = ast
.map((declaration, index) => {
// skip comments, but keep index in array intact (filter would break index)
if (!declaration.identifier) return false;
const firstDeclaration = identifiers.indexOf(declaration.identifier);
if (firstDeclaration === index) return false;
return `${declaration.location}: Duplicate declaration: "${
declaration.identifier
}" already declared on line ${ast[firstDeclaration].location}.`;
})
.filter(Boolean);
const missingReferences = ast
.filter(declaration => declaration.identifier)
.map(declaration =>
getReferences(declaration)
.filter((item, index, list) => list.indexOf(item) === index)
.filter(reference => !identifiers.includes(reference))
.map(
missingReference =>
`${declaration.location}: Missing reference: "${missingReference}".`
)
)
.filter(m => m.length > 0)
.reduce((acc, elem) => acc.concat(elem), []);
return doubleDeclarations.concat(missingReferences).sort();
};
module.exports = {
createDocumentation,
optimizeAst
valididateEbnf
};

@@ -26,4 +26,6 @@ const { Converter } = require("showdown");

color: #0F0C00;
background: #FFFCF0;
background: #FFFCFC;
}
h1 { font-size: 2em; }
h2 { font-size: 1.5em; }
code {

@@ -30,0 +32,0 @@ padding: 1em 1em 1em 3em;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc