From 1288864fb6777292fd5ddd0d3d6e3788e86add59 Mon Sep 17 00:00:00 2001 From: pedroth Date: Tue, 14 Nov 2023 22:56:24 +0000 Subject: [PATCH] fix bug in html parsing add html comments --- dist/node/CodeRender/CodeRender.js | 47 +++++++++++++++++++++++----- dist/node/Lexer.js | 12 ++++++- dist/node/MathRender.js | 49 ++++++++++++++++++++++++----- dist/node/NabladownRender.js | 49 ++++++++++++++++++++++++----- dist/node/Parser.js | 40 +++++++++++++++++++----- dist/node/Render.js | 49 ++++++++++++++++++++++++----- dist/node/index.js | 50 +++++++++++++++++++++++++----- dist/web/CodeRender/CodeRender.js | 47 +++++++++++++++++++++++----- dist/web/Lexer.js | 12 ++++++- dist/web/MathRender.js | 47 +++++++++++++++++++++++----- dist/web/NabladownRender.js | 47 +++++++++++++++++++++++----- dist/web/Parser.js | 40 +++++++++++++++++++----- dist/web/Render.js | 47 +++++++++++++++++++++++----- dist/web/index.js | 48 +++++++++++++++++++++++----- index.js | 9 +++--- src/Lexer.js | 2 ++ src/Parser.js | 50 +++++++++++++++++++++--------- src/Render.js | 11 +++++++ src/Utils.js | 4 +++ src/buildDom.js | 11 ++++--- test/resources/snapshot2.html | 2 +- test/resources/test2.nd | 22 +++++++++---- 22 files changed, 575 insertions(+), 120 deletions(-) diff --git a/dist/node/CodeRender/CodeRender.js b/dist/node/CodeRender/CodeRender.js index c384435..8d6a467 100644 --- a/dist/node/CodeRender/CodeRender.js +++ b/dist/node/CodeRender/CodeRender.js @@ -47335,7 +47335,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -47366,6 +47366,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -47389,6 +47390,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -47397,6 +47400,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -47453,6 +47458,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -47725,6 +47733,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -48296,6 +48306,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -48303,9 +48316,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -48317,15 +48330,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -48353,7 +48378,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -48462,7 +48487,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -62758,6 +62788,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { diff --git a/dist/node/Lexer.js b/dist/node/Lexer.js index 3ca17a5..99864b3 100644 --- a/dist/node/Lexer.js +++ b/dist/node/Lexer.js @@ -122,7 +122,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -153,6 +153,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -176,6 +177,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -184,6 +187,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -240,6 +245,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -512,6 +520,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), diff --git a/dist/node/MathRender.js b/dist/node/MathRender.js index 2cba328..afbf942 100644 --- a/dist/node/MathRender.js +++ b/dist/node/MathRender.js @@ -122,7 +122,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -153,6 +153,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -176,6 +177,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -184,6 +187,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -240,6 +245,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -512,6 +520,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -1083,6 +1093,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -1090,9 +1103,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -1104,15 +1117,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -1140,7 +1165,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -1249,7 +1274,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -15545,6 +15575,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { diff --git a/dist/node/NabladownRender.js b/dist/node/NabladownRender.js index edb86db..5a48bf4 100644 --- a/dist/node/NabladownRender.js +++ b/dist/node/NabladownRender.js @@ -47335,7 +47335,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -47366,6 +47366,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -47389,6 +47390,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -47397,6 +47400,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -47453,6 +47458,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -47725,6 +47733,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -48296,6 +48306,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -48303,9 +48316,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -48317,15 +48330,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -48353,7 +48378,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -48462,7 +48487,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -62758,6 +62788,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { diff --git a/dist/node/Parser.js b/dist/node/Parser.js index cf5dfbc..e4d8c70 100644 --- a/dist/node/Parser.js +++ b/dist/node/Parser.js @@ -122,7 +122,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -153,6 +153,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -176,6 +177,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -184,6 +187,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -240,6 +245,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -512,6 +520,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -1083,6 +1093,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -1090,9 +1103,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -1104,15 +1117,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -1140,7 +1165,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -1249,7 +1274,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -153,6 +153,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -176,6 +177,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -184,6 +187,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -240,6 +245,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -512,6 +520,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -1083,6 +1093,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -1090,9 +1103,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -1104,15 +1117,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -1140,7 +1165,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -1249,7 +1274,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -15545,6 +15575,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { diff --git a/dist/node/index.js b/dist/node/index.js index 8689389..693409e 100644 --- a/dist/node/index.js +++ b/dist/node/index.js @@ -47335,7 +47335,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -47366,6 +47366,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -47389,6 +47390,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -47397,6 +47400,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -47453,6 +47458,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -47725,6 +47733,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -48296,6 +48306,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -48303,9 +48316,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -48317,15 +48330,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -48353,7 +48378,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -48462,7 +48487,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -62758,6 +62788,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { @@ -62966,6 +62999,7 @@ export { evalScriptTag, either, eatSymbolsWhile, + eatSpacesTabsAndNewLines, eatSpaces, eatNSymbol, createDefaultEl, diff --git a/dist/web/CodeRender/CodeRender.js b/dist/web/CodeRender/CodeRender.js index e01ef7b..37b421c 100644 --- a/dist/web/CodeRender/CodeRender.js +++ b/dist/web/CodeRender/CodeRender.js @@ -47335,7 +47335,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -47366,6 +47366,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -47389,6 +47390,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -47397,6 +47400,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -47453,6 +47458,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -47725,6 +47733,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -48296,6 +48306,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -48303,9 +48316,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -48317,15 +48330,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -48353,7 +48378,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -48462,7 +48487,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -62758,6 +62788,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { diff --git a/dist/web/Lexer.js b/dist/web/Lexer.js index 3aafdf0..2619c70 100644 --- a/dist/web/Lexer.js +++ b/dist/web/Lexer.js @@ -122,7 +122,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -153,6 +153,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -176,6 +177,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -184,6 +187,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -240,6 +245,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -512,6 +520,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), diff --git a/dist/web/MathRender.js b/dist/web/MathRender.js index 6db84ae..ec4f33e 100644 --- a/dist/web/MathRender.js +++ b/dist/web/MathRender.js @@ -122,7 +122,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -153,6 +153,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -176,6 +177,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -184,6 +187,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -240,6 +245,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -512,6 +520,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -1083,6 +1093,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -1090,9 +1103,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -1104,15 +1117,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -1140,7 +1165,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -1249,7 +1274,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -15545,6 +15575,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { diff --git a/dist/web/NabladownRender.js b/dist/web/NabladownRender.js index a557854..5a2b2b8 100644 --- a/dist/web/NabladownRender.js +++ b/dist/web/NabladownRender.js @@ -47335,7 +47335,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -47366,6 +47366,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -47389,6 +47390,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -47397,6 +47400,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -47453,6 +47458,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -47725,6 +47733,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -48296,6 +48306,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -48303,9 +48316,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -48317,15 +48330,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -48353,7 +48378,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -48462,7 +48487,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -62758,6 +62788,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { diff --git a/dist/web/Parser.js b/dist/web/Parser.js index 67a4c7f..648d09e 100644 --- a/dist/web/Parser.js +++ b/dist/web/Parser.js @@ -122,7 +122,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -153,6 +153,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -176,6 +177,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -184,6 +187,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -240,6 +245,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -512,6 +520,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -1083,6 +1093,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -1090,9 +1103,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -1104,15 +1117,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -1140,7 +1165,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -1249,7 +1274,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -153,6 +153,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -176,6 +177,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -184,6 +187,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -240,6 +245,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -512,6 +520,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -1083,6 +1093,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -1090,9 +1103,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -1104,15 +1117,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -1140,7 +1165,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -1249,7 +1274,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -15545,6 +15575,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { diff --git a/dist/web/index.js b/dist/web/index.js index f0094e7..8755281 100644 --- a/dist/web/index.js +++ b/dist/web/index.js @@ -47335,7 +47335,7 @@ function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach((child) => { - if (!child.build) + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()); }); @@ -47366,6 +47366,7 @@ function buildDom(nodeType) { domNode.getLazyActions = () => lazyActions; domNode.getType = () => nodeType; domNode.getRef = () => (f) => f(maybe(ref)); + domNode.isEmpty = () => !nodeType; return domNode; } var childrenToString = function({ @@ -47389,6 +47390,8 @@ var childrenToString = function({ }; var startTagToString = function({ nodeType, attrs, isFormatted }) { const result = []; + if (!nodeType) + return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -47397,6 +47400,8 @@ var startTagToString = function({ nodeType, attrs, isFormatted }) { return result; }; var endTagToString = function({ nodeType, isFormatted, n }) { + if (!nodeType) + return ""; const indentation = Array(n).fill(" ").join(""); const result = []; if (isFormatted) @@ -47453,6 +47458,9 @@ function eatNSymbol(n, symbolPredicate) { function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, (s) => s.type === " "); } +function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, (s) => s.type === " " || s.type === "\t" || s.type === "\n"); +} function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { @@ -47725,6 +47733,8 @@ var tokenBuilder = () => { var TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), @@ -48296,6 +48306,9 @@ var parseHtml = function(stream2) { }, () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream2); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream2); + return pair({ type: TYPES.html, CommentTag }, nextStream); }); }; var parseStartTag = function(stream2) { @@ -48303,9 +48316,9 @@ var parseStartTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === ">") { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -48317,15 +48330,27 @@ var parseEmptyTag = function(stream2) { if (token.type === "<") { const nextStream1 = eatSpaces(stream2.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1); - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (nextStream5.head().type === "/>") { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } } throw new Error(`Error occurred while parsing EmptyTag,` + stream2.toString()); }; +var parseCommentTag = function(stream2) { + return success(stream2).filter((nextStream) => { + return nextStream.head().type === "")(nextStream.tail()); + if (AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream2.toString()}`); + }); +}; function parseAlphaNumName(tokenStream) { const strBuffer = []; let s = tokenStream; @@ -48353,7 +48378,7 @@ var parseCharAlphaNumName = function(charStream) { var parseAttrs = function(stream2) { return or(() => { const { left: Attr, right: nextStream } = parseAttr(stream2); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -48462,7 +48487,7 @@ var parseInnerHtmlTypes = function(stream2) { }); }; var parseEndTag = function(stream2) { - const filteredStream = eatSymbolsWhile(stream2, (token2) => token2.type === " " || token2.type === "\t" || token2.type === "\n"); + const filteredStream = eatSpacesTabsAndNewLines(stream2); const token = filteredStream.head(); if (token.type === " !!h.EmptyTag, value: (h) => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: (h) => !!h.CommentTag, + value: (h) => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -62758,6 +62788,9 @@ class Render { attributes.forEach(({ attributeName, attributeValue }) => container.attr(attributeName, attributeValue)); return container; } + renderCommentTag(commentTag) { + return buildDom(); + } renderNablaText(text2) { const { left: Expression } = parseExpression(tokenizer(stream(text2))); if (Expression.expressions.length > 0) { @@ -62966,6 +62999,7 @@ export { evalScriptTag, either, eatSymbolsWhile, + eatSpacesTabsAndNewLines, eatSpaces, eatNSymbol, createDefaultEl, diff --git a/index.js b/index.js index 77acb8c..ab9de70 100644 --- a/index.js +++ b/index.js @@ -156,12 +156,13 @@ function renderEditor(anchor) { // eslint-disable-next-line no-undef const editor = monaco.editor.create(anchor, { value: "", - language: "markdown", + fontSize: "16", + theme: "vs-dark", lineNumbers: "on", + insertSpaces: false, + language: "markdown", + automaticLayout: true, wordWrap: "wordWrapColumn", - theme: "vs-dark", - fontSize: "16", - automaticLayout: true }); return editor; } diff --git a/src/Lexer.js b/src/Lexer.js index 0defa15..aaf3105 100644 --- a/src/Lexer.js +++ b/src/Lexer.js @@ -179,6 +179,8 @@ function orToken(...tokenParsers) { const TOKENS_PARSERS = [ tokenRepeat("#", 6), tokenRepeat("$", 2), + tokenSymbol(""), tokenSymbol("*"), tokenSymbol("_"), tokenSymbol(CUSTOM_SYMBOL), diff --git a/src/Parser.js b/src/Parser.js index ab061fd..8a521fe 100644 --- a/src/Parser.js +++ b/src/Parser.js @@ -22,7 +22,8 @@ import { eatSpaces, isNumeric, eatSymbolsWhile, - returnOne + returnOne, + eatSpacesTabsAndNewLines } from "./Utils.js"; /** @@ -124,21 +125,21 @@ import { * * SingleBut(s) -> ¬s * - * Html -> StartTag InnerHtml EndTag / EmptyTag + * Html -> StartTag InnerHtml EndTag / EmptyTag / CommentTag * * InnerHtml -> InnerHtmlTypes InnerHtml / ε * * InnerHtmlTypes -> Html / Paragraph / Expression* * - * StartTag -> (" " || "\n")* < (" ")* AlphaNumName (" ")* Attrs (" ")*> + * StartTag -> < (" ")* AlphaNumName (" " || "\n")* Attrs (" " || "\n")*> * - * EmptyTag -> <(" ")* AlphaNumName (" ")* /> + * EmptyTag -> <(" ")* AlphaNumName (" " || "\n")* Attrs (" " || "\n")* /> * - * Attrs -> Attr Attrs / ε + * Attrs -> Attr (" " || "\n")* Attrs / ε * * Attr -> AlphaNumName="AnyBut(")" / AlphaNumName='AnyBut(')' * - * EndTag -> (" " || "\n")* + * EndTag -> * * AlphaNumName -> [a-zA-z][a-zA-Z0-9]* * @@ -185,6 +186,7 @@ export const TYPES = { html: "html", startTag: "startTag", emptyTag: "emptyTag", + commentTag: "commentTag", innerHtml: "innerHtml", innerHtmlTypes: "innerHtmlTypes", endTag: "endTag", @@ -1078,6 +1080,10 @@ function parseHtml(stream) { () => { const { left: EmptyTag, right: nextStream } = parseEmptyTag(stream); return pair({ type: TYPES.html, EmptyTag }, nextStream); + }, + () => { + const { left: CommentTag, right: nextStream } = parseCommentTag(stream); + return pair({ type: TYPES.html, CommentTag }, nextStream); } ); } @@ -1090,9 +1096,9 @@ function parseStartTag(stream) { if ("<" === token.type) { const nextStream1 = eatSpaces(stream.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1) - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if (">" === nextStream5.head().type) { return pair({ type: TYPES.startTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -1108,9 +1114,9 @@ function parseEmptyTag(stream) { if ("<" === token.type) { const nextStream1 = eatSpaces(stream.tail()); const { left: tagName, right: nextStream2 } = parseAlphaNumName(nextStream1) - const nextStream3 = eatSpaces(nextStream2); + const nextStream3 = eatSpacesTabsAndNewLines(nextStream2); const { left: Attrs, right: nextStream4 } = parseAttrs(nextStream3); - const nextStream5 = eatSpaces(nextStream4); + const nextStream5 = eatSpacesTabsAndNewLines(nextStream4); if ("/>" === nextStream5.head().type) { return pair({ type: TYPES.emptyTag, tag: tagName.text, Attrs }, nextStream5.tail()); } @@ -1118,6 +1124,23 @@ function parseEmptyTag(stream) { throw new Error(`Error occurred while parsing EmptyTag,` + stream.toString()); } +function parseCommentTag(stream) { + return success(stream) + .filter((nextStream) => { + return "' === token.type + )(nextStream.tail()); + if(AnyBut.textArray.length > 0) + return pair({ type: TYPES.commentTag }, nextStream1.tail()); + throw new Error(`Dummy error. Real error to be thrown in _orCatch_ function`); + }).orCatch(() => { + throw new Error(`Error occurred while parsing Attr, ${stream.toString()}`); + }) +} + /** * stream => pair(AlphaNumName, stream) */ @@ -1151,7 +1174,7 @@ function parseAttrs(stream) { return or( () => { const { left: Attr, right: nextStream } = parseAttr(stream); - const nextStreamNoSpaces = eatSpaces(nextStream); + const nextStreamNoSpaces = eatSpacesTabsAndNewLines(nextStream); const { left: Attrs, right: nextStream1 } = parseAttrs(nextStreamNoSpaces); return pair({ type: TYPES.attrs, @@ -1325,10 +1348,7 @@ function parseInnerHtmlTypes(stream) { * stream => pair(EndTag, stream) */ function parseEndTag(stream) { - const filteredStream = eatSymbolsWhile( - stream, - token => token.type === " " || token.type === "\t" || token.type === "\n" - ); + const filteredStream = eatSpacesTabsAndNewLines(stream); const token = filteredStream.head(); if (" !!h.EmptyTag, value: h => this.renderEmptyTag(h.EmptyTag) + }, + { + predicate: h => !!h.CommentTag, + value: h => this.renderCommentTag(h.CommentTag) } ])(html); } @@ -747,6 +751,13 @@ export class Render { return container; } + /** + * commentTag => DomBuilder + */ + renderCommentTag(commentTag) { + return buildDom(); + } + renderNablaText(text) { const { left: Expression } = parseExpression(tokenizer(stream(text))); if (Expression.expressions.length > 0) { diff --git a/src/Utils.js b/src/Utils.js index 47c025d..80c7d88 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -57,6 +57,10 @@ export function eatSpaces(tokenStream) { return eatSymbolsWhile(tokenStream, s => s.type === " "); } +export function eatSpacesTabsAndNewLines(tokenStream) { + return eatSymbolsWhile(tokenStream, s => s.type === " " || s.type === "\t" || s.type === "\n"); +} + export function eatSymbolsWhile(tokenStream, predicate) { let s = tokenStream; while (!tokenStream.isEmpty()) { diff --git a/src/buildDom.js b/src/buildDom.js index 7d448b3..ef2390d 100644 --- a/src/buildDom.js +++ b/src/buildDom.js @@ -71,7 +71,7 @@ export function buildDom(nodeType) { dom.innerHTML = innerHtml; if (children.length > 0) { children.forEach(child => { - if (!child.build) return; + if (!child.build || child.isEmpty()) return; dom.appendChild(child.build()) }); } @@ -106,6 +106,7 @@ export function buildDom(nodeType) { domNode.getRef = () => f => f( maybe(ref) ); + domNode.isEmpty = () => !nodeType; return domNode; } @@ -127,9 +128,9 @@ function childrenToString({ const result = []; const indentation = Array(n + 1).fill(" ").join("") if (children.length > 0) { - result.push(...children.map(child => - `${isFormatted ? indentation : ""}${child.toString({ isFormatted, n: n + 1 })}${isFormatted ? "\n" : ""}`) - ); + result.push(...children.map(child => + `${isFormatted ? indentation : ""}${child.toString({ isFormatted, n: n + 1 })}${isFormatted ? "\n" : ""}` + )); } else { if (isFormatted) result.push(indentation); result.push(innerHtml); @@ -140,6 +141,7 @@ function childrenToString({ function startTagToString({ nodeType, attrs, isFormatted }) { const result = []; + if(!nodeType) return ""; result.push(`<${nodeType}`); result.push(...Object.entries(attrs).map(([attr, value]) => ` ${attr}="${value}" `)); result.push(`>`); @@ -148,6 +150,7 @@ function startTagToString({ nodeType, attrs, isFormatted }) { } function endTagToString({ nodeType, isFormatted, n }) { + if(!nodeType) return ""; const indentation = Array(n).fill(" ").join("") const result = []; if (isFormatted) result.push(indentation); diff --git a/test/resources/snapshot2.html b/test/resources/snapshot2.html index a3f446a..5e01c6a 100644 --- a/test/resources/snapshot2.html +++ b/test/resources/snapshot2.html @@ -68,7 +68,7 @@ System.out.println("Hello") } } -

Syntax here.

Name of the available languages according to highlight.js

HTML

Normal markdown with red text inline

A paragraph with html and nabladown inside:

Custom