From 3da7f29cb0b351efd9a231a7c313d05d9e6fe04b Mon Sep 17 00:00:00 2001 From: David Bruant Date: Sat, 26 Apr 2025 19:59:44 +0200 Subject: [PATCH] Split text nodes so they contain at most one structuring block (#3) * rename test folders * failing test * First promising result of splitting textNodes to enable {#each}{/each} block within a single text node * tests passing * cleanup --- scripts/odf/fillOdtTemplate.js | 81 ++++++++++++++++-- tests/basic-node.js | 2 +- tests/fill-odt-template.js | 50 ++++++++--- .../{data => fixtures}/cellule avec sauts.ods | Bin .../cellules avec dates.ods | Bin .../cellules-répétées.ods | Bin tests/{data => fixtures}/enum-courses.odt | Bin tests/{data => fixtures}/liste-courses.odt | Bin .../liste-fruits-et-légumes.odt | Bin tests/fixtures/liste-nombres.odt | Bin 0 -> 12458 bytes .../{data => fixtures}/légumes-de-saison.odt | Bin tests/{data => fixtures}/nom-age.ods | Bin tests/{data => fixtures}/tableau-simple.odt | Bin .../template-anniversaire.odt | Bin .../template-avec-image.odt | Bin tests/{_helpers => helpers}/zip-analysis.js | 0 tests/ods-files.js | 6 +- 17 files changed, 113 insertions(+), 26 deletions(-) rename tests/{data => fixtures}/cellule avec sauts.ods (100%) rename tests/{data => fixtures}/cellules avec dates.ods (100%) rename tests/{data => fixtures}/cellules-répétées.ods (100%) rename tests/{data => fixtures}/enum-courses.odt (100%) rename tests/{data => fixtures}/liste-courses.odt (100%) rename tests/{data => fixtures}/liste-fruits-et-légumes.odt (100%) create mode 100644 tests/fixtures/liste-nombres.odt rename tests/{data => fixtures}/légumes-de-saison.odt (100%) rename tests/{data => fixtures}/nom-age.ods (100%) rename tests/{data => fixtures}/tableau-simple.odt (100%) rename tests/{data => fixtures}/template-anniversaire.odt (100%) rename tests/{data => fixtures}/template-avec-image.odt (100%) rename tests/{_helpers => helpers}/zip-analysis.js (100%) diff --git a/scripts/odf/fillOdtTemplate.js b/scripts/odf/fillOdtTemplate.js index 8ef4e4b..0e09c51 100644 --- a/scripts/odf/fillOdtTemplate.js +++ b/scripts/odf/fillOdtTemplate.js @@ -217,6 +217,7 @@ function fillEachBlock(startNode, iterableExpression, itemExpression, endNode, d } + /** * * @param {Element | DocumentFragment} rootElement @@ -227,6 +228,70 @@ function fillEachBlock(startNode, iterableExpression, itemExpression, endNode, d function fillTemplatedOdtElement(rootElement, data, Node){ //console.log('fillTemplatedOdtElement', rootElement.nodeType, rootElement.nodeName) + // Perform a first traverse to split textnodes when they contain several block markers + traverse(rootElement, currentNode => { + if(currentNode.nodeType === Node.TEXT_NODE){ + // trouver tous les débuts et fin de each et découper le textNode + + let remainingText = currentNode.textContent || '' + + while(remainingText.length >= 1){ + let match; + + // looking for opening {#each ...} block + const eachBlockOpeningRegex = /{#each\s+([^}]+?)\s+as\s+([^}]+?)\s*}/; + const eachBlockClosingRegex = /{\/each}/; + + for(const regexp of [eachBlockOpeningRegex, eachBlockClosingRegex]){ + let thisMatch = remainingText.match(regexp) + + // trying to find only the first match in remainingText string + if(thisMatch && (!match || match.index > thisMatch.index)){ + match = thisMatch + } + } + + if(match){ + // split 3-way : before-match, match and after-match + + if(match[0].length < remainingText.length){ + let afterMatchTextNode = currentNode.splitText(match.index + match[0].length) + if(afterMatchTextNode.textContent && afterMatchTextNode.textContent.length >= 1){ + remainingText = afterMatchTextNode.textContent + } + else{ + remainingText = '' + } + + // per spec, currentNode now contains before-match and match text + + if(match.index > 0){ + currentNode.splitText(match.index) + } + + if(afterMatchTextNode){ + currentNode = afterMatchTextNode + } + } + else{ + remainingText = '' + } + } + else{ + remainingText = '' + } + } + + } + else{ + // skip + } + }) + + // now, each Node contains at most one block marker + + + /** @type {Node | undefined} */ let eachBlockStartNode /** @type {Node | undefined} */ @@ -246,17 +311,15 @@ function fillTemplatedOdtElement(rootElement, data, Node){ const text = currentNode.textContent || '' // looking for {#each x as y} - const eachStartRegex = /{#each\s+([^}]+?)\s+as\s+([^}]+?)\s*}/g; - const startMatches = [...text.matchAll(eachStartRegex)]; + const eachStartRegex = /{#each\s+([^}]+?)\s+as\s+([^}]+?)\s*}/; + const startMatch = text.match(eachStartRegex); - if(startMatches && startMatches.length >= 1){ + if(startMatch){ if(insideAnEachBlock){ nestedEach = nestedEach + 1 } else{ - // PPP for now, consider only the first set of matches - // eventually, consider all of them for in-text-node {#each}...{/each} - let [_, _iterableExpression, _itemExpression] = startMatches[0] + let [_, _iterableExpression, _itemExpression] = startMatch iterableExpression = _iterableExpression itemExpression = _itemExpression @@ -265,10 +328,10 @@ function fillTemplatedOdtElement(rootElement, data, Node){ } // trying to find an {/each} - const eachEndRegex = /{\/each}/g - const endMatches = [...text.matchAll(eachEndRegex)]; + const eachEndRegex = /{\/each}/ + const endMatch = text.match(eachEndRegex) - if(endMatches && endMatches.length >= 1){ + if(endMatch){ if(!eachBlockStartNode) throw new TypeError(`{/each} found without corresponding opening {#each x as y}`) diff --git a/tests/basic-node.js b/tests/basic-node.js index 5f538c4..fb07e98 100644 --- a/tests/basic-node.js +++ b/tests/basic-node.js @@ -4,7 +4,7 @@ import test from 'ava'; import {getODSTableRawContent} from '../exports.js' -const nomAgeContent = (await readFile('./tests/data/nom-age.ods')).buffer +const nomAgeContent = (await readFile('./tests/fixtures/nom-age.ods')).buffer test('basic', async t => { const table = await getODSTableRawContent(nomAgeContent); diff --git a/tests/fill-odt-template.js b/tests/fill-odt-template.js index dcec8b4..ec06b9a 100644 --- a/tests/fill-odt-template.js +++ b/tests/fill-odt-template.js @@ -4,11 +4,11 @@ import {join} from 'node:path'; import {getOdtTemplate} from '../scripts/odf/odtTemplate-forNode.js' import {fillOdtTemplate, getOdtTextContent} from '../exports.js' -import { listZipEntries } from './_helpers/zip-analysis.js'; +import { listZipEntries } from './helpers/zip-analysis.js'; test('basic template filling with variable substitution', async t => { - const templatePath = join(import.meta.dirname, './data/template-anniversaire.odt') + const templatePath = join(import.meta.dirname, './fixtures/template-anniversaire.odt') const templateContent = `Yo {nom} ! Tu es né.e le {dateNaissance} @@ -36,9 +36,8 @@ Bonjoir ☀️ }); - test('basic template filling with {#each}', async t => { - const templatePath = join(import.meta.dirname, './data/enum-courses.odt') + const templatePath = join(import.meta.dirname, './fixtures/enum-courses.odt') const templateContent = `🧺 La liste de courses incroyable 🧺 {#each listeCourses as élément} @@ -73,8 +72,9 @@ Pâtes à lasagne (fraîches !) }); + test('Filling with {#each} and non-iterable value results in no error and empty result', async t => { - const templatePath = join(import.meta.dirname, './data/enum-courses.odt') + const templatePath = join(import.meta.dirname, './fixtures/enum-courses.odt') const templateContent = `🧺 La liste de courses incroyable 🧺 {#each listeCourses as élément} @@ -103,9 +103,8 @@ test('Filling with {#each} and non-iterable value results in no error and empty }); - test('template filling with {#each} generating a list', async t => { - const templatePath = join(import.meta.dirname, './data/liste-courses.odt') + const templatePath = join(import.meta.dirname, './fixtures/liste-courses.odt') const templateContent = `🧺 La liste de courses incroyable 🧺 - {#each listeCourses as élément} @@ -142,7 +141,7 @@ test('template filling with {#each} generating a list', async t => { test('template filling with 2 sequential {#each}', async t => { - const templatePath = join(import.meta.dirname, './data/liste-fruits-et-légumes.odt') + const templatePath = join(import.meta.dirname, './fixtures/liste-fruits-et-légumes.odt') const templateContent = `Liste de fruits et légumes Fruits @@ -193,9 +192,8 @@ Poivron 🫑 }); - test('template filling with nested {#each}s', async t => { - const templatePath = join(import.meta.dirname, './data/légumes-de-saison.odt') + const templatePath = join(import.meta.dirname, './fixtures/légumes-de-saison.odt') const templateContent = `Légumes de saison {#each légumesSaison as saisonLégumes} @@ -279,9 +277,36 @@ Hiver }); +test('template filling {#each ...}{/each} within a single text node', async t => { + const templatePath = join(import.meta.dirname, './fixtures/liste-nombres.odt') + const templateContent = `Liste de nombres + +Les nombres : {#each nombres as n}{n} {/each} !! +` + + const data = { + nombres : [1,1,2,3,5,8,13,21] + } + + const odtTemplate = await getOdtTemplate(templatePath) + + const templateTextContent = await getOdtTextContent(odtTemplate) + t.deepEqual(templateTextContent, templateContent, 'reconnaissance du template') + + const odtResult = await fillOdtTemplate(odtTemplate, data) + + const odtResultTextContent = await getOdtTextContent(odtResult) + t.deepEqual(odtResultTextContent, `Liste de nombres + +Les nombres : 1 1 2 3 5 8 13 21  !! +`) + +}); + + test('template filling of a table', async t => { - const templatePath = join(import.meta.dirname, './data/tableau-simple.odt') + const templatePath = join(import.meta.dirname, './fixtures/tableau-simple.odt') const templateContent = `Évolution énergie en kWh par personne en France Année @@ -341,9 +366,8 @@ Année }); - test('template filling preserves images', async t => { - const templatePath = join(import.meta.dirname, './data/template-avec-image.odt') + const templatePath = join(import.meta.dirname, './fixtures/template-avec-image.odt') const data = { commentaire : `J'adooooooore 🤩 West covinaaaaaaaaaaa 🎶` diff --git a/tests/data/cellule avec sauts.ods b/tests/fixtures/cellule avec sauts.ods similarity index 100% rename from tests/data/cellule avec sauts.ods rename to tests/fixtures/cellule avec sauts.ods diff --git a/tests/data/cellules avec dates.ods b/tests/fixtures/cellules avec dates.ods similarity index 100% rename from tests/data/cellules avec dates.ods rename to tests/fixtures/cellules avec dates.ods diff --git a/tests/data/cellules-répétées.ods b/tests/fixtures/cellules-répétées.ods similarity index 100% rename from tests/data/cellules-répétées.ods rename to tests/fixtures/cellules-répétées.ods diff --git a/tests/data/enum-courses.odt b/tests/fixtures/enum-courses.odt similarity index 100% rename from tests/data/enum-courses.odt rename to tests/fixtures/enum-courses.odt diff --git a/tests/data/liste-courses.odt b/tests/fixtures/liste-courses.odt similarity index 100% rename from tests/data/liste-courses.odt rename to tests/fixtures/liste-courses.odt diff --git a/tests/data/liste-fruits-et-légumes.odt b/tests/fixtures/liste-fruits-et-légumes.odt similarity index 100% rename from tests/data/liste-fruits-et-légumes.odt rename to tests/fixtures/liste-fruits-et-légumes.odt diff --git a/tests/fixtures/liste-nombres.odt b/tests/fixtures/liste-nombres.odt new file mode 100644 index 0000000000000000000000000000000000000000..5088eee3b45571c0d174edb3cbca2504be210d35 GIT binary patch literal 12458 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 F{{#Lu>?Z&K literal 0 HcmV?d00001 diff --git a/tests/data/légumes-de-saison.odt b/tests/fixtures/légumes-de-saison.odt similarity index 100% rename from tests/data/légumes-de-saison.odt rename to tests/fixtures/légumes-de-saison.odt diff --git a/tests/data/nom-age.ods b/tests/fixtures/nom-age.ods similarity index 100% rename from tests/data/nom-age.ods rename to tests/fixtures/nom-age.ods diff --git a/tests/data/tableau-simple.odt b/tests/fixtures/tableau-simple.odt similarity index 100% rename from tests/data/tableau-simple.odt rename to tests/fixtures/tableau-simple.odt diff --git a/tests/data/template-anniversaire.odt b/tests/fixtures/template-anniversaire.odt similarity index 100% rename from tests/data/template-anniversaire.odt rename to tests/fixtures/template-anniversaire.odt diff --git a/tests/data/template-avec-image.odt b/tests/fixtures/template-avec-image.odt similarity index 100% rename from tests/data/template-avec-image.odt rename to tests/fixtures/template-avec-image.odt diff --git a/tests/_helpers/zip-analysis.js b/tests/helpers/zip-analysis.js similarity index 100% rename from tests/_helpers/zip-analysis.js rename to tests/helpers/zip-analysis.js diff --git a/tests/ods-files.js b/tests/ods-files.js index 66017c9..5926b5b 100644 --- a/tests/ods-files.js +++ b/tests/ods-files.js @@ -5,7 +5,7 @@ import test from 'ava'; import {getODSTableRawContent} from '../exports.js' test('.ods file with table:number-columns-repeated attribute in cell', async t => { - const repeatedCellFileContent = (await readFile('./tests/data/cellules-répétées.ods')).buffer + const repeatedCellFileContent = (await readFile('./tests/fixtures/cellules-répétées.ods')).buffer const table = await getODSTableRawContent(repeatedCellFileContent); @@ -17,7 +17,7 @@ test('.ods file with table:number-columns-repeated attribute in cell', async t = test('.ods cells with dates should be recognized', async t => { - const odsFileWithDates = (await readFile('./tests/data/cellules avec dates.ods')).buffer + const odsFileWithDates = (await readFile('./tests/fixtures/cellules avec dates.ods')).buffer const table = await getODSTableRawContent(odsFileWithDates); const feuille1 = table.get('Feuille1') @@ -39,7 +39,7 @@ test('.ods cells with dates should be recognized', async t => { test('.ods file with new lines in content is ', async t => { - const repeatedCellFileContent = (await readFile('./tests/data/cellule avec sauts.ods')).buffer + const repeatedCellFileContent = (await readFile('./tests/fixtures/cellule avec sauts.ods')).buffer const table = await getODSTableRawContent(repeatedCellFileContent);