From 1c569bf92542e397aa33c5869574fbafe5eccc2f Mon Sep 17 00:00:00 2001 From: Kushal Kumar <59891164+K-Kumar-01@users.noreply.github.com> Date: Tue, 3 Aug 2021 15:36:36 +0530 Subject: [PATCH] feat(markdown-docx): add codeblock transformer - #397 (#430) Signed-off-by: k-kumar-01 --- .../markdown-docx/src/ToCiceroMarkVisitor.js | 82 +++++++++++++++++-- .../markdown-docx/src/ToOOXMLVisitor/index.js | 18 +++- .../markdown-docx/src/ToOOXMLVisitor/rules.js | 20 +++++ packages/markdown-docx/src/constants.js | 1 + .../test/data/ciceroMark/codeblock.json | 1 + 5 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 packages/markdown-docx/test/data/ciceroMark/codeblock.json diff --git a/packages/markdown-docx/src/ToCiceroMarkVisitor.js b/packages/markdown-docx/src/ToCiceroMarkVisitor.js index a179a3d4..99437c53 100644 --- a/packages/markdown-docx/src/ToCiceroMarkVisitor.js +++ b/packages/markdown-docx/src/ToCiceroMarkVisitor.js @@ -112,6 +112,50 @@ class ToCiceroMarkVisitor { return isBorderPresent; } + /** + * Checks if the node is a codeblock or not + * + * @param {Array} paragraphProperties paragraph styling properties + * @returns {boolean} true if the node is of type codeblock or else, false + */ + checkCodeBlockProperties(paragraphProperties) { + let isDesiredTopBorderPresent = false; + let isDesiredBottomBorderPresent = false; + let isDesiredLeftBorderPresent = false; + let isDesiredRightBorderPresent = false; + let isDesiredShadePresent = false; + + for (const property of paragraphProperties) { + if (property.name === 'w:pBdr') { + // do something + for (const borderProperty of property.elements) { + if (borderProperty.attributes['w:color'] === 'CCCCCC') { + if (borderProperty.name === 'w:top') { + isDesiredTopBorderPresent = true; + } else if (borderProperty.name === 'w:bottom') { + isDesiredBottomBorderPresent = true; + } else if (borderProperty.name === 'w:left') { + isDesiredLeftBorderPresent = true; + } else if (borderProperty.name === 'w:right') { + isDesiredRightBorderPresent = true; + } + } + } + } else if (property.name === 'w:shd') { + if (property.attributes['w:fill'] === 'F8F8F8') { + isDesiredShadePresent = true; + } + } + } + return ( + isDesiredTopBorderPresent && + isDesiredBottomBorderPresent && + isDesiredLeftBorderPresent && + isDesiredRightBorderPresent && + isDesiredShadePresent + ); + } + /** * Constructs a ciceroMark Node for inline element from the information. * @@ -213,10 +257,13 @@ class ToCiceroMarkVisitor { /** * Traverses for properties and value. * - * @param {Array} node Node to be traversed - * @param {object} nodeInformation Information for the current node + * @param {Array} node Node to be traversed + * @param {object} nodeInformation Information for the current node + * @param {Boolean} calledByCodeBlock Is function called by codeblock checker + * @returns {string} Value in tags */ - fetchFormattingProperties(node, nodeInformation) { + fetchFormattingProperties(node, nodeInformation, calledByCodeBlock = false) { + let ooxmlTagTextValue = ''; for (const runTimeNodes of node.elements) { if (runTimeNodes.name === 'w:rPr') { let colorCodePresent = false; @@ -245,13 +292,21 @@ class ToCiceroMarkVisitor { nodeInformation.nodeType = TRANSFORMED_NODES.code; } } else if (runTimeNodes.name === 'w:t') { - nodeInformation.value = runTimeNodes.elements ? runTimeNodes.elements[0].text : ' '; - this.JSONXML = [...this.JSONXML, nodeInformation]; + if (calledByCodeBlock) { + ooxmlTagTextValue += runTimeNodes.elements ? runTimeNodes.elements[0].text : ''; + } else { + ooxmlTagTextValue = runTimeNodes.elements ? runTimeNodes.elements[0].text : ' '; + nodeInformation.value = ooxmlTagTextValue; + this.JSONXML = [...this.JSONXML, nodeInformation]; + } + } else if (runTimeNodes.name === 'w:br') { + ooxmlTagTextValue += '\n'; } else if (runTimeNodes.name === 'w:sym') { nodeInformation.nodeType = TRANSFORMED_NODES.softbreak; this.JSONXML = [...this.JSONXML, nodeInformation]; } } + return ooxmlTagTextValue; } /** @@ -273,6 +328,23 @@ class ToCiceroMarkVisitor { const isThematicBreak = this.checkThematicBreakProperties(subNode.elements[0].elements); + const isCodeBlock = this.checkCodeBlockProperties(subNode.elements[0].elements); + + if (isCodeBlock) { + let text = ''; + for (const codeBlockSubNode of subNode.elements) { + if (codeBlockSubNode.name === 'w:r') { + text = this.fetchFormattingProperties(codeBlockSubNode, undefined, true); + } + } + const codeBlockNode = { + $class: TRANSFORMED_NODES.codeBlock, + text, + }; + this.nodes = [...this.nodes, codeBlockNode]; + continue; + } + if (isThematicBreak) { const thematicBreakNode = { $class: TRANSFORMED_NODES.thematicBreak, diff --git a/packages/markdown-docx/src/ToOOXMLVisitor/index.js b/packages/markdown-docx/src/ToOOXMLVisitor/index.js index 8b52a4a6..1f4d80d7 100644 --- a/packages/markdown-docx/src/ToOOXMLVisitor/index.js +++ b/packages/markdown-docx/src/ToOOXMLVisitor/index.js @@ -26,6 +26,8 @@ const { STRONG_RULE, CODE_PROPERTIES_RULE, THEMATICBREAK_RULE, + CODEBLOCK_PROPERTIES_RULE, + CODEBLOCK_FONTPROPERTIES_RULE, } = require('./rules'); const { wrapAroundDefaultDocxTags } = require('./helpers'); const { TRANSFORMED_NODES } = require('../constants'); @@ -99,6 +101,20 @@ class ToOOXMLVisitor { let tag = TEXT_WRAPPER_RULE(propertyTag, textValueTag); this.tags = [...this.tags, tag]; + } else if (this.getClass(subNode) === TRANSFORMED_NODES.codeBlock) { + let ooxml = CODEBLOCK_PROPERTIES_RULE(); + let textValues = subNode.text.split('\n'); + let textValueTag = ''; + for (let textValueIndex = 0; textValueIndex < textValues.length; textValueIndex++) { + textValueTag += TEXT_RULE(textValues[textValueIndex]); + if (textValueIndex !== textValues.length - 1) { + textValueTag += ''; + } + } + let textPropertyTag = TEXT_STYLES_RULE(CODEBLOCK_FONTPROPERTIES_RULE()); + ooxml += TEXT_WRAPPER_RULE(textPropertyTag, textValueTag); + + this.globalOOXML += PARAGRAPH_RULE(ooxml); } else if (this.getClass(subNode) === TRANSFORMED_NODES.variable) { const tag = subNode.name; const type = subNode.elementType; @@ -122,7 +138,7 @@ class ToOOXMLVisitor { this.tags = [...this.tags, VARIABLE_RULE(title, tag, value, type)]; } else if (this.getClass(subNode) === TRANSFORMED_NODES.softbreak) { this.tags = [...this.tags, SOFTBREAK_RULE()]; - } else if(this.getClass(subNode) === TRANSFORMED_NODES.thematicBreak){ + } else if (this.getClass(subNode) === TRANSFORMED_NODES.thematicBreak) { this.globalOOXML += THEMATICBREAK_RULE(); } else { if (subNode.nodes) { diff --git a/packages/markdown-docx/src/ToOOXMLVisitor/rules.js b/packages/markdown-docx/src/ToOOXMLVisitor/rules.js index 919e18c3..4f4ccd10 100644 --- a/packages/markdown-docx/src/ToOOXMLVisitor/rules.js +++ b/packages/markdown-docx/src/ToOOXMLVisitor/rules.js @@ -169,6 +169,24 @@ const CODE_PROPERTIES_RULE = () => { `; }; +const CODEBLOCK_FONTPROPERTIES_RULE = () => { + return ''; +}; + +const CODEBLOCK_PROPERTIES_RULE = () => { + return ` + + + + + + + + + + `; +}; + const LINEBREAK_RULE = () => { return ''; }; @@ -197,5 +215,7 @@ module.exports = { SOFTBREAK_RULE, STRONG_RULE, CODE_PROPERTIES_RULE, + CODEBLOCK_PROPERTIES_RULE, + CODEBLOCK_FONTPROPERTIES_RULE, THEMATICBREAK_RULE, }; diff --git a/packages/markdown-docx/src/constants.js b/packages/markdown-docx/src/constants.js index 84666929..035bed7e 100644 --- a/packages/markdown-docx/src/constants.js +++ b/packages/markdown-docx/src/constants.js @@ -19,6 +19,7 @@ const { NS_PREFIX_CiceroMarkModel } = require('@accordproject/markdown-cicero'). const TRANSFORMED_NODES = { code: `${NS_PREFIX_CommonMarkModel}Code`, + codeBlock: `${NS_PREFIX_CommonMarkModel}CodeBlock`, computedVariable: `${NS_PREFIX_CiceroMarkModel}ComputedVariable`, document: `${NS_PREFIX_CommonMarkModel}Document`, emphasize: `${NS_PREFIX_CommonMarkModel}Emph`, diff --git a/packages/markdown-docx/test/data/ciceroMark/codeblock.json b/packages/markdown-docx/test/data/ciceroMark/codeblock.json new file mode 100644 index 00000000..39881b2d --- /dev/null +++ b/packages/markdown-docx/test/data/ciceroMark/codeblock.json @@ -0,0 +1 @@ +{"$class":"org.accordproject.commonmark.Document","xmlns":"http://commonmark.org/xml/1.0","nodes":[{"$class":"org.accordproject.commonmark.Paragraph","nodes":[{"$class":"org.accordproject.commonmark.Text","text":"just testing some"}]},{"$class":"org.accordproject.commonmark.CodeBlock","text":"Let us try some sentences to see whether we are able to convert the above\ninto an ooxml document **using some** of the techniques we have already encountered.\nlets hope for the best\n"}]} \ No newline at end of file