diff --git a/packages/markdown-docx/src/ToCiceroMarkVisitor.js b/packages/markdown-docx/src/ToCiceroMarkVisitor.js index 58a0b868..19fd9309 100644 --- a/packages/markdown-docx/src/ToCiceroMarkVisitor.js +++ b/packages/markdown-docx/src/ToCiceroMarkVisitor.js @@ -230,6 +230,22 @@ class ToCiceroMarkVisitor { ciceroMarkNode.whenSome = []; } } + if (nodeInformation.properties[nodePropertyIndex] === TRANSFORMED_NODES.conditional) { + let currentNodes = [...ciceroMarkNode.nodes]; + ciceroMarkNode = { + $class: TRANSFORMED_NODES.conditional, + ...nodeInformation.optionalProperties, + isTrue: nodeInformation.hasSome, + nodes: currentNodes, + }; + if (nodeInformation.whenSomeType) { + ciceroMarkNode.whenTrue = currentNodes; + ciceroMarkNode.whenFalse = []; + } else { + ciceroMarkNode.whenFalse = currentNodes; + ciceroMarkNode.whenTrue = []; + } + } if (nodeInformation.properties[nodePropertyIndex] === TRANSFORMED_NODES.link) { ciceroMarkNode.title = ''; for (const relationshipElement of this.relationshipXML) { @@ -312,6 +328,18 @@ class ToCiceroMarkVisitor { } else { eval(`${nestedExpression}nodes=${nestedExpression}whenNone`); } + } else if (propertiesCurrent[commonPropertiesLength - 1] === TRANSFORMED_NODES.conditional) { + // equivalent to whenTrue + if (this.JSONXML[nodeIndex].whenSomeType) { + eval(`${nestedExpression}whenTrue=[...${nestedExpression}whenTrue, constructedNode]`); + } else { + eval(`${nestedExpression}whenFalse=[...${nestedExpression}whenFalse, constructedNode]`); + } + if (eval(`${nestedExpression}isTrue`)) { + eval(`${nestedExpression}nodes=${nestedExpression}whenTrue`); + } else { + eval(`${nestedExpression}nodes=${nestedExpression}whenFalse`); + } } else { eval(`${nestedExpression}nodes=[...${nestedExpression}nodes, constructedNode]`); } @@ -375,6 +403,15 @@ class ToCiceroMarkVisitor { if (colorCodePresent && shadeCodePresent) { nodeInformation.nodeType = TRANSFORMED_NODES.code; } + /** + * for optional hasSome and whenSome stand for same as would be in the ciceromark. + * for conditional, the following relations with optional can be made + * optional | conditional + * hasSome | isTrue + * whenSome | whenTrue + * whenFalse | whenFalse + * The properties for conditional are not added therefore. + */ if (vanishPropertyPresent) { if (fontFamilyPresent) { nodeInformation.whenSomeType = false; @@ -395,7 +432,7 @@ class ToCiceroMarkVisitor { } else if (runTimeNodes.name === 'w:t') { if (calledBy === TRANSFORMED_NODES.codeBlock) { ooxmlTagTextValue += runTimeNodes.elements ? runTimeNodes.elements[0].text : ''; - } else if (calledBy === TRANSFORMED_NODES.optional) { + } else if (calledBy === TRANSFORMED_NODES.optional || calledBy === TRANSFORMED_NODES.conditional) { ooxmlTagTextValue = runTimeNodes.elements && runTimeNodes.elements[0].text; nodeInformation.value = ooxmlTagTextValue; } else { @@ -407,7 +444,7 @@ class ToCiceroMarkVisitor { ooxmlTagTextValue += '\n'; } else if (runTimeNodes.name === 'w:sym') { nodeInformation.nodeType = TRANSFORMED_NODES.softbreak; - if (calledBy !== TRANSFORMED_NODES.optional) { + if (!(calledBy === TRANSFORMED_NODES.optional || calledBy === TRANSFORMED_NODES.conditional)) { this.JSONXML = [...this.JSONXML, nodeInformation]; } } @@ -419,7 +456,7 @@ class ToCiceroMarkVisitor { nodeInformation.hasSome = true; } - if (calledBy === TRANSFORMED_NODES.optional) { + if (calledBy === TRANSFORMED_NODES.optional || calledBy === TRANSFORMED_NODES.conditional) { return nodeInformation; } return ooxmlTagTextValue; @@ -555,6 +592,20 @@ class ToCiceroMarkVisitor { this.JSONXML = [...this.JSONXML, { ...node }]; } } + } else if (nodeInformation.nodeType === TRANSFORMED_NODES.conditional) { + if (variableSubNodes.elements) { + const optionalNodes = this.traverseElements( + variableSubNodes.elements, + TRANSFORMED_NODES.conditional + ); + for (const node of optionalNodes) { + node.properties = [TRANSFORMED_NODES.conditional, ...node.properties]; + node.optionalProperties = { + name: nodeInformation.name, + }; + this.JSONXML = [...this.JSONXML, { ...node }]; + } + } } else { for (const variableContentNodes of variableSubNodes.elements) { if (variableContentNodes.name === 'w:r') { @@ -582,7 +633,7 @@ class ToCiceroMarkVisitor { inlineNodes = [...inlineNodes, this.fetchFormattingProperties(subNode, parent, nodeInformation)]; } } - if (parent === TRANSFORMED_NODES.optional) { + if (parent === TRANSFORMED_NODES.optional || parent === TRANSFORMED_NODES.conditional) { return inlineNodes; } return blockNodes; diff --git a/packages/markdown-docx/src/ToOOXMLVisitor/index.js b/packages/markdown-docx/src/ToOOXMLVisitor/index.js index 9e430009..05007c94 100644 --- a/packages/markdown-docx/src/ToOOXMLVisitor/index.js +++ b/packages/markdown-docx/src/ToOOXMLVisitor/index.js @@ -34,6 +34,7 @@ const { OPTIONAL_RULE, VANISH_PROPERTY_RULE, CONDITIONAL_OR_OPTIONAL_FONT_FAMILY_RULE, + CONDITIONAL_RULE, } = require('./rules'); const { wrapAroundDefaultDocxTags, wrapAroundLockedContentControls } = require('./helpers'); const { TRANSFORMED_NODES, RELATIONSHIP_OFFSET } = require('../constants'); @@ -153,13 +154,13 @@ class ToOOXMLVisitor { if (this.getClass(subNode) === TRANSFORMED_NODES.text) { const tag = this.generateTextOrCodeOOXML(subNode.text, properties, false, parentProperties); inlineOOXML += tag; - if (parent !== TRANSFORMED_NODES.optional) { + if (!(parent === TRANSFORMED_NODES.optional || parent === TRANSFORMED_NODES.conditional)) { this.tags = [...this.tags, tag]; } } else if (this.getClass(subNode) === TRANSFORMED_NODES.code) { const tag = this.generateTextOrCodeOOXML(subNode.text, properties, true, parentProperties); inlineOOXML += tag; - if (parent !== TRANSFORMED_NODES.optional) { + if (!(parent === TRANSFORMED_NODES.optional || parent === TRANSFORMED_NODES.conditional)) { this.tags = [...this.tags, tag]; } } else if (this.getClass(subNode) === TRANSFORMED_NODES.codeBlock) { @@ -190,12 +191,12 @@ class ToOOXMLVisitor { type, parentProperties.traversingNodeHiddenInConditional ); - if (parent !== TRANSFORMED_NODES.optional) { + 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.softbreak) { inlineOOXML += SOFTBREAK_RULE(); - if (parent !== TRANSFORMED_NODES.optional) { + if (!(parent === TRANSFORMED_NODES.optional || parent === TRANSFORMED_NODES.conditional)) { this.tags = [...this.tags, SOFTBREAK_RULE()]; } } else if (this.getClass(subNode) === TRANSFORMED_NODES.thematicBreak) { @@ -325,6 +326,31 @@ class ToOOXMLVisitor { // make the parentProperties false as traversal is done parentProperties.traversingNodeHiddenInConditional = false; parentProperties.traversingNodePresentInWhenFalseOrWhenNoneCondtion = false; + } else if (this.getClass(subNode) === TRANSFORMED_NODES.conditional) { + parentProperties.traversingNodeHiddenInConditional = !subNode.isTrue; + // traverse true nodes + const whenTrueOOXML = this.traverseNodes( + subNode.whenTrue, + properties, + TRANSFORMED_NODES.conditional, + parentProperties + ); + parentProperties.traversingNodePresentInWhenFalseOrWhenNoneCondtion = true; + // traverse false nodes + const whenFalseOOXML = this.traverseNodes( + subNode.whenFalse, + properties, + TRANSFORMED_NODES.conditional, + parentProperties + ); + const ooxml = `${whenTrueOOXML} ${whenFalseOOXML}`; + const tag = subNode.name; + this.createOrUpdateCounter(tag); + const title = `${tag.toUpperCase()[0]}${tag.substring(1)}${this.counter[tag].count}`; + const conditionalTag = CONDITIONAL_RULE(title, tag, ooxml); + this.tags = [...this.tags, conditionalTag]; + parentProperties.traversingNodeHiddenInConditional = false; + parentProperties.traversingNodePresentInWhenFalseOrWhenNoneCondtion = false; } else { if (this.getClass(subNode) === TRANSFORMED_NODES.link) { this.relationships = [ @@ -336,7 +362,7 @@ class ToOOXMLVisitor { ]; } let newProperties = [...properties, subNode.$class]; - this.traverseNodes(subNode.nodes, newProperties, parent, parentProperties); + inlineOOXML += this.traverseNodes(subNode.nodes, newProperties, parent, parentProperties); } } } diff --git a/packages/markdown-docx/src/ToOOXMLVisitor/rules.js b/packages/markdown-docx/src/ToOOXMLVisitor/rules.js index eedffa2e..915e78a1 100644 --- a/packages/markdown-docx/src/ToOOXMLVisitor/rules.js +++ b/packages/markdown-docx/src/ToOOXMLVisitor/rules.js @@ -283,14 +283,38 @@ const OPTIONAL_RULE = (title, tag, value, type) => { const VANISH_PROPERTY_RULE = () => ''; /** - * Inserts a different font family so that the `whenNone` nodes for optional content can be distinguished from `whenSome` nodes. - * + * Inserts a different font family so that the conditional/optional content(else condition) can be distinguished. They can be of following types:- + * 1) `whenNone` nodes for optional(to be distinguished from `whenSome`) + * 2) `whenFalse` nodes for conditional(to be distinguished from `whenTrue`) * @returns {string} OOXML tag for Baskerville Old Face font family */ const CONDITIONAL_OR_OPTIONAL_FONT_FAMILY_RULE = () => { return ''; }; +/** + * Inserts optional node in OOXML form. + * + * @param {string} title Title of the optional node. Eg. receiver-1, shipper-1 + * @param {string} tag Name of the optional node. Eg. receiver, shipper + * @param {string} value Value of the optional node + * @returns {string} OOXML string for the variable + */ +const CONDITIONAL_RULE = (title, tag, value) => { + return ` + + + + + + + + ${value} + + + `; +}; + module.exports = { TEXT_RULE, EMPHASIS_RULE, @@ -311,4 +335,5 @@ module.exports = { OPTIONAL_RULE, VANISH_PROPERTY_RULE, CONDITIONAL_OR_OPTIONAL_FONT_FAMILY_RULE, + CONDITIONAL_RULE, }; diff --git a/packages/markdown-docx/src/constants.js b/packages/markdown-docx/src/constants.js index 4014c688..8b86a2b1 100644 --- a/packages/markdown-docx/src/constants.js +++ b/packages/markdown-docx/src/constants.js @@ -21,6 +21,7 @@ const TRANSFORMED_NODES = { code: `${NS_PREFIX_CommonMarkModel}Code`, codeBlock: `${NS_PREFIX_CommonMarkModel}CodeBlock`, computedVariable: `${NS_PREFIX_CiceroMarkModel}ComputedVariable`, + conditional: `${NS_PREFIX_CiceroMarkModel}Conditional`, optional: `${NS_PREFIX_CiceroMarkModel}Optional`, document: `${NS_PREFIX_CommonMarkModel}Document`, emphasize: `${NS_PREFIX_CommonMarkModel}Emph`, diff --git a/packages/markdown-docx/test/data/ciceroMark/conditional-isTrue-false.json b/packages/markdown-docx/test/data/ciceroMark/conditional-isTrue-false.json new file mode 100644 index 00000000..40709229 --- /dev/null +++ b/packages/markdown-docx/test/data/ciceroMark/conditional-isTrue-false.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":"Late Delivery and Penalty."}]},{"$class":"org.accordproject.commonmark.Paragraph","nodes":[{"$class":"org.accordproject.commonmark.Text","text":"In case of delayed delivery"},{"$class":"org.accordproject.ciceromark.Conditional","isTrue":false,"whenTrue":[{"$class":"org.accordproject.commonmark.Text","text":" except for Force Majeure cases,"}],"whenFalse":[{"$class":"org.accordproject.commonmark.Text","text":" even when Force Majeure occurs,"}],"name":"forceMajeure","nodes":[{"$class":"org.accordproject.commonmark.Text","text":" even when Force Majeure occurs,"}]},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.ciceromark.Variable","value":"\"Dan\"","name":"seller","elementType":"org.accordproject.party.Party"},{"$class":"org.accordproject.commonmark.Text","text":" (the Seller) shall pay to "},{"$class":"org.accordproject.ciceromark.Variable","value":"\"Steve\"","name":"buyer","elementType":"org.accordproject.party.Party"},{"$class":"org.accordproject.commonmark.Text","text":" (the Buyer) for every "},{"$class":"org.accordproject.ciceromark.Variable","value":"2","name":"amount","elementType":"Long"},{"$class":"org.accordproject.commonmark.Text","text":" "},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"of delay penalty amounting to "},{"$class":"org.accordproject.ciceromark.Variable","value":"10.5","name":"penaltyPercentage","elementType":"Double"},{"$class":"org.accordproject.commonmark.Text","text":"% of the total value of the Equipment"},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"whose delivery has been delayed. Any fractional part of a "},{"$class":"org.accordproject.commonmark.Text","text":" is to be"},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"considered a full "},{"$class":"org.accordproject.commonmark.Text","text":". The total amount of penalty shall not however,"},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"exceed "},{"$class":"org.accordproject.ciceromark.Variable","value":"55.0","name":"capPercentage","elementType":"Double"},{"$class":"org.accordproject.commonmark.Text","text":"% of the total value of the Equipment involved in late delivery."},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"If the delay is more than "},{"$class":"org.accordproject.ciceromark.Variable","value":"15","name":"amount","elementType":"Long"},{"$class":"org.accordproject.commonmark.Text","text":" "},{"$class":"org.accordproject.commonmark.Text","text":", the Buyer is entitled to terminate this Contract."}]}]} \ No newline at end of file diff --git a/packages/markdown-docx/test/data/ciceroMark/conditional.json b/packages/markdown-docx/test/data/ciceroMark/conditional.json new file mode 100644 index 00000000..aecea8a5 --- /dev/null +++ b/packages/markdown-docx/test/data/ciceroMark/conditional.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":"Late Delivery and Penalty."}]},{"$class":"org.accordproject.commonmark.Paragraph","nodes":[{"$class":"org.accordproject.commonmark.Text","text":"In case of delayed delivery"},{"$class":"org.accordproject.ciceromark.Conditional","isTrue":true,"whenTrue":[{"$class":"org.accordproject.commonmark.Text","text":" except for Force Majeure cases,"},{"$class":"org.accordproject.commonmark.Emph","nodes":[{"$class":"org.accordproject.commonmark.Text","text":"not"}]}],"whenFalse":[{"$class":"org.accordproject.commonmark.Text","text":" even when Force Majeure occurs,"}],"name":"forceMajeure","nodes":[{"$class":"org.accordproject.commonmark.Text","text":" except for Force Majeure cases,"},{"$class":"org.accordproject.commonmark.Emph","nodes":[{"$class":"org.accordproject.commonmark.Text","text":"not"}]}]},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.ciceromark.Variable","value":"\"Dan\"","name":"seller","elementType":"org.accordproject.party.Party"},{"$class":"org.accordproject.commonmark.Text","text":" (the Seller) shall pay to "},{"$class":"org.accordproject.ciceromark.Variable","value":"\"Steve\"","name":"buyer","elementType":"org.accordproject.party.Party"},{"$class":"org.accordproject.commonmark.Text","text":" (the Buyer) for every "},{"$class":"org.accordproject.ciceromark.Variable","value":"2","name":"amount","elementType":"Long"},{"$class":"org.accordproject.commonmark.Text","text":" "},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"of delay penalty amounting to "},{"$class":"org.accordproject.ciceromark.Variable","value":"10.5","name":"penaltyPercentage","elementType":"Double"},{"$class":"org.accordproject.commonmark.Text","text":"% of the total value of the Equipment"},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"whose delivery has been delayed. Any fractional part of a "},{"$class":"org.accordproject.commonmark.Text","text":" is to be"},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"considered a full "},{"$class":"org.accordproject.commonmark.Text","text":". The total amount of penalty shall not however,"},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"exceed "},{"$class":"org.accordproject.ciceromark.Variable","value":"55.0","name":"capPercentage","elementType":"Double"},{"$class":"org.accordproject.commonmark.Text","text":"% of the total value of the Equipment involved in late delivery."},{"$class":"org.accordproject.commonmark.Softbreak"},{"$class":"org.accordproject.commonmark.Text","text":"If the delay is more than "},{"$class":"org.accordproject.ciceromark.Variable","value":"15","name":"amount","elementType":"Long"},{"$class":"org.accordproject.commonmark.Text","text":" "},{"$class":"org.accordproject.commonmark.Text","text":", the Buyer is entitled to terminate this Contract."}]}]} \ No newline at end of file