From c6591521aa8184f588aaa595ed9d2b5e38ed1b12 Mon Sep 17 00:00:00 2001 From: Kushal Kumar <59891164+K-Kumar-01@users.noreply.github.com> Date: Mon, 23 Aug 2021 14:42:41 +0530 Subject: [PATCH] feat(markdown-docx): add formula transformer - #397 (#454) Signed-off-by: k-kumar-01 --- .../omitted-acceptance-of-delivery.xml | 30 ++++++++-------- .../markdown-docx/src/ToCiceroMarkVisitor.js | 27 +++++++++++++++ .../src/ToOOXMLVisitor/helpers.js | 11 ++++-- .../markdown-docx/src/ToOOXMLVisitor/index.js | 33 +++++++++++++++++- .../markdown-docx/src/ToOOXMLVisitor/rules.js | 34 +++++++++++++++++++ packages/markdown-docx/src/constants.js | 1 + .../test/data/ciceroMark/formula.json | 1 + .../data/ooxml/acceptance-of-delivery.xml | 30 ++++++++-------- .../omitted-acceptance-of-delivery.xml | 30 ++++++++-------- 9 files changed, 148 insertions(+), 49 deletions(-) create mode 100644 packages/markdown-docx/test/data/ciceroMark/formula.json diff --git a/packages/markdown-cli/test/data/acceptance/omitted-acceptance-of-delivery.xml b/packages/markdown-cli/test/data/acceptance/omitted-acceptance-of-delivery.xml index 8bdf2222..f5b2dfc8 100644 --- a/packages/markdown-cli/test/data/acceptance/omitted-acceptance-of-delivery.xml +++ b/packages/markdown-cli/test/data/acceptance/omitted-acceptance-of-delivery.xml @@ -79,7 +79,7 @@ - "Party A" + "Party A" @@ -114,7 +114,7 @@ - "Party B" + "Party B" @@ -122,7 +122,7 @@ - 's opinion, the + 's opinion, the @@ -139,7 +139,7 @@ - "Widgets" + "Widgets" @@ -174,7 +174,7 @@ - "Party B" + "Party B" @@ -199,7 +199,7 @@ - "Party A" + "Party A" @@ -234,7 +234,7 @@ - "Widgets" + "Widgets" @@ -277,7 +277,7 @@ - "Party B" + "Party B" @@ -337,7 +337,7 @@ - "Widgets" + "Widgets" @@ -366,7 +366,7 @@ - "Party A" + "Party A" @@ -395,7 +395,7 @@ - "Widgets" + "Widgets" @@ -427,7 +427,7 @@ - The "Acceptance Criteria" are the specifications the + The "Acceptance Criteria" are the specifications the @@ -444,7 +444,7 @@ - "Widgets" + "Widgets" @@ -473,7 +473,7 @@ - "Party A" + "Party A" @@ -508,7 +508,7 @@ - "Attachment X" + "Attachment X" diff --git a/packages/markdown-docx/src/ToCiceroMarkVisitor.js b/packages/markdown-docx/src/ToCiceroMarkVisitor.js index 19fd9309..591b4476 100644 --- a/packages/markdown-docx/src/ToCiceroMarkVisitor.js +++ b/packages/markdown-docx/src/ToCiceroMarkVisitor.js @@ -69,6 +69,20 @@ class ToCiceroMarkVisitor { } } + /** + * Gets the dependencies of a formula node + * + * @param {Array} variableProperties the variable elements + * @returns {string} the name of the variable + */ + getDependencies(variableProperties) { + for (const property of variableProperties) { + if (property.name === 'w:tag') { + return property.attributes['w:val'].split(SEPARATOR)[2]; + } + } + } + /** * Get the type of the element. * @@ -194,6 +208,14 @@ class ToCiceroMarkVisitor { elementType: nodeInformation.elementType, name: nodeInformation.name, }; + } else if (nodeInformation.nodeType === TRANSFORMED_NODES.formula) { + ciceroMarkNode = { + $class: TRANSFORMED_NODES.formula, + value: nodeInformation.value, + name: nodeInformation.name, + code: nodeInformation.code, + dependencies: nodeInformation.dependencies.split(','), + }; } else if (nodeInformation.nodeType === TRANSFORMED_NODES.code) { ciceroMarkNode = { $class: TRANSFORMED_NODES.code, @@ -563,6 +585,11 @@ class ToCiceroMarkVisitor { nodeInformation.name = this.getName(variableSubNodes.elements); nodeInformation.elementType = this.getElementType(variableSubNodes.elements); nodeInformation.nodeType = this.getNodeType(variableSubNodes.elements); + if (nodeInformation.nodeType === TRANSFORMED_NODES.formula) { + nodeInformation.code = nodeInformation.elementType; + nodeInformation.dependencies = this.getDependencies(variableSubNodes.elements); + delete nodeInformation.elementType; + } } if (variableSubNodes.name === 'w:sdtContent') { if (nodeInformation.nodeType === TRANSFORMED_NODES.clause) { diff --git a/packages/markdown-docx/src/ToOOXMLVisitor/helpers.js b/packages/markdown-docx/src/ToOOXMLVisitor/helpers.js index 2462ec64..11ea07db 100644 --- a/packages/markdown-docx/src/ToOOXMLVisitor/helpers.js +++ b/packages/markdown-docx/src/ToOOXMLVisitor/helpers.js @@ -15,13 +15,19 @@ 'use strict'; /** - * Replaces the angular brackets with the respective codes. + * Escapes certain characters in OOXML with respective character encodings. + * (https://stackoverflow.com/questions/1091945/what-characters-do-i-need-to-escape-in-xml-documents) * * @param {string} node String to be replaced * @returns {string} String with replaced angular brackets */ function sanitizeHtmlChars(node) { - return node.replace(/>/g, '>').replace(//g, '>') + .replace(/ diff --git a/packages/markdown-docx/src/ToOOXMLVisitor/index.js b/packages/markdown-docx/src/ToOOXMLVisitor/index.js index 05007c94..02cc7a20 100644 --- a/packages/markdown-docx/src/ToOOXMLVisitor/index.js +++ b/packages/markdown-docx/src/ToOOXMLVisitor/index.js @@ -35,8 +35,9 @@ const { VANISH_PROPERTY_RULE, CONDITIONAL_OR_OPTIONAL_FONT_FAMILY_RULE, CONDITIONAL_RULE, + FORMULA_RULE, } = require('./rules'); -const { wrapAroundDefaultDocxTags, wrapAroundLockedContentControls } = require('./helpers'); +const { wrapAroundDefaultDocxTags, wrapAroundLockedContentControls, sanitizeHtmlChars } = require('./helpers'); const { TRANSFORMED_NODES, RELATIONSHIP_OFFSET } = require('../constants'); /** @@ -194,6 +195,36 @@ class ToOOXMLVisitor { if (!(parent === TRANSFORMED_NODES.optional || parent === TRANSFORMED_NODES.conditional)) { this.tags = [...this.tags, VARIABLE_RULE(title, tag, value, type)]; } + } else if (this.getClass(subNode) === TRANSFORMED_NODES.formula) { + // Dependencies are added for the reason to extract them + // when converting from ooxml -> ciceromark + const tag = subNode.name; + const type = sanitizeHtmlChars(subNode.code); + this.createOrUpdateCounter(tag, type); + const value = subNode.value; + const dependencies = subNode.dependencies.join(','); + const title = `${tag.toUpperCase()[0]}${tag.substring(1)}${this.counter[tag].count}`; + inlineOOXML += FORMULA_RULE( + title, + tag, + value, + type, + dependencies, + parentProperties.traversingNodeHiddenInConditional + ); + if (!(parent === TRANSFORMED_NODES.optional || parent === TRANSFORMED_NODES.conditional)) { + this.tags = [ + ...this.tags, + FORMULA_RULE( + title, + tag, + value, + type, + dependencies, + parentProperties.traversingNodeHiddenInConditional + ), + ]; + } } else if (this.getClass(subNode) === TRANSFORMED_NODES.softbreak) { inlineOOXML += SOFTBREAK_RULE(); if (!(parent === TRANSFORMED_NODES.optional || parent === TRANSFORMED_NODES.conditional)) { diff --git a/packages/markdown-docx/src/ToOOXMLVisitor/rules.js b/packages/markdown-docx/src/ToOOXMLVisitor/rules.js index 915e78a1..50f2c8d1 100644 --- a/packages/markdown-docx/src/ToOOXMLVisitor/rules.js +++ b/packages/markdown-docx/src/ToOOXMLVisitor/rules.js @@ -314,6 +314,39 @@ const CONDITIONAL_RULE = (title, tag, value) => { `; }; +/** + * Inserts a formula. + * + * @param {string} title Title of the formula. Eg. receiver-1, shipper-1 + * @param {string} tag Name of the formula. Eg. receiver, shipper + * @param {string} value Value of the formula + * @param {string} type Type of the formula - Long, Double, etc. + * @param {string} dependencies Dependencies of the formula + * @param {boolean} vanish Should vanish property be present + * @returns {string} OOXML string for the formula + */ +const FORMULA_RULE = (title, tag, value, type, dependencies, vanish = false) => { + return ` + + + + + + + + + + + + + ${vanish ? VANISH_PROPERTY_RULE() : ''} + + ${sanitizeHtmlChars(value)} + + + +`; +}; module.exports = { TEXT_RULE, @@ -336,4 +369,5 @@ module.exports = { VANISH_PROPERTY_RULE, CONDITIONAL_OR_OPTIONAL_FONT_FAMILY_RULE, CONDITIONAL_RULE, + FORMULA_RULE, }; diff --git a/packages/markdown-docx/src/constants.js b/packages/markdown-docx/src/constants.js index 8b86a2b1..06d563d6 100644 --- a/packages/markdown-docx/src/constants.js +++ b/packages/markdown-docx/src/constants.js @@ -25,6 +25,7 @@ const TRANSFORMED_NODES = { optional: `${NS_PREFIX_CiceroMarkModel}Optional`, document: `${NS_PREFIX_CommonMarkModel}Document`, emphasize: `${NS_PREFIX_CommonMarkModel}Emph`, + formula: `${NS_PREFIX_CiceroMarkModel}Formula`, heading: `${NS_PREFIX_CommonMarkModel}Heading`, item: `${NS_PREFIX_CommonMarkModel}Item`, link: `${NS_PREFIX_CommonMarkModel}Link`, diff --git a/packages/markdown-docx/test/data/ciceroMark/formula.json b/packages/markdown-docx/test/data/ciceroMark/formula.json new file mode 100644 index 00000000..bfbc0042 --- /dev/null +++ b/packages/markdown-docx/test/data/ciceroMark/formula.json @@ -0,0 +1 @@ +{"$class":"org.accordproject.commonmark.Document","xmlns":"http://commonmark.org/xml/1.0","nodes":[{"$class":"org.accordproject.commonmark.Heading","level":"2","nodes":[{"$class":"org.accordproject.commonmark.Text","text":"Fixed rate loan"}]},{"$class":"org.accordproject.commonmark.Paragraph","nodes":[{"$class":"org.accordproject.commonmark.Text","text":"This is a "},{"$class":"org.accordproject.commonmark.Emph","nodes":[{"$class":"org.accordproject.commonmark.Text","text":"fixed interest"}]},{"$class":"org.accordproject.commonmark.Text","text":" loan to the amount of "},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"at the yearly interest rate of "},{"$class":"org.accordproject.ciceromark.Variable","value":"2.5","name":"rate","elementType":"Double"},{"$class":"org.accordproject.commonmark.Text","text":"%"},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"with a loan term of "},{"$class":"org.accordproject.ciceromark.Variable","value":"15","name":"loanDuration","elementType":"Integer"},{"$class":"org.accordproject.commonmark.Text","text":","},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"and monthly payments of "},{"$class":"org.accordproject.ciceromark.Formula","value":"\"£667.00\"","dependencies":["loanAmount","rate","loanDuration"],"code":" monthlyPaymentFormula(loanAmount,rate,loanDuration) as \"K0,0.00\" ","name":"formula_d02c8642fa12d6ed08dea71f0af7a77b0c7893804d0b43b537eb18ea6f666463"}]}]} \ No newline at end of file diff --git a/packages/markdown-docx/test/data/ooxml/acceptance-of-delivery.xml b/packages/markdown-docx/test/data/ooxml/acceptance-of-delivery.xml index 8bdf2222..f5b2dfc8 100644 --- a/packages/markdown-docx/test/data/ooxml/acceptance-of-delivery.xml +++ b/packages/markdown-docx/test/data/ooxml/acceptance-of-delivery.xml @@ -79,7 +79,7 @@ - "Party A" + "Party A" @@ -114,7 +114,7 @@ - "Party B" + "Party B" @@ -122,7 +122,7 @@ - 's opinion, the + 's opinion, the @@ -139,7 +139,7 @@ - "Widgets" + "Widgets" @@ -174,7 +174,7 @@ - "Party B" + "Party B" @@ -199,7 +199,7 @@ - "Party A" + "Party A" @@ -234,7 +234,7 @@ - "Widgets" + "Widgets" @@ -277,7 +277,7 @@ - "Party B" + "Party B" @@ -337,7 +337,7 @@ - "Widgets" + "Widgets" @@ -366,7 +366,7 @@ - "Party A" + "Party A" @@ -395,7 +395,7 @@ - "Widgets" + "Widgets" @@ -427,7 +427,7 @@ - The "Acceptance Criteria" are the specifications the + The "Acceptance Criteria" are the specifications the @@ -444,7 +444,7 @@ - "Widgets" + "Widgets" @@ -473,7 +473,7 @@ - "Party A" + "Party A" @@ -508,7 +508,7 @@ - "Attachment X" + "Attachment X" diff --git a/packages/markdown-transform/test/data/acceptance/omitted-acceptance-of-delivery.xml b/packages/markdown-transform/test/data/acceptance/omitted-acceptance-of-delivery.xml index 8bdf2222..f5b2dfc8 100644 --- a/packages/markdown-transform/test/data/acceptance/omitted-acceptance-of-delivery.xml +++ b/packages/markdown-transform/test/data/acceptance/omitted-acceptance-of-delivery.xml @@ -79,7 +79,7 @@ - "Party A" + "Party A" @@ -114,7 +114,7 @@ - "Party B" + "Party B" @@ -122,7 +122,7 @@ - 's opinion, the + 's opinion, the @@ -139,7 +139,7 @@ - "Widgets" + "Widgets" @@ -174,7 +174,7 @@ - "Party B" + "Party B" @@ -199,7 +199,7 @@ - "Party A" + "Party A" @@ -234,7 +234,7 @@ - "Widgets" + "Widgets" @@ -277,7 +277,7 @@ - "Party B" + "Party B" @@ -337,7 +337,7 @@ - "Widgets" + "Widgets" @@ -366,7 +366,7 @@ - "Party A" + "Party A" @@ -395,7 +395,7 @@ - "Widgets" + "Widgets" @@ -427,7 +427,7 @@ - The "Acceptance Criteria" are the specifications the + The "Acceptance Criteria" are the specifications the @@ -444,7 +444,7 @@ - "Widgets" + "Widgets" @@ -473,7 +473,7 @@ - "Party A" + "Party A" @@ -508,7 +508,7 @@ - "Attachment X" + "Attachment X"