New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.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.6.0 to 1.7.0

11

CHANGELOG.md

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

## [1.7.0] - 2018-11-22
### Added
- Syntax diagram will wrap if sequences become very long
- Split navigation bar in 3 parts. Root elements, Normal elements,
Common elements
- Added Marker of recursion in navigation list
- Responsive design, mobile navigation, overall styling
### Fixed
- Small pretty print issues that caused weird line breaks
## [1.6.0] - 2018-11-13

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

2

package.json
{
"name": "ebnf2railroad",
"version": "1.6.0",
"version": "1.7.0",
"description": "EBNF to Railroad diagram",

@@ -5,0 +5,0 @@ "keywords": [

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

const MAX_LINE_LENGTH = 40;
const LINE_MARGIN_LENGTH = 30;

@@ -29,2 +30,3 @@ const defaultOptions = {

maxLineLength: MAX_LINE_LENGTH,
lineMargin: LINE_MARGIN_LENGTH,
indent: 0

@@ -36,3 +38,5 @@ };

item.choice &&
item.choice.length > 2 &&
(item.choice.length > 2 ||
productionToEBNF(item, { format: false, markup: false }).length >
options.maxLineLength) &&
item.choice.length <= 6 &&

@@ -44,2 +48,3 @@ options.format;

...options,
offsetLength: 0,
multiline: true,

@@ -65,2 +70,3 @@ indent: 1,

multiline: true,
offsetLength: 0,
rowCount,

@@ -72,15 +78,7 @@ padding: true,

const sequence = item.sequence && options.format;
if (sequence) {
return {
...options,
lineWrap: true
};
}
return options;
};
const calculateMaxLength = production => {
const output = productionToEBNF(production, { markup: false, format: true });
const calculateMaxLength = (production, format) => {
const output = productionToEBNF(production, { markup: false, format });
const multiLine = output.includes("\n");

@@ -182,23 +180,57 @@ return multiLine ? -1 : output.length;

if (production.sequence) {
return production.sequence
.map(element => ({
output: productionToEBNF(element, { ...options, offsetLength: 0 }),
length: calculateMaxLength(element)
}))
.map((elem, index, list) => {
if (index === 0) return elem.output;
const indent = options.indent + 1;
const currentOffset = list
.slice(0, index - 1)
.reduce(
(acc, elem) => (elem.length === -1 ? 0 : acc + elem.length + 3),
options.offsetLength || 0
const sequenceLength = (list, offset, till = undefined) =>
list
.slice(0, till)
.reduce(
(acc, elem) => (elem.length === -1 ? 0 : acc + elem.length + 3),
offset
);
return (
production.sequence
.map(element => ({
element,
length: calculateMaxLength(element, options.format)
}))
.map(({ element }, index, list) => {
if (index === 0) return productionToEBNF(element, options);
const indent = options.indent + 1;
const currentLength = sequenceLength(
list,
options.offsetLength || 0,
index
);
const addBreak = currentOffset + indent * 2 > options.maxLineLength;
if (addBreak) list[index - 1].length = -1;
const nextLength = sequenceLength(
list,
options.offsetLength || 0,
index + 1
);
const totalLength = sequenceLength(list, options.offsetLength || 0);
const addBreak =
options.format &&
currentLength > options.maxLineLength &&
nextLength > options.maxLineLength + options.lineMargin / 2 &&
totalLength - currentLength > 10;
if (addBreak) list[index - 1].length = -1;
return ` ,${addBreak ? lineIndent(indent) : " "}${elem.output}`;
})
.join("");
const offsetLength = addBreak ? 0 : currentLength;
const output = productionToEBNF(element, {
...options,
offsetLength
});
if (options.format && output.indexOf("\n") !== -1) {
const lastLineLength = output.split("\n").slice(-1)[0].length;
list[index].length = lastLineLength - currentLength;
}
return ` ,${addBreak ? lineIndent(indent) : " "}${output}`;
})
.join("")
// Remove potentially added whitespace paddings at the end of the line
.split("\n")
.map(line => line.trimEnd())
.join("\n")
);
}

@@ -205,0 +237,0 @@ if (production.specialSequence) {

@@ -11,4 +11,6 @@ const {

Skip,
Stack,
Terminal
} = require("railroad-diagrams");
const { optimizeProduction } = require("./structure-optimizer");

@@ -27,6 +29,59 @@ const {

} = require("./references");
const { createAlphabeticalToc, createStructuralToc } = require("./toc");
const {
createAlphabeticalToc,
createStructuralToc,
createDefinitionMetadata
} = require("./toc");
const { productionToEBNF } = require("./ebnf-builder");
const dasherize = str => str.replace(/\s+/g, "-");
const EXTRA_DIAGRAM_PADDING = 1;
const determineDiagramSequenceLength = production => {
if (production.sequence) {
return production.sequence.reduce(
(total, elem) =>
determineDiagramSequenceLength(elem) + EXTRA_DIAGRAM_PADDING + total,
0
);
}
if (production.nonTerminal) {
return production.nonTerminal.length + EXTRA_DIAGRAM_PADDING;
}
if (production.terminal) {
return production.terminal.length + EXTRA_DIAGRAM_PADDING;
}
if (production.group) {
return determineDiagramSequenceLength(production.group);
}
if (production.choice) {
return (
production.choice
.map(elem => determineDiagramSequenceLength(elem))
.reduce((max, elem) => (max > elem ? max : elem), 0) +
EXTRA_DIAGRAM_PADDING * 2
);
}
if (production.repetition) {
const repetitionLength = determineDiagramSequenceLength(
production.repetition
);
const repeaterLength = production.repeater
? determineDiagramSequenceLength(production.repeater)
: 0;
return (
Math.max(repetitionLength, repeaterLength) +
EXTRA_DIAGRAM_PADDING * 2 +
(production.skippable ? EXTRA_DIAGRAM_PADDING * 2 : 0)
);
}
if (production.optional) {
return (
determineDiagramSequenceLength(production.optional) +
EXTRA_DIAGRAM_PADDING * 2
);
}
return 0;
};
const SHRINK_CHOICE = 10;

@@ -70,2 +125,34 @@

if (production.sequence) {
const sequenceLength = determineDiagramSequenceLength(production);
if (sequenceLength > 45) {
const subSequences = production.sequence
.reduce(
(totals, elem, index, list) => {
const lastList = totals.slice(-1)[0];
lastList.push(elem);
const currentLength = determineDiagramSequenceLength({
sequence: lastList
});
const remainingLength = determineDiagramSequenceLength({
sequence: list.slice(index + 1)
});
if (
currentLength + remainingLength > 40 &&
currentLength >= 25 &&
remainingLength > 10
) {
totals.push([]);
}
return totals;
},
[[]]
)
.filter(array => array.length > 0);
return Stack(
...subSequences.map(subSequence =>
Sequence(...subSequence.map(productionToDiagram))
)
);
}
return Sequence(...production.sequence.map(productionToDiagram));

@@ -125,11 +212,23 @@ }

const createTocStructure = tocData =>
const createTocStructure = (tocData, metadata) =>
tocData
.map(
tocNode =>
`<li><a href="#${dasherize(
`<li${
metadata[tocNode.name].root
? ' class="root-node"'
: metadata[tocNode.name].common
? ' class="common-node"'
: ""
}><a href="#${dasherize(
tocNode.name.trim()
)}">${tocNode.name.trim()} ${tocNode.recursive ? "↖︎" : ""}</a>${
)}">${tocNode.name.trim()}</a>
${
metadata[tocNode.name].recursive
? '<dfn title="recursive">♺</dfn>'
: ""
}
${
tocNode.children
? `<ul>${createTocStructure(tocNode.children)}</ul>`
? `<ul>${createTocStructure(tocNode.children, metadata)}</ul>`
: ""

@@ -173,4 +272,13 @@ }

const alphabeticalToc = createTocStructure(createAlphabeticalToc(ast));
const hierarchicalToc = createTocStructure(createStructuralToc(ast));
const structuralToc = createStructuralToc(ast);
const metadata = createDefinitionMetadata(structuralToc);
const alphabetical = createAlphabeticalToc(ast);
const rootItems = alphabetical.filter(item => metadata[item.name].root);
const commonItems = alphabetical.filter(
item => !metadata[item.name].root && metadata[item.name].common
);
const otherItems = alphabetical.filter(
item => !metadata[item.name].root && !metadata[item.name].common
);
const hierarchicalToc = createTocStructure(structuralToc, metadata);

@@ -180,4 +288,9 @@ const htmlContent = documentContent({

contents,
alphabeticalToc,
hierarchicalToc
singleRoot: rootItems.length === 1,
toc: {
hierarchical: hierarchicalToc,
common: createTocStructure(commonItems, metadata),
roots: createTocStructure(rootItems, metadata),
other: createTocStructure(otherItems, metadata)
}
});

@@ -184,0 +297,0 @@ return options.full !== false

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

const documentContent = ({
title,
contents,
alphabeticalToc,
hierarchicalToc
}) =>
const documentContent = ({ title, contents, toc, singleRoot }) =>
`<header>
<h1>${title}</h1>
<button type="button"></button>
</header>
<main>
<nav>
<h3>Root element${singleRoot ? "" : "s"}:</h3>
<ul class="nav-alphabetical">
${toc.roots}
</ul>
<h3>Quick navigation:</h3>
<ul class="nav-alphabetical">
${alphabeticalToc}
${toc.other}
</ul>
<h3>Common elements:</h3>
<ul class="nav-alphabetical">
${toc.common}
</ul>
</nav>
<main>
<article>
${contents}
</article>
<nav>
<h3>Language overview</h3>
<ul class="nav-hierarchical">
${hierarchicalToc}
</ul>
</nav>
</main>`;
</main>
<script type="text/javascript">
document.querySelector("header button").addEventListener("click", function() {
document.getElementsByTagName("html")[0].classList.toggle("menu-open");
});
document.querySelector("nav").addEventListener("click", function(event) {
if (event.target.tagName !== "A") return;
document.getElementsByTagName("html")[0].classList.remove("menu-open");
});
</script>
`;
const documentStyle = () =>
`/* Text styling */
body {
font: normal 12px Verdana, sans-serif;
color: #0F0C00;
background: #FFFCFC;
}
h1 { font-size: 2em; }
h2 { font-size: 1.5em; }
a,
a:visited,
a:active {
color: #0F0C00;
}
a:hover {
color: #000;
}
section h4 {
margin-bottom: 0;
}
`
html {
box-sizing: border-box;
}
/* EBNF text representation styling */
code.ebnf {
padding: 1em 1em 1em 1em;
background: rgb(255, 246, 209);
font-weight: bold;
color: #777;
*, *:before, *:after {
box-sizing: inherit;
}
:root {
--subtleText: #777;
--highlightText: hotpink;
--itemHeadingBackground: #eee;
--diagramBackground: #f8f8f8;
}
html {
font-family: sans-serif;
}
html, body {
margin: 0;
padding: 0;
}
a {
color: inherit;
}
a:visited {
color: var(--subtleText);
}
a:active, a:focus, a:hover {
color: var(--highlightText);
}
header {
border-bottom: 1px solid #ccc;
padding: 1rem;
}
header button {
display: none;
}
main {
display: flex;
overflow: hidden;
margin-left: 300px;
}
nav {
position: sticky;
top: 0;
height: 100vh;
padding: 1rem 2rem 1rem 1rem;
z-index: 5;
background: white;
width: 300px;
float: left;
overflow: auto;
}
nav h3 {
white-space: nowrap;
}
nav ul {
list-style: none;
padding: 0;
}
nav a {
display: inline-block;
color: var(--subtleText);
text-decoration: none;
padding: 0.33rem 0;
}
article {
width: 100%;
overflow: hidden;
padding: 1rem 2rem;
border-left: 1px solid #ccc;
}
code {
width: 100%;
}
pre {
overflow: auto;
}
pre > code {
display: block;
padding: 1em;
background: var(--diagramBackground);
}
h4 {
padding: 2rem;
margin: 4rem -2rem 1rem -2rem;
background: var(--itemHeadingBackground);
font-size: 125%;
}
dfn {
font-style: normal;
cursor: default;
}
.diagram-container {
background: var(--diagramBackground);
margin-bottom: 0.25rem;
padding: 1rem 0;
display: flex;
justify-content: center;
overflow: auto;
}
/* Responsiveness */
@media (max-width: 640px) {
header {
padding: 0.5rem 1rem;
display: flex;
}
code.ebnf pre {
margin: 0;
header h1 {
margin: 0 auto 0 0;
display: flex;
align-items: center;
}
.ebnf-identifier {
color: #990099;
header button {
display: initial;
position: relative;
z-index: 10;
}
.ebnf-terminal {
color: #009900;
header button::after {
content: '☰';
margin-left: auto;
font-size: 1.5rem;
}
.ebnf-non-terminal {
font-weight: normal;
main {
display: block;
position: relative;
margin-left: 0;
}
.ebnf-comment {
font-weight: normal;
font-style: italic;
color: #999;
nav {
height: auto;
display: block;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
position: absolute;
top: 0;
right: 0;
padding-top: 3rem;
background: white;
box-shadow: 0 0 0 1000000rem rgba(0, 0, 0, 0.35);
}
/* EBNF diagram representation styling */
svg.railroad-diagram path {
stroke-width: 3;
stroke: black;
fill: rgba(0,0,0,0);
.menu-open nav {
pointer-events: auto;
opacity: 1;
}
svg.railroad-diagram text {
font: bold 14px monospace;
text-anchor: middle;
nav a {
padding: 0.66rem 0;
}
svg.railroad-diagram text.diagram-text {
font-size: 12px;
article {
margin-left: 0;
border-left: 0;
padding: 1rem;
}
svg.railroad-diagram text.diagram-arrow {
font-size: 16px;
}
svg.railroad-diagram text.label {
text-anchor: start;
}
svg.railroad-diagram text.comment {
font: italic 12px monospace;
}
svg.railroad-diagram g.non-terminal text {
/*font-style: italic;*/
}
svg.railroad-diagram g.special-sequence rect {
fill: #FFDB4D;
}
svg.railroad-diagram g.special-sequence text {
font-style: italic;
}
svg.railroad-diagram rect {
stroke-width: 3;
stroke: black;
}
svg.railroad-diagram g.non-terminal rect {
fill: hsl(120,100%,90%);
}
svg.railroad-diagram g.terminal rect {
fill: hsl(120,100%,90%);
}
svg.railroad-diagram path.diagram-text {
stroke-width: 3;
stroke: black;
fill: white;
cursor: help;
}
svg.railroad-diagram g.diagram-text:hover path.diagram-text {
fill: #eee;
}
}
/* EBNF text representation styling */
code.ebnf {
padding: 1em;
background: rgb(255, 246, 209);
font-weight: bold;
color: #777;
white-space: pre-wrap;
display: inline-block;
width: 100%;
}
.ebnf-identifier {
color: #990099;
}
.ebnf-terminal {
color: #009900;
}
.ebnf-non-terminal {
font-weight: normal;
}
.ebnf-comment {
font-weight: normal;
font-style: italic;
color: #999;
}
/* EBNF diagram representation styling */
svg.railroad-diagram {
width: 100%;
}
svg.railroad-diagram path {
stroke-width: 3;
stroke: black;
fill: rgba(0,0,0,0);
}
svg.railroad-diagram text {
font: bold 14px monospace;
text-anchor: middle;
}
svg.railroad-diagram text.diagram-text {
font-size: 12px;
}
svg.railroad-diagram text.diagram-arrow {
font-size: 16px;
}
svg.railroad-diagram text.label {
text-anchor: start;
}
svg.railroad-diagram text.comment {
font: italic 12px monospace;
}
svg.railroad-diagram g.non-terminal text {
/*font-style: italic;*/
}
svg.railroad-diagram g.special-sequence rect {
fill: #FFDB4D;
}
svg.railroad-diagram g.special-sequence text {
font-style: italic;
}
svg.railroad-diagram rect {
stroke-width: 3;
stroke: black;
}
svg.railroad-diagram g.non-terminal rect {
fill: hsl(120,100%,90%);
}
svg.railroad-diagram g.terminal rect {
fill: hsl(120,100%,90%);
}
svg.railroad-diagram path.diagram-text {
stroke-width: 3;
stroke: black;
fill: white;
cursor: help;
}
svg.railroad-diagram g.diagram-text:hover path.diagram-text {
fill: #eee;
}
`;

@@ -193,3 +365,3 @@

${diagram} </div>
<code class="ebnf"><pre>${ebnf}</pre></code>${(referencedBy.length > 0
<code class="ebnf">${ebnf}</code>${(referencedBy.length > 0
? "\n " + referencesTemplate(identifier, referencedBy)

@@ -196,0 +368,0 @@ : "") +

@@ -92,5 +92,40 @@ const {

const createDefinitionMetadata = (structuralToc, level = 0) => {
const metadata = {};
structuralToc.forEach(item => {
const data = metadata[item.name] || { counted: 0 };
if (level === 0) {
data["root"] = true;
}
if (item.recursive) {
data["recursive"] = true;
}
data["counted"]++;
metadata[item.name] = data;
if (item.children) {
const childData = createDefinitionMetadata(item.children, level + 1);
Object.entries(childData).forEach(([name, cData]) => {
const data = metadata[name] || { counted: 0 };
metadata[name] = {
...data,
...cData,
counted: cData.counted + data.counted
};
});
}
});
const values = Object.values(metadata);
const total = values.reduce((acc, item) => acc + item.counted, 0);
const average = total / values.length;
Object.entries(metadata).forEach(([varName, value]) => {
metadata[varName].common = value.counted > average;
});
return metadata;
};
module.exports = {
createAlphabeticalToc,
createDefinitionMetadata,
createStructuralToc
};
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