Compare commits

...

6 Commits

Author SHA1 Message Date
David Bruant
1d42b4d0eb fix minor bug 2025-05-21 15:04:16 +02:00
David Bruant
08e40f3607 fix test case to new reality 2025-05-21 14:01:50 +02:00
David Bruant
8beb2f5279 look for left/right branch content only up to common ancestor 2025-05-21 12:45:47 +02:00
David Bruant
86c1676614 remove open if block after {/if} 2025-05-21 12:36:02 +02:00
David Bruant
788acba66b Getting start branch right content and end branch left content when extracting block content 2025-05-21 12:08:22 +02:00
David Bruant
8ddf6fe221 Adjust variable marker to ignore {:else} 2025-05-21 11:28:50 +02:00
7 changed files with 100 additions and 10 deletions

2
.gitignore vendored
View File

@ -3,5 +3,7 @@ node_modules/
build/*
.~lock*
**/*(Copie)*
**/*(Copy)*
stats.html

View File

@ -85,6 +85,7 @@ function findPlacesToFillInString(str, compartment) {
* @returns {{startChild: Node, endChild:Node, content: DocumentFragment}}
*/
function extractBlockContent(blockStartNode, blockEndNode) {
//console.log('[extractBlockContent] blockStartNode', blockStartNode.textContent)
//console.log('[extractBlockContent] blockEndNode', blockEndNode.textContent)
// find common ancestor of blockStartNode and blockEndNode
@ -93,6 +94,7 @@ function extractBlockContent(blockStartNode, blockEndNode) {
let startAncestor = blockStartNode
let endAncestor = blockEndNode
// ancestries in order of deepest first, closest to root last
const startAncestry = new Set([startAncestor])
const endAncestry = new Set([endAncestor])
@ -117,9 +119,11 @@ function extractBlockContent(blockStartNode, blockEndNode) {
const startAncestryToCommonAncestor = [...startAncestry].slice(0, [...startAncestry].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 endChild = endAncestryToCommonAncestor.at(-1)
//console.log('[extractBlockContent] startChild', startChild.textContent)
//console.log('[extractBlockContent] endChild', endChild.textContent)
// Extract DOM content in a documentFragment
@ -127,15 +131,57 @@ function extractBlockContent(blockStartNode, blockEndNode) {
const contentFragment = blockStartNode.ownerDocument.createDocumentFragment()
/** @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
while(sibling !== endChild) {
repeatedPatternArray.push(sibling)
blockContent.push(sibling)
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)
contentFragment.appendChild(sibling)
}
@ -206,7 +252,6 @@ function fillIfBlock(ifOpeningMarkerNode, ifElseMarkerNode, ifClosingMarkerNode,
.add(startIfThenChild).add(endIfThenChild)
}
if(chosenFragment) {
fillOdtElementTemplate(
chosenFragment,
@ -340,7 +385,8 @@ const EACH = eachStartMarkerRegex.source
* @returns {void}
*/
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 = []
@ -362,9 +408,11 @@ export default function fillOdtElementTemplate(rootElement, compartment) {
let ifBlockConditionExpression
// Traverse "in document order"
// @ts-ignore
traverse(rootElement, currentNode => {
//console.log('currentlyUnclosedBlocks', currentlyUnclosedBlocks)
//console.log('currentlyOpenBlocks', currentlyOpenBlocks)
const insideAnOpenBlock = currentlyOpenBlocks.length >= 1
if(currentNode.nodeType === Node.TEXT_NODE) {
@ -473,9 +521,9 @@ export default function fillOdtElementTemplate(rootElement, compartment) {
/**
* Looking for {/if}
*/
const hasClosingMarker = text.includes(closingIfMarker);
const ifClosingMarker = text.includes(closingIfMarker);
if(hasClosingMarker) {
if(ifClosingMarker) {
if(!insideAnOpenBlock)
throw new Error('{/if} without a corresponding {#if}')
@ -498,6 +546,8 @@ export default function fillOdtElementTemplate(rootElement, compartment) {
else {
// do nothing because the marker is too deep
}
currentlyOpenBlocks.pop()
}

View File

@ -1,5 +1,5 @@
// 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 elseMarker = '{:else}'

View File

@ -3,6 +3,7 @@
import {traverse, Node} from "../../DOMUtils.js";
import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex, variableRegex} from './markers.js'
/**
*
* @param {string} text
@ -166,6 +167,7 @@ function consolidateMarkers(document){
]
for(const potentialMarkersContainer of potentialMarkersContainers) {
/** @type {{marker: string, index: number}[]} */
const consolidatedMarkers = []
/** @type {Text[]} */
@ -244,13 +246,16 @@ function consolidateMarkers(document){
// Check if marker spans multiple nodes
if(startNode !== endNode) {
//console.log('startNode !== endNode', startNode.textContent, endNode.textContent)
const commonAncestor = findCommonAncestor(startNode, endNode)
/** @type {Node} */
let commonAncestorStartChild = startNode
while(commonAncestorStartChild.parentNode !== commonAncestor){
commonAncestorStartChild = commonAncestorStartChild.parentNode
}
/** @type {Node} */
let commonAncestorEndChild = endNode
while(commonAncestorEndChild.parentNode !== commonAncestor){
commonAncestorEndChild = commonAncestorEndChild.parentNode
@ -322,6 +327,7 @@ function consolidateMarkers(document){
}
}
}
}
/**
@ -551,5 +557,4 @@ export default function prepareTemplateDOMTree(document){
isolateMarkerText(document)
// 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)
}

View File

@ -327,16 +327,22 @@ Année
Année
Énergie par personne
1970
36252.637
1980
43328.78
1990
46971.94
2000
53147.277
2010
48062.32
2020
37859.246
`.trim())

View File

@ -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 dutilisation 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`)
});

Binary file not shown.