From dd09b7a1178d2b5aace6bffac2f0b758e07edffd Mon Sep 17 00:00:00 2001 From: David Bruant Date: Thu, 8 May 2025 17:08:35 +0200 Subject: [PATCH] test with partially formatted variable passes --- .../odf/templating/fillOdtElementTemplate.js | 5 +-- scripts/odf/templating/markers.js | 2 ++ .../odf/templating/prepareTemplateDOMTree.js | 19 ++++-------- tests/fill-odt-template/formatting.js | 29 +++++++++++++++++- .../fixtures/partially-formatted-variable.odt | Bin 0 -> 11685 bytes 5 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 tests/fixtures/partially-formatted-variable.odt diff --git a/scripts/odf/templating/fillOdtElementTemplate.js b/scripts/odf/templating/fillOdtElementTemplate.js index f4f48be..fd6995f 100644 --- a/scripts/odf/templating/fillOdtElementTemplate.js +++ b/scripts/odf/templating/fillOdtElementTemplate.js @@ -1,5 +1,5 @@ import {traverse, Node} from '../../DOMUtils.js' -import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex} from './markers.js' +import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex, variableRegex} from './markers.js' /** * @typedef TextPlaceToFill @@ -14,7 +14,8 @@ import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, if * @returns {TextPlaceToFill | undefined} */ function findPlacesToFillInString(str, compartment) { - const matches = str.matchAll(/\{([^{#\/]+?)\}/g) + const varRexExp = new RegExp(variableRegex.source, 'g'); + const matches = str.matchAll(varRexExp) /** @type {TextPlaceToFill['expressions']} */ const expressions = [] diff --git a/scripts/odf/templating/markers.js b/scripts/odf/templating/markers.js index da1928a..1a09f1e 100644 --- a/scripts/odf/templating/markers.js +++ b/scripts/odf/templating/markers.js @@ -1,4 +1,6 @@ // the regexps below are shared, so they shoudn't have state (no 'g' flag) +export const variableRegex = /\{([^{#\/]+?)\}/ + export const ifStartMarkerRegex = /{#if\s+([^}]+?)\s*}/; export const elseMarker = '{:else}' export const closingIfMarker = '{/if}' diff --git a/scripts/odf/templating/prepareTemplateDOMTree.js b/scripts/odf/templating/prepareTemplateDOMTree.js index 50fae71..da3af78 100644 --- a/scripts/odf/templating/prepareTemplateDOMTree.js +++ b/scripts/odf/templating/prepareTemplateDOMTree.js @@ -1,5 +1,5 @@ import {traverse, Node} from "../../DOMUtils.js"; -import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex} from './markers.js' +import {closingIfMarker, eachClosingMarker, eachStartMarkerRegex, elseMarker, ifStartMarkerRegex, variableRegex} from './markers.js' /** * @@ -183,8 +183,6 @@ function consolidateMarkers(document){ containerTextNodesInTreeOrder.push(/** @type {Text} */(node)) } }) - - console.log('containerTextNodesInTreeOrder', containerTextNodesInTreeOrder.map(n => n.textContent)) } refreshContainerTextNodes() @@ -200,18 +198,19 @@ function consolidateMarkers(document){ ...findAllMatches(fullText, elseMarker), ...findAllMatches(fullText, closingIfMarker), ...findAllMatches(fullText, eachStartMarkerRegex), - ...findAllMatches(fullText, eachClosingMarker) + ...findAllMatches(fullText, eachClosingMarker), + ...findAllMatches(fullText, variableRegex) ]; - if(positionedMarkers.length >= 1) - console.log('positionedMarkers', positionedMarkers) + /*if(positionedMarkers.length >= 1) + console.log('positionedMarkers', positionedMarkers)*/ while(consolidatedMarkers.length < positionedMarkers.length) { refreshContainerTextNodes() // For each marker, check if it's contained within a single text node for(const positionedMarker of positionedMarkers.slice(consolidatedMarkers.length)) { - console.log('positionedMarker', positionedMarker) + //console.log('positionedMarker', positionedMarker) let currentPos = 0; let startNode; @@ -222,8 +221,6 @@ function consolidateMarkers(document){ const nodeStart = currentPos; const nodeEnd = nodeStart + textNode.textContent.length; - console.log('nodeStart, nodeEnd', nodeStart, nodeEnd) - // If start of marker is in this node if(!startNode && positionedMarker.index >= nodeStart && positionedMarker.index < nodeEnd) { startNode = textNode; @@ -239,8 +236,6 @@ function consolidateMarkers(document){ currentPos = nodeEnd; } - console.log('startNode, endNode', startNode?.textContent, endNode?.textContent) - if(!startNode){ throw new Error(`Could not find startNode for marker '${positionedMarker.marker}'`) } @@ -251,8 +246,6 @@ function consolidateMarkers(document){ // Check if marker spans multiple nodes if(startNode !== endNode) { - const commonAncestor = findCommonAncestor(startNode, endNode); - // Calculate relative positions within the nodes let startNodeTextContent = startNode.textContent || ''; let endNodeTextContent = endNode.textContent || ''; diff --git a/tests/fill-odt-template/formatting.js b/tests/fill-odt-template/formatting.js index cf05508..fda17fc 100644 --- a/tests/fill-odt-template/formatting.js +++ b/tests/fill-odt-template/formatting.js @@ -86,7 +86,7 @@ Les nombres : 3 5 8 13  !! }); -// + test('template filling - {/each} and text after partially formatted', async t => { const templatePath = join(import.meta.dirname, '../fixtures/formatting-liste-nombres-each-end-and-after-formatted.odt') const templateContent = `Liste de nombres @@ -112,3 +112,30 @@ Les nombres : 5 8 13 21  !! `) }); + + + + +test('template filling - partially formatted variable', async t => { + const templatePath = join(import.meta.dirname, '../fixtures/partially-formatted-variable.odt') + const templateContent = `Nombre + +Voici le nombre : {nombre} !!! +` + + const data = {nombre : 37} + + 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, `Nombre + +Voici le nombre : 37 !!! +`) + +}); \ No newline at end of file diff --git a/tests/fixtures/partially-formatted-variable.odt b/tests/fixtures/partially-formatted-variable.odt new file mode 100644 index 0000000000000000000000000000000000000000..cedf874ce8738de6acb03581a9d1c75f5ad901eb GIT binary patch literal 11685 zcmb_?1yq&Wx9)M%ESu!|S8qizm+M3wXTY-R<23Gp^7C=iodOM(#o%~N=_xAr0qI*r) z%F@up$lm4;7+Yor6AN7&VBX#4-r!-vX#j0-$G{2%M+zEl4Z#Cy%w&eh-v}A{4?MQQ!v1uW{bxS4hH53kn7A=~*+~si#a`{@|&gyP~!r79z2=Y5w ziC6*O9)VLUc>2v+duN?(%HoDV@#P^=*Rz+4%{LhH{hn?Y{x!5iuY+oEq&`E(lIC{= zuDCqz2R6yC=|p@CMUU?L`UgPWPe)XGUzN_B4QqZ4M!t0AWbH9g;s zd0SgqFn_gGRQ{2$2ZtfsMyhZ~gV-9raQo#QyvSK|I1#P3t4==aDuW!Met%#jGOlis zEza)Zes8v9eThj_1tn0_7iM}G{B>0=Ph1veV{kYs>Rnq{jMAoYSeQ|46s=z15$o$A z(@&%c^*tKKeR{AX*Qbi?52}8R%;#+v&o@Lqp}jSq z9YhAtE4j#oNgJ0Zzwx2OOPN zi682tu@)P$@3-!#1r65D$~kn*^G6_TLmlOqh z2xU%jvo}XE?d>o(Pw;t<>oJ02?s{NtzPQ6bN43g2{tG#gp!rOFu;EZ&_^ z(W|gIqLSN~@wD_4Z;;5^DfRLeQDXF1%RgMC_>}`SB#zu`sV`VTP8R;jkHcJu-3jow zH|0(yz9gA4XSLS`#HEBOxy{Y3$r|fHaEvfKUgOVx$ zy9KPLIX?(2o)XwmB(u&Z#wT7&Xk|lx#!_h7tHkO;uQuEAK}QKb!Io-j0FME78KzQJ zC@TY6uBv01E%eT8v^!khyujp@ITt+|)%c*5uv;ATTScO)2;C52)6Crbq)Y`EUou%c z174m-k!xYKXV{4B(tGQxEJ1$!ORm?*9Uk4giW?|V-o%kyLT}L(RSTqBHW9-(dCoty zNtCE>Uwt`O#b5J!6CDo+a}8}j;_i1kgf_JCCEX+gp%KO-s%}x)d)dvigYraD9>k3e zswo++rOu*d;a@^Rz5#3Afc2+Mq>KD}UA;J?#2MAdd9wPlcA{pE2%ZUP*9$$1rk$0H z6MEdb_ayz6zMV_(Od)G01C1|T@m9VFS&7fyrdssdJ5SKTrmhiXrnvdao9}z>09oY) zyK=D%M1A|nZPBd5=(W%3VxY@0e$C~p55hRCDjqZ2@5<{@2+y zsFciQ^@(sq3l?Dl-MgW{1d}I)HI(8UeF^vuuVQh)o?lYQOu-d`7eY|SuQZXsXv-GB zaFAq)kDD|W{HBkj#|QUZ?X5@b*EU;3N_k!$xSAl4`$Hg@au{u{l zuny%C=anDbu6$a+R_Kmi6ebQ+Tq<5?mA5jZ6lDpyW_VM+Z?$!=v!M6i7a~^PeBxub zK-Jq&_TkEiBCy8Xm#u$}WxN@0s>G4%C(S&p+E-c@Q_{JEWA>bVVrN{HPhZO~)c(@6 zFu80(SHI|8=s3&7+bLC*ha$V&=7qZ|`ez~b&)6ph3d&qMXFh~hIkPD@Q)wk`OJYIf zHg-O_;l)TV;SM4JWzRz|P1oQ*a?x*wAY8ik>jlE%>2()Yt z$G$s;^-3H9n?~;@6_e0cM0gu$3i32nN)&vFi(48`@;J|;hhzVI{#d7<+wju_BF1Lx zSBZF=vrg^m7pXDMS9b52@W59R+3&a=0ax21^IzPFdBR+EV0TlQ+nehZKf9yX$V1f0 z{mhlLpCEs?Is1m6f>Gm^UJJF@wjxi>u>08MC5Lg9Dqlb6n4Nu<;4^F$cd<(KWh!)r z>ky6>cF~pkp*SJhWR85pMqFn4NSG9T-o(_YtydB_+~_GldvZF?E|;WKJgp5ss09M^ zchUJFW<-&_{!bztUxdQuqwTs!W<7B)H)Q`r7RO{XEs(*oFgjFw63 z;b%!t?h4;vB??<_^*mZ~hmzG{f#Y~RF1vCl?}=F`jhPz(S8%YX%_#jCILC)vAd#}M z{Y9_=jE~Kwhz0VyGYe#QmU^oytVCln%_Td|^FK}>5fB_cPhO)QLG^K^j zPZgHoI01bD92TjpkeR=eGPYVQ##C*Z?+XXi^b4U|5G_??boV~8S)Kq$)>9gn-ZR~QO?_xjNakNMlrIW~fAh*-N z;|$rnqaT9ctdvwbh?oluW*A*XY*ro02?5m>Vn#Lcm@99dtEuU14H7qt8BxFfZoBmw zTUNmj-5gX3taKYU-kW&osZ3Vi&>$>3BgBTsNRal5kSMu3VS`gg2#*$?&zL;6N*zS~ zwixd4nNlDgi1b9T?>+n$=Ezh!n?m7xY0Ibp@(JlK=uM?AzxMLf^w*wqqFu$t<)EH?rcP~`YbrGm|J}CssIZc*vUPnrA{|Xl+8=?d?}Lu4`YN1pnZleGx;JGG zJ18`LHkW{*0B%(|M+&(AHQR2BXq6?Cu-> zePe8?tQT{3eEk^dWnr;mm(XP9)EZ5`7zbJ-nOr9=Fp6UJO6YMNza?UUR(t^)&!l%= zv+)67TthtLoY=QPAVN>b=L32%*2VL(^QnSly6`$k3$bJ@={E!ngeCg#@mlS05A@A73>fXcFc( z(IQF5K@llnd+ci@A_-J9f7vilj_b^-fR{?4u0MmVrW7H%!h;bmd;P!s}OvZ3{*Q7*(-5an#uX?)53BTW$G^#~cO}?jO zP|MpFc|4W-n8g!UUL?C>dWQvHmcLIoXUqg~8;K#RK9g2Mm_?X~qUpt3@0b3?GmXLrh=ov?z+xRQ|&j2>--*`KtjnjlA z591R$HV2>eS?kaY!q)GdbF8Slqi+4$ce(AgDOPf(J|4q3pG6_sK0PP*qynJRIz$W| zXBL1=0`&x~zwGdB&yj5@CH;yPqpHl4-M4aVJUz+WvN9BBrh<#LcBW?hNFG%?k7s4Y zydO>X2Is<23hAsTYh*!qcaYbeQL=X=**Y}?W9c^<%|fvIH)&kCZ>>H69TWrBZw;4T zP)=@Zm&bHO#cA{;8h!9^DQ`!kAbCO3>WVRnJ<1s-A^pib7^MClE=UOELUtxsEv|v6 zFF6um@WKl%OAShSW{=v}#^Wdrd+)U9xGUMbndI2^sJ5Uv_Ncir+C8wEXbXuy5-%@H z1y6&&pttv%qTTyd%HR=rPiJKpP9p8{(}>Q`c%5k#8#QYv0WiwU{`i6T6QzSBQjD*6 z5>%cS6yzJe(8pPJ+Fl;8tZrUdTDXL7QgmZk4traKT!&LR3+tiqELXO$?vafB_A1%T zJmc{5io&u&o?_TW3^DzVAPcMzBEHW&CX>*wV}s762*P`N!1{Ba=bkD6dZ8N|M3#n8 zHSQigEQ=?b)KJU!+u6atZf6gt0b8J*or$HU-f}v$mZxr97 za|xya^phH&G(73Ib}%$ER9;(5IhgjvrbkfQOQZlY%#U7_xEeC>H@(=IXHlgH1sCEs zy((;cL=dmK(*s=Bo#N&!aI3%CZ4K#S_EtAfr-j-_#diu1uXX%h?@-mfRo0HhTwo@~ zxoxWcV#$<0KOW(>}<)t&*oEEQX zh#J2{-!e>f_tT>j;^_0i?YVkDYOWF(q9&#VO0=mK9t%$0Xq80Bl8D4G5r>`sbn zrTgh=YS(5eK1{zcinCP)>BD5fQn)0VGOFN_3+XcV}d);BVj3|C)%%2UXLmYY+mRMx(M|C?6)S z!BH5`Rm;L;p23gVyDxo5{B+xEjHywevAA#m1#>~rsODr|X(3D{W~VVa)BJdS^*DQO z$F<9UlR|ub+Y%{y^<*_1n8(fa=J5OrdNWsOULz|P;ry?lT5r@T) z*M1VF1rwF8BO!zNrRj=hq!2Vs!4(Q`c>DF9LKWHOfI)kL3rk(UzL z44P7ifKSB$4rrh;O~o+9L34hxOQ4Qw3krO`eJVSZ6H^v=DE#b2rjq&v2lqi(EUIGR-VQ1Yo>L(r)N2m4V$&*5>}tFE z!sVCQtwn_EstRdrN|+mWH(PO{FK_l|@J!xvmwRMDhengL#J6=sir~k<2NWhdvt-C# zDO_z6#F!zXKQ{C+U!x=Kk4b2NEzI|SN84|n>lwvQ#Pkv_P(Fxet4Dc)(l3>W)aICr zxc`>R{|!Bc^Hr>1W*WA_AYmqHx=mk1@$j5E>%Z*bbI5$6cES-+&Q3n$@lk{kv#0Pi1U}RJypogil~6H554<8{zOyj< zN~6q&6wcP4!y~`VT@CcKEB7fG?EF#OvEUHrYvU*i2>S973 z6Z#1LNNXY3#(xkyOg$L zd5{km@9^v^VgiXAWB5sF??;C1FeK&CmqepWPl73dUZpqhPC>4SQ0Jb#2zck;&f{^| za#~$XC5c8lcbbMhZPei*-RctBjUSdpA#!`O{_(}@%xs-&A z!u6z$!D8|$nd-``ViI+@{bRVt$=Da4OOd_9MgZKd;sdLQe`B^a?`%39j_J8P%|^W9)} zfkJ4mFp9y-<`mT8XEW?z=_3MEjcFuvv%!V+1vg9+&S1as+PKhCgN?DF5^)l^x%4Ld zAp?4yAbw8xttf}D_%0-pq8;xCbm9uMw7M>DU@t%JCkTngue8d_kdI=lB!}cS>)
J_w6a{2e9r~Ey>h(yCK`t$5Fi!5W_y?2vJI=n$A6liLkY9Umae_ zsLtBZHS-7JVemNZ@j428Tlekrr-l`3e6(j+opLl|L`Di>%@jbR?7>ns19?6RdQ*Dt z6>^6x9GNp!Gl{yNYL44OKt!0FloWM?K>{6Ls;C9KcMqLCt@{@r@$P#=GZi z8%1w?f{Suu3(Qi2-qyH_IG+7+OuTV+b(??#0Q@-qIwt-V??ljQJc_#a8$3J@@jE4B zdkZ~FT@!O#2D`shdXS}2puDX36GYsHP}Y;z5+ZK^04P%c02%;)f5HGHdQE`tUvA~4 zl|%uW_jhC%fB_4iDOz z4Bn0s!GRgkiTSBLDW(%8o-;X`3oDu%C%zlgOJ@QSH%bXfB{fMwEln-;cR+1DprNj| zzOki|xxI3cR}FCJQ79#*fHocV^3P-*Xj@FQjQc#H$P>hk&h!$0hQ;|>5)J#y+NYZ?r zWFeer^EOFOHCbOg)k!MVQ7YZ-ZK}Cunvq7DsYaHARhpVznzD12mQ{|4TaJ!9fh`0}yIKXvl5}C}<7IY>O=DiZAU5ukMY{>dnm=C@bqrjUH%87-}v4 zGF13wBx|fIbF4deVxVYhxURLgu6L$}_JQf%k(u%S)~T`X$;pY{ z$@Q_>m9~|c!HwDZ)sBhH>6z`>FKf#q+bbjc-)2^J7WP&q*H5MokJl!FF-yZ1ehb4|2Hy^ndo3cU%zXN zS-4T`Ye!h$D;HkJi(3zm##h&?NA8Qe;KlT>kX%xjTm>XH(=@SA^*@v`p$8=c)AU}! zt&)FGa(#bN#ONOWVcX#V-=rkZM=m({%}d1ziDjfrP^HWr;CZSNoSulOtsc4Ubz z%9P}W!<=a>fcaNuJCIPzbb3j?rSePfKp8b&7K&(1jq@CEHmoFUk`jWq!WZ*v4R@ar z;T=T=^mHt`ZuJLGUTEI#MVFlv2Lc$h|HvxDK7M8{6i4v^J5>T1C_! zBFVCPQ7J4wAT-t#=+bzh6Xc;_JhHrDPh1>-j?QTpQF&M(aV=;5X zx!J(Ub{q#8+KC@xMciK5uJfPFN)BERJ7UtgpxD2A+ztD>ys{C}T1zVv_+59SkZ`QB zz?N@Jk@=l8S%%SjTG~0;N0}!KTx0I3gNd;oU2d6~r(RBmOT&)*c5aZAPM~PuRZ-4{ zp3Rl4yUCID9{YF)}_)nUp$Gkg?oZ~UTH<_ZakSRROd!dkU9Jnr);xjWSwq% zr}&n_mn|2yVen~&cvvBRT}f~6a0ZQd$bu*LaaD$0ozd&%s`B#Vm0>b*Hrl! zZ(I`F4#hkdGkyn6qY98_f82*9cfXK+UVAPXxhg~9N%o(~*sHT6ljxp?Uff=%a}_lW zO-`Kgr#Ox7`d?ti7-}@^WUM=nHL0H*bPrC=p%?6C(0xvd&&?6l5En7hm_2aQ=qffh z>zdKr=iu0!1Ug!2Vtr%)EF4P|YBX?Zn}?sDpYQJJ%9vIW`5?T+9GoXYq zEc(|wetTDMco4!>p*#mp&n^ZUr^~_thr~}1#%qR>Rp!sZI6g)y1M%$Hy8V@~EctkP z`t~k{BgZO>JgblP^}9+;>ks^nIOaI*=i2d9JbW`*&J;~)7* zutM3YMo0E6i%kjD=ee`jGxs9Qr%#=$PP%x-TPon%`A9w&~+}G%S}{6e!zUeIGxsB*rZX zYcf%BoE{g?t~&E?tkO$jaD|lJ2$mekctX?`SfZ73zzHRNuxv=p>OaCxA9EP4P5 zPpIK3_~LOTk0!Tb;up9|r7{&T5LVs-FSA;2v8&|Rhv59PRt`Md2g)4bkBbVm(a)ul zGv7k_ycidZD2thZVyl)VkdN}*T$iYSi}dK*9<>Fn=1Z-`-q#YdBB4RfSBT!hkHUqe za7?N?ao2=&U+i;q;0tDWF^6A!u%|{cWhovhF({wz*l!z z51z!~RKae#dru$zo%gS9_Qy4P5lbzr`H`~u*Ao8A?(fm!2PgUu8M%M`58vDe*#Bwy_jt`i zH2H@-MfoYV{7=Kbd-NZ|IX|T5KJ;^+qx?s3=bu)8zxV&#(53s&`0u{|zbt>}7x+=% v;r-10&P(tY%3lNZclLPTHQCQPde084{!emcH5*R literal 0 HcmV?d00001