Compare commits
5 Commits
main
...
in-text-no
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08085debc5 | ||
|
|
94dbd2c54e | ||
|
|
4882c39e32 | ||
|
|
9275e5777a | ||
|
|
6cf15c7d04 |
@ -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}`)
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 🎶`
|
||||
|
||||
BIN
tests/fixtures/liste-nombres.odt
vendored
Normal file
BIN
tests/fixtures/liste-nombres.odt
vendored
Normal file
Binary file not shown.
@ -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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user