Bug if 2 (#8)
* Adjust variable marker to ignore {:else}
* Getting start branch right content and end branch left content when extracting block content
* remove open if block after {/if}
* look for left/right branch content only up to common ancestor
* fix test case to new reality
* fix minor bug
This commit is contained in:
parent
4e86fc1656
commit
29a2429c00
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,5 +3,7 @@ node_modules/
|
|||||||
build/*
|
build/*
|
||||||
|
|
||||||
.~lock*
|
.~lock*
|
||||||
|
**/*(Copie)*
|
||||||
|
**/*(Copy)*
|
||||||
|
|
||||||
stats.html
|
stats.html
|
||||||
@ -85,6 +85,7 @@ function findPlacesToFillInString(str, compartment) {
|
|||||||
* @returns {{startChild: Node, endChild:Node, content: DocumentFragment}}
|
* @returns {{startChild: Node, endChild:Node, content: DocumentFragment}}
|
||||||
*/
|
*/
|
||||||
function extractBlockContent(blockStartNode, blockEndNode) {
|
function extractBlockContent(blockStartNode, blockEndNode) {
|
||||||
|
//console.log('[extractBlockContent] blockStartNode', blockStartNode.textContent)
|
||||||
//console.log('[extractBlockContent] blockEndNode', blockEndNode.textContent)
|
//console.log('[extractBlockContent] blockEndNode', blockEndNode.textContent)
|
||||||
|
|
||||||
// find common ancestor of blockStartNode and blockEndNode
|
// find common ancestor of blockStartNode and blockEndNode
|
||||||
@ -93,6 +94,7 @@ function extractBlockContent(blockStartNode, blockEndNode) {
|
|||||||
let startAncestor = blockStartNode
|
let startAncestor = blockStartNode
|
||||||
let endAncestor = blockEndNode
|
let endAncestor = blockEndNode
|
||||||
|
|
||||||
|
// ancestries in order of deepest first, closest to root last
|
||||||
const startAncestry = new Set([startAncestor])
|
const startAncestry = new Set([startAncestor])
|
||||||
const endAncestry = new Set([endAncestor])
|
const endAncestry = new Set([endAncestor])
|
||||||
|
|
||||||
@ -117,9 +119,11 @@ function extractBlockContent(blockStartNode, blockEndNode) {
|
|||||||
const startAncestryToCommonAncestor = [...startAncestry].slice(0, [...startAncestry].indexOf(commonAncestor))
|
const startAncestryToCommonAncestor = [...startAncestry].slice(0, [...startAncestry].indexOf(commonAncestor))
|
||||||
const endAncestryToCommonAncestor = [...endAncestry].slice(0, [...endAncestry].indexOf(commonAncestor))
|
const endAncestryToCommonAncestor = [...endAncestry].slice(0, [...endAncestry].indexOf(commonAncestor))
|
||||||
|
|
||||||
|
// direct children of commonAncestor in the branch or blockStartNode and blockEndNode respectively
|
||||||
const startChild = startAncestryToCommonAncestor.at(-1)
|
const startChild = startAncestryToCommonAncestor.at(-1)
|
||||||
const endChild = endAncestryToCommonAncestor.at(-1)
|
const endChild = endAncestryToCommonAncestor.at(-1)
|
||||||
|
|
||||||
|
//console.log('[extractBlockContent] startChild', startChild.textContent)
|
||||||
//console.log('[extractBlockContent] endChild', endChild.textContent)
|
//console.log('[extractBlockContent] endChild', endChild.textContent)
|
||||||
|
|
||||||
// Extract DOM content in a documentFragment
|
// Extract DOM content in a documentFragment
|
||||||
@ -127,15 +131,57 @@ function extractBlockContent(blockStartNode, blockEndNode) {
|
|||||||
const contentFragment = blockStartNode.ownerDocument.createDocumentFragment()
|
const contentFragment = blockStartNode.ownerDocument.createDocumentFragment()
|
||||||
|
|
||||||
/** @type {Element[]} */
|
/** @type {Element[]} */
|
||||||
const repeatedPatternArray = []
|
const blockContent = []
|
||||||
|
|
||||||
|
// get start branch "right" content
|
||||||
|
for(const startAncestor of startAncestryToCommonAncestor){
|
||||||
|
if(startAncestor === startChild)
|
||||||
|
break;
|
||||||
|
|
||||||
|
let sibling = startAncestor.nextSibling
|
||||||
|
|
||||||
|
while(sibling) {
|
||||||
|
blockContent.push(sibling)
|
||||||
|
sibling = sibling.nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let sibling = startChild.nextSibling
|
let sibling = startChild.nextSibling
|
||||||
|
|
||||||
while(sibling !== endChild) {
|
while(sibling !== endChild) {
|
||||||
repeatedPatternArray.push(sibling)
|
blockContent.push(sibling)
|
||||||
sibling = sibling.nextSibling;
|
sibling = sibling.nextSibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const sibling of repeatedPatternArray) {
|
|
||||||
|
// get end branch "left" content
|
||||||
|
for(const endAncestor of [...endAncestryToCommonAncestor].reverse()){
|
||||||
|
if(endAncestor === endChild)
|
||||||
|
continue; // already taken care of
|
||||||
|
|
||||||
|
let sibling = endAncestor.previousSibling
|
||||||
|
|
||||||
|
const reversedBlockContentContribution = []
|
||||||
|
|
||||||
|
while(sibling) {
|
||||||
|
reversedBlockContentContribution.push(sibling)
|
||||||
|
sibling = sibling.previousSibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
const blockContentContribution = reversedBlockContentContribution.reverse()
|
||||||
|
|
||||||
|
blockContent.push(...blockContentContribution)
|
||||||
|
|
||||||
|
if(endAncestor === blockEndNode)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//console.log('blockContent', blockContent.map(n => n.textContent))
|
||||||
|
|
||||||
|
|
||||||
|
for(const sibling of blockContent) {
|
||||||
sibling.parentNode?.removeChild(sibling)
|
sibling.parentNode?.removeChild(sibling)
|
||||||
contentFragment.appendChild(sibling)
|
contentFragment.appendChild(sibling)
|
||||||
}
|
}
|
||||||
@ -206,7 +252,6 @@ function fillIfBlock(ifOpeningMarkerNode, ifElseMarkerNode, ifClosingMarkerNode,
|
|||||||
.add(startIfThenChild).add(endIfThenChild)
|
.add(startIfThenChild).add(endIfThenChild)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(chosenFragment) {
|
if(chosenFragment) {
|
||||||
fillOdtElementTemplate(
|
fillOdtElementTemplate(
|
||||||
chosenFragment,
|
chosenFragment,
|
||||||
@ -340,7 +385,8 @@ const EACH = eachStartMarkerRegex.source
|
|||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export default function fillOdtElementTemplate(rootElement, compartment) {
|
export default function fillOdtElementTemplate(rootElement, compartment) {
|
||||||
//console.log('fillTemplatedOdtElement', rootElement.nodeType, rootElement.nodeName)
|
//console.log('fillTemplatedOdtElement', rootElement.nodeType, rootElement.nodeName, rootElement.textContent)
|
||||||
|
//console.log('fillTemplatedOdtElement', rootElement.childNodes[0].childNodes.length)
|
||||||
|
|
||||||
let currentlyOpenBlocks = []
|
let currentlyOpenBlocks = []
|
||||||
|
|
||||||
@ -362,9 +408,11 @@ export default function fillOdtElementTemplate(rootElement, compartment) {
|
|||||||
let ifBlockConditionExpression
|
let ifBlockConditionExpression
|
||||||
// Traverse "in document order"
|
// Traverse "in document order"
|
||||||
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
traverse(rootElement, currentNode => {
|
traverse(rootElement, currentNode => {
|
||||||
//console.log('currentlyUnclosedBlocks', currentlyUnclosedBlocks)
|
//console.log('currentlyOpenBlocks', currentlyOpenBlocks)
|
||||||
|
|
||||||
const insideAnOpenBlock = currentlyOpenBlocks.length >= 1
|
const insideAnOpenBlock = currentlyOpenBlocks.length >= 1
|
||||||
|
|
||||||
if(currentNode.nodeType === Node.TEXT_NODE) {
|
if(currentNode.nodeType === Node.TEXT_NODE) {
|
||||||
@ -473,9 +521,9 @@ export default function fillOdtElementTemplate(rootElement, compartment) {
|
|||||||
/**
|
/**
|
||||||
* Looking for {/if}
|
* Looking for {/if}
|
||||||
*/
|
*/
|
||||||
const hasClosingMarker = text.includes(closingIfMarker);
|
const ifClosingMarker = text.includes(closingIfMarker);
|
||||||
|
|
||||||
if(hasClosingMarker) {
|
if(ifClosingMarker) {
|
||||||
if(!insideAnOpenBlock)
|
if(!insideAnOpenBlock)
|
||||||
throw new Error('{/if} without a corresponding {#if}')
|
throw new Error('{/if} without a corresponding {#if}')
|
||||||
|
|
||||||
@ -498,6 +546,8 @@ export default function fillOdtElementTemplate(rootElement, compartment) {
|
|||||||
else {
|
else {
|
||||||
// do nothing because the marker is too deep
|
// do nothing because the marker is too deep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentlyOpenBlocks.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
// the regexps below are shared, so they shoudn't have state (no 'g' flag)
|
// the regexps below are shared, so they shoudn't have state (no 'g' flag)
|
||||||
export const variableRegex = /\{([^{#\/]+?)\}/
|
export const variableRegex = /\{([^{#\/:]+?)\}/
|
||||||
|
|
||||||
export const ifStartMarkerRegex = /{#if\s+([^}]+?)\s*}/;
|
export const ifStartMarkerRegex = /{#if\s+([^}]+?)\s*}/;
|
||||||
export const elseMarker = '{:else}'
|
export const elseMarker = '{:else}'
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
import {traverse, Node} from "../../DOMUtils.js";
|
import {traverse, Node} from "../../DOMUtils.js";
|
||||||
import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex, variableRegex} from './markers.js'
|
import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex, variableRegex} from './markers.js'
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} text
|
* @param {string} text
|
||||||
@ -166,6 +167,7 @@ function consolidateMarkers(document){
|
|||||||
]
|
]
|
||||||
|
|
||||||
for(const potentialMarkersContainer of potentialMarkersContainers) {
|
for(const potentialMarkersContainer of potentialMarkersContainers) {
|
||||||
|
/** @type {{marker: string, index: number}[]} */
|
||||||
const consolidatedMarkers = []
|
const consolidatedMarkers = []
|
||||||
|
|
||||||
/** @type {Text[]} */
|
/** @type {Text[]} */
|
||||||
@ -244,13 +246,16 @@ function consolidateMarkers(document){
|
|||||||
|
|
||||||
// Check if marker spans multiple nodes
|
// Check if marker spans multiple nodes
|
||||||
if(startNode !== endNode) {
|
if(startNode !== endNode) {
|
||||||
|
//console.log('startNode !== endNode', startNode.textContent, endNode.textContent)
|
||||||
const commonAncestor = findCommonAncestor(startNode, endNode)
|
const commonAncestor = findCommonAncestor(startNode, endNode)
|
||||||
|
|
||||||
|
/** @type {Node} */
|
||||||
let commonAncestorStartChild = startNode
|
let commonAncestorStartChild = startNode
|
||||||
while(commonAncestorStartChild.parentNode !== commonAncestor){
|
while(commonAncestorStartChild.parentNode !== commonAncestor){
|
||||||
commonAncestorStartChild = commonAncestorStartChild.parentNode
|
commonAncestorStartChild = commonAncestorStartChild.parentNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {Node} */
|
||||||
let commonAncestorEndChild = endNode
|
let commonAncestorEndChild = endNode
|
||||||
while(commonAncestorEndChild.parentNode !== commonAncestor){
|
while(commonAncestorEndChild.parentNode !== commonAncestor){
|
||||||
commonAncestorEndChild = commonAncestorEndChild.parentNode
|
commonAncestorEndChild = commonAncestorEndChild.parentNode
|
||||||
@ -322,6 +327,7 @@ function consolidateMarkers(document){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -551,5 +557,4 @@ export default function prepareTemplateDOMTree(document){
|
|||||||
isolateMarkerText(document)
|
isolateMarkerText(document)
|
||||||
// after isolateMarkerText, each marker is in exactly one text node
|
// after isolateMarkerText, each marker is in exactly one text node
|
||||||
// (markers are separated from text that was before or after in the same text node)
|
// (markers are separated from text that was before or after in the same text node)
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -327,16 +327,22 @@ Année
|
|||||||
|
|
||||||
Année
|
Année
|
||||||
Énergie par personne
|
Énergie par personne
|
||||||
|
|
||||||
1970
|
1970
|
||||||
36252.637
|
36252.637
|
||||||
|
|
||||||
1980
|
1980
|
||||||
43328.78
|
43328.78
|
||||||
|
|
||||||
1990
|
1990
|
||||||
46971.94
|
46971.94
|
||||||
|
|
||||||
2000
|
2000
|
||||||
53147.277
|
53147.277
|
||||||
|
|
||||||
2010
|
2010
|
||||||
48062.32
|
48062.32
|
||||||
|
|
||||||
2020
|
2020
|
||||||
37859.246
|
37859.246
|
||||||
`.trim())
|
`.trim())
|
||||||
|
|||||||
@ -40,3 +40,30 @@ n est un grand nombre
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('weird bug', async t => {
|
||||||
|
const templatePath = join(import.meta.dirname, '../fixtures/left-branch-content-and-two-consecutive-ifs.odt')
|
||||||
|
const templateContent = `Utilisation de sources lumineuses : {#if scientifique.source_lumineuses}Oui{:else}Non{/if}
|
||||||
|
{#if scientifique.source_lumineuses && scientifique.modalités_source_lumineuses }
|
||||||
|
Modalités d’utilisation de sources lumineuses : {scientifique.modalités_source_lumineuses}
|
||||||
|
{/if}
|
||||||
|
`
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
scientifique: {
|
||||||
|
source_lumineuses: false,
|
||||||
|
//modalités_source_lumineuses: 'lampes torches'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const odtTemplate = await getOdtTemplate(templatePath)
|
||||||
|
const templateTextContent = await getOdtTextContent(odtTemplate)
|
||||||
|
t.deepEqual(templateTextContent.trim(), templateContent.trim(), 'reconnaissance du template')
|
||||||
|
|
||||||
|
const odtResult = await fillOdtTemplate(odtTemplate, data)
|
||||||
|
const odtResultTextContent = await getOdtTextContent(odtResult)
|
||||||
|
t.deepEqual(odtResultTextContent.trim(), `Utilisation de sources lumineuses : Non`)
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|||||||
BIN
tests/fixtures/left-branch-content-and-two-consecutive-ifs.odt
vendored
Normal file
BIN
tests/fixtures/left-branch-content-and-two-consecutive-ifs.odt
vendored
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user