Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
b3fce4244d | |||
bd443067b6 | |||
a9b6f7f984 | |||
10c39b02a0 | |||
7f4392b10e | |||
7e19cf4e2c | |||
c5fb20e96a | |||
a8c2257f20 | |||
b63b4d1352 | |||
6a3d44ccd0 | |||
c22e6ff41f | |||
068c64d714 | |||
2c7a4f5d97 | |||
0d7d251e76 | |||
0d8c447ff6 |
27
go.mod
27
go.mod
@@ -9,10 +9,31 @@ require (
|
|||||||
github.com/yuin/gopher-lua v1.1.1
|
github.com/yuin/gopher-lua v1.1.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
|
github.com/ProtonMail/go-crypto v1.1.5 // indirect
|
||||||
|
github.com/cloudflare/circl v1.6.0 // indirect
|
||||||
|
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||||
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
|
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||||
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
|
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||||
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||||
|
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||||
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
|
golang.org/x/crypto v0.35.0 // indirect
|
||||||
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PaesslerAG/gval v1.0.0 // indirect
|
github.com/PaesslerAG/gval v1.0.0 // indirect
|
||||||
github.com/antchfx/xpath v1.3.3 // indirect
|
github.com/antchfx/xpath v1.3.3 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/go-git/go-git/v5 v5.14.0
|
||||||
golang.org/x/net v0.33.0 // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/net v0.35.0 // indirect
|
||||||
|
golang.org/x/text v0.22.0 // indirect
|
||||||
)
|
)
|
||||||
|
101
go.sum
101
go.sum
@@ -1,26 +1,99 @@
|
|||||||
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
|
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8=
|
github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8=
|
||||||
github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I=
|
github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I=
|
||||||
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
|
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
|
||||||
github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk=
|
github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk=
|
||||||
github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY=
|
github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY=
|
||||||
|
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
|
||||||
|
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||||
github.com/antchfx/xmlquery v1.4.4 h1:mxMEkdYP3pjKSftxss4nUHfjBhnMk4imGoR96FRY2dg=
|
github.com/antchfx/xmlquery v1.4.4 h1:mxMEkdYP3pjKSftxss4nUHfjBhnMk4imGoR96FRY2dg=
|
||||||
github.com/antchfx/xmlquery v1.4.4/go.mod h1:AEPEEPYE9GnA2mj5Ur2L5Q5/2PycJ0N9Fusrx9b12fc=
|
github.com/antchfx/xmlquery v1.4.4/go.mod h1:AEPEEPYE9GnA2mj5Ur2L5Q5/2PycJ0N9Fusrx9b12fc=
|
||||||
github.com/antchfx/xpath v1.3.3 h1:tmuPQa1Uye0Ym1Zn65vxPgfltWb/Lxu2jeqIGteJSRs=
|
github.com/antchfx/xpath v1.3.3 h1:tmuPQa1Uye0Ym1Zn65vxPgfltWb/Lxu2jeqIGteJSRs=
|
||||||
github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||||
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
|
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||||
|
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
|
||||||
|
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||||
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
|
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||||
|
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||||
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
|
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||||
|
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||||
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||||
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||||
|
github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60=
|
||||||
|
github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
|
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||||
|
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||||
|
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||||
|
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||||
|
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||||
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||||
|
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||||
|
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
|
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
|
||||||
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
|
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||||
|
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||||
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
@@ -28,14 +101,16 @@ golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
|||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
|
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||||
|
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -44,9 +119,13 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -54,6 +133,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@@ -63,16 +144,20 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
|||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
|
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||||
|
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
@@ -80,3 +165,13 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
|||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
115
main.go
115
main.go
@@ -5,9 +5,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/bmatcuk/doublestar/v4"
|
"github.com/bmatcuk/doublestar/v4"
|
||||||
|
"github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
|
|
||||||
"modify/processor"
|
"modify/processor"
|
||||||
)
|
)
|
||||||
@@ -23,8 +27,12 @@ var stats GlobalStats
|
|||||||
var logger *log.Logger
|
var logger *log.Logger
|
||||||
|
|
||||||
var (
|
var (
|
||||||
jsonFlag = flag.Bool("json", false, "Process JSON files")
|
jsonFlag = flag.Bool("json", false, "Process JSON files")
|
||||||
xmlFlag = flag.Bool("xml", false, "Process XML files")
|
xmlFlag = flag.Bool("xml", false, "Process XML files")
|
||||||
|
gitFlag = flag.Bool("git", false, "Use git to manage files")
|
||||||
|
resetFlag = flag.Bool("reset", false, "Reset files to their original state")
|
||||||
|
repo *git.Repository
|
||||||
|
worktree *git.Worktree
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -54,6 +62,10 @@ func main() {
|
|||||||
fmt.Fprintf(os.Stderr, " Process JSON files\n")
|
fmt.Fprintf(os.Stderr, " Process JSON files\n")
|
||||||
fmt.Fprintf(os.Stderr, " -xml\n")
|
fmt.Fprintf(os.Stderr, " -xml\n")
|
||||||
fmt.Fprintf(os.Stderr, " Process XML files\n")
|
fmt.Fprintf(os.Stderr, " Process XML files\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " -git\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " Use git to manage files\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " -reset\n")
|
||||||
|
fmt.Fprintf(os.Stderr, " Reset files to their original state\n")
|
||||||
fmt.Fprintf(os.Stderr, " -mode string\n")
|
fmt.Fprintf(os.Stderr, " -mode string\n")
|
||||||
fmt.Fprintf(os.Stderr, " Processing mode: regex, xml, json (default \"regex\")\n")
|
fmt.Fprintf(os.Stderr, " Processing mode: regex, xml, json (default \"regex\")\n")
|
||||||
fmt.Fprintf(os.Stderr, "\nExamples:\n")
|
fmt.Fprintf(os.Stderr, "\nExamples:\n")
|
||||||
@@ -75,6 +87,9 @@ func main() {
|
|||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
args := flag.Args()
|
args := flag.Args()
|
||||||
|
if *resetFlag {
|
||||||
|
*gitFlag = true
|
||||||
|
}
|
||||||
|
|
||||||
if len(args) < 3 {
|
if len(args) < 3 {
|
||||||
log.Printf("At least %d arguments are required", 3)
|
log.Printf("At least %d arguments are required", 3)
|
||||||
@@ -97,6 +112,14 @@ func main() {
|
|||||||
logger.Printf("Transformed Lua expression from %q to %q", originalLuaExpr, luaExpr)
|
logger.Printf("Transformed Lua expression from %q to %q", originalLuaExpr, luaExpr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *gitFlag {
|
||||||
|
err := setupGit()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error setting up git: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Expand file patterns with glob support
|
// Expand file patterns with glob support
|
||||||
files, err := expandFilePatterns(filePatterns)
|
files, err := expandFilePatterns(filePatterns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -109,6 +132,18 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *gitFlag {
|
||||||
|
err := cleanupGitFiles(files)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error cleaning up git files: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if *resetFlag {
|
||||||
|
log.Printf("Files reset to their original state, nothing more to do")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Create the processor based on mode
|
// Create the processor based on mode
|
||||||
var proc processor.Processor
|
var proc processor.Processor
|
||||||
switch {
|
switch {
|
||||||
@@ -158,6 +193,35 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupGit() error {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get current working directory: %w", err)
|
||||||
|
}
|
||||||
|
logger.Printf("Current working directory obtained: %s", cwd)
|
||||||
|
|
||||||
|
logger.Printf("Attempting to open git repository at %s", cwd)
|
||||||
|
repo, err = git.PlainOpen(cwd)
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("No existing git repository found at %s, attempting to initialize a new git repository.", cwd)
|
||||||
|
repo, err = git.PlainInit(cwd, false)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to initialize a new git repository at %s: %w", cwd, err)
|
||||||
|
}
|
||||||
|
logger.Printf("Successfully initialized a new git repository at %s", cwd)
|
||||||
|
} else {
|
||||||
|
logger.Printf("Successfully opened existing git repository at %s", cwd)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Printf("Attempting to obtain worktree for repository at %s", cwd)
|
||||||
|
worktree, err = repo.Worktree()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to obtain worktree for repository at %s: %w", cwd, err)
|
||||||
|
}
|
||||||
|
logger.Printf("Successfully obtained worktree for repository at %s", cwd)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func expandFilePatterns(patterns []string) ([]string, error) {
|
func expandFilePatterns(patterns []string) ([]string, error) {
|
||||||
var files []string
|
var files []string
|
||||||
filesMap := make(map[string]bool)
|
filesMap := make(map[string]bool)
|
||||||
@@ -176,3 +240,50 @@ func expandFilePatterns(patterns []string) ([]string, error) {
|
|||||||
}
|
}
|
||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cleanupGitFiles(files []string) error {
|
||||||
|
for _, file := range files {
|
||||||
|
logger.Printf("Checking file: %s", file)
|
||||||
|
status, err := worktree.Status()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error getting worktree status: %v\n", err)
|
||||||
|
return fmt.Errorf("error getting worktree status: %w", err)
|
||||||
|
}
|
||||||
|
if status.IsUntracked(file) {
|
||||||
|
logger.Printf("Detected untracked file: %s. Attempting to add it to the git index.", file)
|
||||||
|
_, err = worktree.Add(file)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error adding file to git: %v\n", err)
|
||||||
|
return fmt.Errorf("error adding file to git: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := filepath.Base(file)
|
||||||
|
logger.Printf("File %s added successfully. Now committing it with message: 'Track %s'", filename, filename)
|
||||||
|
_, err = worktree.Commit("Track "+filename, &git.CommitOptions{
|
||||||
|
Author: &object.Signature{
|
||||||
|
Name: "Big Chef",
|
||||||
|
Email: "bigchef@bigchef.com",
|
||||||
|
When: time.Now(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error committing file: %v\n", err)
|
||||||
|
return fmt.Errorf("error committing file: %w", err)
|
||||||
|
}
|
||||||
|
logger.Printf("Successfully committed file: %s with message: 'Track %s'", filename, filename)
|
||||||
|
} else {
|
||||||
|
logger.Printf("File %s is already tracked. Restoring it to the working tree.", file)
|
||||||
|
err := worktree.Restore(&git.RestoreOptions{
|
||||||
|
Files: []string{file},
|
||||||
|
Staged: true,
|
||||||
|
Worktree: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error restoring file: %v\n", err)
|
||||||
|
return fmt.Errorf("error restoring file: %w", err)
|
||||||
|
}
|
||||||
|
logger.Printf("File %s restored successfully.", file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package processor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -239,6 +240,8 @@ modified = false
|
|||||||
if err := L.DoString(helperScript); err != nil {
|
if err := L.DoString(helperScript); err != nil {
|
||||||
return fmt.Errorf("error loading helper functions: %v", err)
|
return fmt.Errorf("error loading helper functions: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
L.SetGlobal("print", L.NewFunction(printToGo))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,6 +298,20 @@ func BuildLuaScript(luaExpr string) string {
|
|||||||
return fullScript
|
return fullScript
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printToGo(L *lua.LState) int {
|
||||||
|
// Get the number of arguments passed to the Lua print function
|
||||||
|
n := L.GetTop()
|
||||||
|
// Create a slice to hold the arguments
|
||||||
|
args := make([]interface{}, n)
|
||||||
|
for i := 1; i <= n; i++ {
|
||||||
|
args[i-1] = L.Get(i) // Get the argument from Lua stack
|
||||||
|
}
|
||||||
|
// Print the arguments to Go's stdout
|
||||||
|
log.Print("Lua: ")
|
||||||
|
log.Println(args...)
|
||||||
|
return 0 // No return values
|
||||||
|
}
|
||||||
|
|
||||||
// Max returns the maximum of two integers
|
// Max returns the maximum of two integers
|
||||||
func Max(a, b int) int {
|
func Max(a, b int) int {
|
||||||
if a > b {
|
if a > b {
|
||||||
|
@@ -2,6 +2,7 @@ package processor
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -65,27 +66,60 @@ func (p *RegexProcessor) FromLua(L *lua.LState) (interface{}, error) {
|
|||||||
return modifications, nil
|
return modifications, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NamedCapture struct {
|
||||||
|
Name string
|
||||||
|
Value string
|
||||||
|
Range [2]int
|
||||||
|
}
|
||||||
|
|
||||||
// ProcessContent applies regex replacement with Lua processing
|
// ProcessContent applies regex replacement with Lua processing
|
||||||
func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr string) (string, int, int, error) {
|
func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr string) (string, int, int, error) {
|
||||||
// Handle special pattern modifications
|
// Handle special pattern modifications
|
||||||
if !strings.HasPrefix(pattern, "(?s)") {
|
if !strings.HasPrefix(pattern, "(?s)") {
|
||||||
pattern = "(?s)" + pattern
|
pattern = "(?s)" + pattern
|
||||||
|
log.Printf("Pattern modified to include (?s): %s", pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The order of these replaces is important
|
||||||
|
// This one handles !num-s inside of named capture groups
|
||||||
|
// If it were not here our !num in a named capture group would
|
||||||
|
// Expand to another capture group in the capture group
|
||||||
|
// We really only want one (our named) capture group
|
||||||
|
namedGroupNum := regexp.MustCompile(`(?:(\?<[^>]+>)(!num))`)
|
||||||
|
pattern = namedGroupNum.ReplaceAllStringFunc(pattern, func(match string) string {
|
||||||
|
parts := namedGroupNum.FindStringSubmatch(match)
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
replacement := `-?\d*\.?\d+`
|
||||||
|
return parts[1] + replacement
|
||||||
|
})
|
||||||
|
pattern = strings.ReplaceAll(pattern, "!num", `"?(-?\d*\.?\d+)"?`)
|
||||||
|
pattern = strings.ReplaceAll(pattern, "!any", `.*?`)
|
||||||
|
repPattern := regexp.MustCompile(`!rep\(([^,]+),\s*(\d+)\)`)
|
||||||
|
// !rep(pattern, count) repeats the pattern n times
|
||||||
|
// Inserting !any between each repetition
|
||||||
|
pattern = repPattern.ReplaceAllStringFunc(pattern, func(match string) string {
|
||||||
|
parts := repPattern.FindStringSubmatch(match)
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
repeatedPattern := parts[1]
|
||||||
|
count := parts[2]
|
||||||
|
repetitions, _ := strconv.Atoi(count)
|
||||||
|
return strings.Repeat(repeatedPattern+".*?", repetitions-1) + repeatedPattern
|
||||||
|
})
|
||||||
|
|
||||||
compiledPattern, err := regexp.Compile(pattern)
|
compiledPattern, err := regexp.Compile(pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("Error compiling pattern: %v", err)
|
||||||
return "", 0, 0, fmt.Errorf("error compiling pattern: %v", err)
|
return "", 0, 0, fmt.Errorf("error compiling pattern: %v", err)
|
||||||
}
|
}
|
||||||
|
log.Printf("Compiled pattern successfully: %s", pattern)
|
||||||
|
|
||||||
previous := luaExpr
|
previous := luaExpr
|
||||||
luaExpr = BuildLuaScript(luaExpr)
|
luaExpr = BuildLuaScript(luaExpr)
|
||||||
fmt.Printf("Changing Lua expression from: %s to: %s\n", previous, luaExpr)
|
log.Printf("Changing Lua expression from: %s to: %s", previous, luaExpr)
|
||||||
|
|
||||||
L, err := NewLuaState()
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, 0, fmt.Errorf("error creating Lua state: %v", err)
|
|
||||||
}
|
|
||||||
defer L.Close()
|
|
||||||
|
|
||||||
// Initialize Lua environment
|
// Initialize Lua environment
|
||||||
modificationCount := 0
|
modificationCount := 0
|
||||||
@@ -93,12 +127,27 @@ func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr
|
|||||||
// Process all regex matches
|
// Process all regex matches
|
||||||
result := content
|
result := content
|
||||||
indices := compiledPattern.FindAllStringSubmatchIndex(content, -1)
|
indices := compiledPattern.FindAllStringSubmatchIndex(content, -1)
|
||||||
|
log.Printf("Found %d matches in the content", len(indices))
|
||||||
|
|
||||||
// We walk backwards because we're replacing something with something else that might be longer
|
// We walk backwards because we're replacing something with something else that might be longer
|
||||||
// And in the case it is longer than the original all indicces past that change will be fucked up
|
// And in the case it is longer than the original all indicces past that change will be fucked up
|
||||||
// By going backwards we fuck up all the indices to the end of the file that we don't care about
|
// By going backwards we fuck up all the indices to the end of the file that we don't care about
|
||||||
// Because there either aren't any (last match) or they're already modified (subsequent matches)
|
// Because there either aren't any (last match) or they're already modified (subsequent matches)
|
||||||
for i := len(indices) - 1; i >= 0; i-- {
|
for i := len(indices) - 1; i >= 0; i-- {
|
||||||
|
L, err := NewLuaState()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error creating Lua state: %v", err)
|
||||||
|
return "", 0, 0, fmt.Errorf("error creating Lua state: %v", err)
|
||||||
|
}
|
||||||
|
// Hmm... Maybe we don't want to defer this..
|
||||||
|
// Maybe we want to close them every iteration
|
||||||
|
// We'll leave it as is for now
|
||||||
|
defer L.Close()
|
||||||
|
log.Printf("Lua state created successfully")
|
||||||
|
|
||||||
matchIndices := indices[i]
|
matchIndices := indices[i]
|
||||||
|
log.Printf("Processing match indices: %v", matchIndices)
|
||||||
|
|
||||||
// Why we're doing this whole song and dance of indices is to properly handle empty matches
|
// Why we're doing this whole song and dance of indices is to properly handle empty matches
|
||||||
// Plus it's a little cleaner to surgically replace our matches
|
// Plus it's a little cleaner to surgically replace our matches
|
||||||
// If we were to use string.replace and encountered an empty match there'd be nothing to replace
|
// If we were to use string.replace and encountered an empty match there'd be nothing to replace
|
||||||
@@ -107,60 +156,127 @@ func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr
|
|||||||
// As if concatenating in the middle of the array
|
// As if concatenating in the middle of the array
|
||||||
// Plus it supports lookarounds
|
// Plus it supports lookarounds
|
||||||
match := content[matchIndices[0]:matchIndices[1]]
|
match := content[matchIndices[0]:matchIndices[1]]
|
||||||
|
log.Printf("Matched content: %s", match)
|
||||||
|
|
||||||
groups := matchIndices[2:]
|
groups := matchIndices[2:]
|
||||||
if len(groups) <= 0 {
|
if len(groups) <= 0 {
|
||||||
fmt.Println("No capture groups for lua to chew on")
|
log.Println("No capture groups for lua to chew on")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(groups)%2 == 1 {
|
if len(groups)%2 == 1 {
|
||||||
fmt.Println("Odd number of indices of groups, what the fuck?")
|
log.Println("Odd number of indices of groups, what the fuck?")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
for _, index := range groups {
|
||||||
|
if index == -1 {
|
||||||
|
// return "", 0, 0, fmt.Errorf("negative indices encountered: %v. This indicates that there was an issue with the match indices, possibly due to an empty match or an unexpected pattern. Please check the regex pattern and input content.", matchIndices)
|
||||||
|
log.Printf("Negative indices encountered: %v. This indicates that there was an issue with the match indices, possibly due to an empty match or an unexpected pattern. This is not an error but it's possibly not what you want.", matchIndices)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
captures := make([]string, 0, len(groups)/2)
|
captures := make([]string, 0, len(groups)/2)
|
||||||
for j := 0; j < len(groups); j += 2 {
|
for j := 0; j < len(groups); j += 2 {
|
||||||
|
if groups[j] == -1 || groups[j+1] == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
captures = append(captures, content[groups[j]:groups[j+1]])
|
captures = append(captures, content[groups[j]:groups[j+1]])
|
||||||
}
|
}
|
||||||
|
log.Printf("Captured groups: %v", captures)
|
||||||
|
|
||||||
|
// We have to use array to preserve order
|
||||||
|
// Very important for the reconstruction step
|
||||||
|
// Because we must overwrite the values in reverse order
|
||||||
|
// See comments a few dozen lines above for more details
|
||||||
|
namedCaptures := make([]NamedCapture, 0, len(groups)/2)
|
||||||
|
groupNames := compiledPattern.SubexpNames()[1:]
|
||||||
|
for i, name := range groupNames {
|
||||||
|
if name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if groups[i*2] == -1 || groups[i*2+1] == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
namedCaptures = append(namedCaptures, NamedCapture{
|
||||||
|
Name: name,
|
||||||
|
Value: captures[i],
|
||||||
|
Range: [2]int{groups[i*2], groups[i*2+1]},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Named captures: %v", namedCaptures)
|
||||||
|
|
||||||
if err := p.ToLua(L, captures); err != nil {
|
if err := p.ToLua(L, captures); err != nil {
|
||||||
fmt.Println("Error setting Lua variables:", err)
|
log.Printf("Error setting Lua variables: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
log.Println("Lua variables set successfully")
|
||||||
|
|
||||||
|
for _, capture := range namedCaptures {
|
||||||
|
if capture.Name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if val, err := strconv.ParseFloat(capture.Value, 64); err == nil {
|
||||||
|
L.SetGlobal(capture.Name, lua.LNumber(val))
|
||||||
|
} else {
|
||||||
|
L.SetGlobal(capture.Name, lua.LString(capture.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := L.DoString(luaExpr); err != nil {
|
if err := L.DoString(luaExpr); err != nil {
|
||||||
fmt.Printf("Error executing Lua code %s for group %s: %v", luaExpr, captures, err)
|
log.Printf("Error executing Lua code %s for group %s: %v", luaExpr, captures, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
log.Println("Lua code executed successfully")
|
||||||
|
|
||||||
// Get modifications from Lua
|
// Get modifications from Lua
|
||||||
modResult, err := p.FromLua(L)
|
modResult, err := p.FromLua(L)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error getting modifications:", err)
|
log.Printf("Error getting modifications: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply modifications to the matched text
|
// Apply modifications to the matched text
|
||||||
modsMap, ok := modResult.(map[int]string)
|
modsMap, ok := modResult.(map[int]string)
|
||||||
if !ok || len(modsMap) == 0 {
|
if !ok || len(modsMap) == 0 {
|
||||||
fmt.Println("No modifications to apply")
|
log.Println("No modifications to apply")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the modifications to the original match
|
replacement := ""
|
||||||
replacement := match
|
replacementVar := L.GetGlobal("replacement")
|
||||||
for i := len(modsMap) - 1; i >= 0; i-- {
|
if replacementVar.Type() != lua.LTNil {
|
||||||
newVal := modsMap[i]
|
replacement = replacementVar.String()
|
||||||
// Indices of the group are relative to content
|
|
||||||
// To relate them to match we have to subtract the match start index
|
|
||||||
groupStart := groups[i*2] - matchIndices[0]
|
|
||||||
groupEnd := groups[i*2+1] - matchIndices[0]
|
|
||||||
replacement = replacement[:groupStart] + newVal + replacement[groupEnd:]
|
|
||||||
}
|
}
|
||||||
|
if replacement == "" {
|
||||||
|
// Apply the modifications to the original match
|
||||||
|
replacement = match
|
||||||
|
for i := len(modsMap) - 1; i >= 0; i-- {
|
||||||
|
newVal := modsMap[i]
|
||||||
|
log.Printf("Applying modification: %s", newVal)
|
||||||
|
// Indices of the group are relative to content
|
||||||
|
// To relate them to match we have to subtract the match start index
|
||||||
|
groupStart := groups[i*2] - matchIndices[0]
|
||||||
|
groupEnd := groups[i*2+1] - matchIndices[0]
|
||||||
|
replacement = replacement[:groupStart] + newVal + replacement[groupEnd:]
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := len(namedCaptures) - 1; i >= 0; i-- {
|
||||||
|
capture := namedCaptures[i]
|
||||||
|
if capture.Name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
groupStart := capture.Range[0] - matchIndices[0]
|
||||||
|
groupEnd := capture.Range[1] - matchIndices[0]
|
||||||
|
luaValue := L.GetGlobal(capture.Name).String()
|
||||||
|
replacement = replacement[:groupStart] + luaValue + replacement[groupEnd:]
|
||||||
|
}
|
||||||
|
}
|
||||||
modificationCount++
|
modificationCount++
|
||||||
result = result[:matchIndices[0]] + replacement + result[matchIndices[1]:]
|
result = result[:matchIndices[0]] + replacement + result[matchIndices[1]:]
|
||||||
|
log.Printf("Modification count updated: %d", modificationCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("Process completed with %d modifications", modificationCount)
|
||||||
return result, modificationCount, len(indices), nil
|
return result, modificationCount, len(indices), nil
|
||||||
}
|
}
|
||||||
|
@@ -547,3 +547,793 @@ func TestEdgeCases(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNamedCaptureGroups(t *testing.T) {
|
||||||
|
content := `<config>
|
||||||
|
<item>
|
||||||
|
<value>100</value>
|
||||||
|
</item>
|
||||||
|
</config>`
|
||||||
|
|
||||||
|
expected := `<config>
|
||||||
|
<item>
|
||||||
|
<value>200</value>
|
||||||
|
</item>
|
||||||
|
</config>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(content, `(?s)<value>(?<amount>\d+)</value>`, "amount = amount * 2")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamedCaptureGroupsNum(t *testing.T) {
|
||||||
|
content := `<config>
|
||||||
|
<item>
|
||||||
|
<value>100</value>
|
||||||
|
</item>
|
||||||
|
</config>`
|
||||||
|
|
||||||
|
expected := `<config>
|
||||||
|
<item>
|
||||||
|
<value>200</value>
|
||||||
|
</item>
|
||||||
|
</config>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(content, `(?s)<value>(?<amount>!num)</value>`, "amount = amount * 2")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultipleNamedCaptureGroups(t *testing.T) {
|
||||||
|
content := `<product>
|
||||||
|
<name>Widget</name>
|
||||||
|
<price>15.99</price>
|
||||||
|
<quantity>10</quantity>
|
||||||
|
</product>`
|
||||||
|
|
||||||
|
expected := `<product>
|
||||||
|
<name>WIDGET</name>
|
||||||
|
<price>23.99</price>
|
||||||
|
<quantity>15</quantity>
|
||||||
|
</product>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`(?s)<name>(?<prodName>[^<]+)</name>.*?<price>(?<prodPrice>\d+\.\d+)</price>.*?<quantity>(?<prodQty>\d+)</quantity>`,
|
||||||
|
`prodName = string.upper(prodName)
|
||||||
|
prodPrice = round(prodPrice + 8, 2)
|
||||||
|
prodQty = prodQty + 5`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMixedIndexedAndNamedCaptures(t *testing.T) {
|
||||||
|
content := `<entry>
|
||||||
|
<id>12345</id>
|
||||||
|
<data>value</data>
|
||||||
|
</entry>`
|
||||||
|
|
||||||
|
expected := `<entry>
|
||||||
|
<id>24690</id>
|
||||||
|
<data>VALUE</data>
|
||||||
|
</entry>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`(?s)<id>(\d+)</id>.*?<data>(?<dataField>[^<]+)</data>`,
|
||||||
|
`v1 = v1 * 2
|
||||||
|
dataField = string.upper(dataField)`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComplexNestedNamedCaptures(t *testing.T) {
|
||||||
|
content := `<person>
|
||||||
|
<details>
|
||||||
|
<name>John Smith</name>
|
||||||
|
<age>32</age>
|
||||||
|
</details>
|
||||||
|
<contact>
|
||||||
|
<email>john@example.com</email>
|
||||||
|
</contact>
|
||||||
|
</person>`
|
||||||
|
|
||||||
|
expected := `<person>
|
||||||
|
<details>
|
||||||
|
<name>JOHN SMITH (32)</name>
|
||||||
|
<age>32</age>
|
||||||
|
</details>
|
||||||
|
<contact>
|
||||||
|
<email>john@example.com</email>
|
||||||
|
</contact>
|
||||||
|
</person>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`(?s)<details>.*?<name>(?<fullName>[^<]+)</name>.*?<age>(?<age>\d+)</age>`,
|
||||||
|
`fullName = string.upper(fullName) .. " (" .. age .. ")"`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamedCaptureWithVariableReadback(t *testing.T) {
|
||||||
|
content := `<stats>
|
||||||
|
<health>100</health>
|
||||||
|
<mana>200</mana>
|
||||||
|
</stats>`
|
||||||
|
|
||||||
|
expected := `<stats>
|
||||||
|
<health>150</health>
|
||||||
|
<mana>300</mana>
|
||||||
|
</stats>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`(?s)<health>(?<hp>\d+)</health>.*?<mana>(?<mp>\d+)</mana>`,
|
||||||
|
`hp = hp * 1.5
|
||||||
|
mp = mp * 1.5`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamedCaptureWithSpecialCharsInName(t *testing.T) {
|
||||||
|
content := `<data value="42" min="10" max="100" />`
|
||||||
|
|
||||||
|
expected := `<data value="84" min="10" max="100" />`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`<data value="(?<val_1>\d+)"`,
|
||||||
|
`val_1 = val_1 * 2`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyNamedCapture(t *testing.T) {
|
||||||
|
content := `<tag attr="" />`
|
||||||
|
|
||||||
|
expected := `<tag attr="default" />`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`attr="(?<value>.*?)"`,
|
||||||
|
`value = value == "" and "default" or value`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultipleNamedCapturesInSameLine(t *testing.T) {
|
||||||
|
content := `<rect x="10" y="20" width="100" height="50" />`
|
||||||
|
|
||||||
|
expected := `<rect x="20" y="40" width="200" height="100" />`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`x="(?<x>\d+)" y="(?<y>\d+)" width="(?<w>\d+)" height="(?<h>\d+)"`,
|
||||||
|
`x = x * 2
|
||||||
|
y = y * 2
|
||||||
|
w = w * 2
|
||||||
|
h = h * 2`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConditionalNamedCapture(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
<item status="active" count="5" />
|
||||||
|
<item status="inactive" count="10" />
|
||||||
|
`
|
||||||
|
|
||||||
|
expected := `
|
||||||
|
<item status="active" count="10" />
|
||||||
|
<item status="inactive" count="10" />
|
||||||
|
`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`<item status="(?<status>[^"]+)" count="(?<count>\d+)"`,
|
||||||
|
`count = status == "active" and count * 2 or count`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 2 {
|
||||||
|
t.Errorf("Expected 2 matches, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 2 {
|
||||||
|
t.Errorf("Expected 2 modifications, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLuaFunctionsOnNamedCaptures(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
<user name="john doe" role="user" />
|
||||||
|
<user name="jane smith" role="admin" />
|
||||||
|
`
|
||||||
|
|
||||||
|
expected := `
|
||||||
|
<user name="John Doe" role="user" />
|
||||||
|
<user name="JANE SMITH" role="admin" />
|
||||||
|
`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`<user name="(?<name>[^"]+)" role="(?<role>[^"]+)"`,
|
||||||
|
`-- Capitalize first letters for regular users
|
||||||
|
if role == "user" then
|
||||||
|
name = name:gsub("(%w)(%w*)", function(first, rest) return first:upper()..rest end):gsub(" (%w)(%w*)", " %1%2")
|
||||||
|
else
|
||||||
|
-- Uppercase for admins
|
||||||
|
name = string.upper(name)
|
||||||
|
end`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 2 {
|
||||||
|
t.Errorf("Expected 2 matches, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 2 {
|
||||||
|
t.Errorf("Expected 2 modifications, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For simpler tests, we can use this. More complex string modifications
|
||||||
|
// might need additional transformations before comparison
|
||||||
|
normalizedResult := normalizeWhitespace(result)
|
||||||
|
normalizedExpected := normalizeWhitespace(expected)
|
||||||
|
if normalizedResult != normalizedExpected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamedCaptureWithMath(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
<item price="19.99" quantity="3" />
|
||||||
|
`
|
||||||
|
|
||||||
|
expected := `
|
||||||
|
<item price="19.99" quantity="3" total="59.97" />
|
||||||
|
`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`<item price="(?<price>\d+\.\d+)" quantity="(?<qty>\d+)"!any$`,
|
||||||
|
`-- Calculate and add total
|
||||||
|
replacement = string.format('<item price="%s" quantity="%s" total="%.2f" />',
|
||||||
|
price, qty, price * qty)`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
result = normalizeWhitespace(result)
|
||||||
|
expected = normalizeWhitespace(expected)
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamedCaptureWithGlobals(t *testing.T) {
|
||||||
|
content := `<temp unit="C">25</temp>`
|
||||||
|
|
||||||
|
expected := `<temp unit="F">77</temp>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`<temp unit="(?<unit>[CF]?)">(?<value>\d+)</temp>`,
|
||||||
|
`if unit == "C" then
|
||||||
|
value = value * 9/5 + 32
|
||||||
|
unit = "F"
|
||||||
|
elseif unit == "F" then
|
||||||
|
value = (value - 32) * 5/9
|
||||||
|
unit = "C"
|
||||||
|
end`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMixedDynamicAndNamedCaptures(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
<color rgb="255,0,0" name="red" />
|
||||||
|
<color rgb="0,255,0" name="green" />
|
||||||
|
`
|
||||||
|
|
||||||
|
expected := `
|
||||||
|
<color rgb="255,0,0" name="RED" hex="#FF0000" />
|
||||||
|
<color rgb="0,255,0" name="GREEN" hex="#00FF00" />
|
||||||
|
`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`<color rgb="(?<r>\d+),(?<g>\d+),(?<b>\d+)" name="(?<colorName>[^"]+)" />`,
|
||||||
|
`-- Uppercase the name
|
||||||
|
colorName = string.upper(colorName)
|
||||||
|
|
||||||
|
-- Create hex color
|
||||||
|
local hex = string.format("#%02X%02X%02X", tonumber(r), tonumber(g), tonumber(b))
|
||||||
|
|
||||||
|
-- Replace the entire match
|
||||||
|
replacement = string.format('<color rgb="%s,%s,%s" name="%s" hex="%s" />',
|
||||||
|
r, g, b, colorName, hex)`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 2 {
|
||||||
|
t.Errorf("Expected 2 matches, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 2 {
|
||||||
|
t.Errorf("Expected 2 modifications, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
result = normalizeWhitespace(result)
|
||||||
|
expected = normalizeWhitespace(expected)
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamedCapturesWithMultipleReferences(t *testing.T) {
|
||||||
|
content := `<text>Hello world</text>`
|
||||||
|
|
||||||
|
expected := `<text format="uppercase" length="11">HELLO WORLD</text>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`<text>(?<content>[^<]+)</text>`,
|
||||||
|
`local uppercaseContent = string.upper(content)
|
||||||
|
local contentLength = string.len(content)
|
||||||
|
replacement = string.format('<text format="uppercase" length="%d">%s</text>',
|
||||||
|
contentLength, uppercaseContent)`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamedCaptureWithJsonData(t *testing.T) {
|
||||||
|
content := `<data>{"name":"John","age":30}</data>`
|
||||||
|
|
||||||
|
expected := `<data>{"name":"JOHN","age":30}</data>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`<data>(?<json>\{.*?\})</data>`,
|
||||||
|
`-- Parse JSON (simplified, assumes valid JSON)
|
||||||
|
local name = json:match('"name":"([^"]+)"')
|
||||||
|
local upperName = string.upper(name)
|
||||||
|
json = json:gsub('"name":"([^"]+)"', '"name":"' .. upperName .. '"')`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamedCaptureInXML(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
<product>
|
||||||
|
<sku>ABC-123</sku>
|
||||||
|
<price currency="USD">19.99</price>
|
||||||
|
<stock>25</stock>
|
||||||
|
</product>
|
||||||
|
`
|
||||||
|
|
||||||
|
expected := `
|
||||||
|
<product>
|
||||||
|
<sku>ABC-123</sku>
|
||||||
|
<price currency="USD">23.99</price>
|
||||||
|
<stock>20</stock>
|
||||||
|
</product>
|
||||||
|
`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`(?s)<price currency="(?<currency>[^"]+)">(?<price>\d+\.\d+)</price>.*?<stock>(?<stock>\d+)</stock>`,
|
||||||
|
`-- Add 20% to price if USD
|
||||||
|
if currency == "USD" then
|
||||||
|
price = round(price * 1.20, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Reduce stock by 5
|
||||||
|
stock = stock - 5`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComprehensiveNamedCaptures(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
<products>
|
||||||
|
<product sku="AB-123" status="in-stock">
|
||||||
|
<name>Widget A</name>
|
||||||
|
<price currency="USD">19.99</price>
|
||||||
|
<quantity>15</quantity>
|
||||||
|
</product>
|
||||||
|
<product sku="CD-456" status="out-of-stock">
|
||||||
|
<name>Widget B</name>
|
||||||
|
<price currency="EUR">29.99</price>
|
||||||
|
<quantity>0</quantity>
|
||||||
|
</product>
|
||||||
|
<product sku="EF-789" status="in-stock">
|
||||||
|
<name>Widget C</name>
|
||||||
|
<price currency="GBP">39.99</price>
|
||||||
|
<quantity>5</quantity>
|
||||||
|
</product>
|
||||||
|
</products>
|
||||||
|
`
|
||||||
|
|
||||||
|
expected := `
|
||||||
|
<products>
|
||||||
|
<product sku="AB-123" status="in-stock" discounted="true">
|
||||||
|
<name>WIDGET A</name>
|
||||||
|
<price currency="USD">15.99</price>
|
||||||
|
<quantity>15</quantity>
|
||||||
|
</product>
|
||||||
|
<product sku="CD-456" status="out-of-stock" discounted="false">
|
||||||
|
<name>Widget B</name>
|
||||||
|
<price currency="EUR">29.99</price>
|
||||||
|
<quantity>0</quantity>
|
||||||
|
</product>
|
||||||
|
<product sku="EF-789" status="in-stock" discounted="true">
|
||||||
|
<name>WIDGET C</name>
|
||||||
|
<price currency="GBP">39.99</price>
|
||||||
|
<quantity>5</quantity>
|
||||||
|
</product>
|
||||||
|
</products>
|
||||||
|
`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`(?s)<product sku="(?<sku>[^"]+)" status="(?<status>[^"]+)"[^>]*>\s*<name>(?<product_name>[^<]+)</name>\s*<price currency="(?<currency>[^"]+)">(?<price>\d+\.\d+)</price>\s*<quantity>(?<qty>\d+)</quantity>`,
|
||||||
|
`-- Only process in-stock items
|
||||||
|
if status == "in-stock" then
|
||||||
|
-- Transform name to uppercase
|
||||||
|
product_name = string.upper(product_name)
|
||||||
|
|
||||||
|
-- Apply discount based on currency
|
||||||
|
local discounted = true
|
||||||
|
if currency == "USD" then
|
||||||
|
price = round(price * 0.8, 2) -- 20% discount for USD
|
||||||
|
elseif currency == "GBP" then
|
||||||
|
price = round(price * 0.8, 2) -- 20% discount for GBP
|
||||||
|
price = price + 8 -- Add shipping cost for GBP
|
||||||
|
else
|
||||||
|
discounted = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add discounted attribute
|
||||||
|
replacement = string.format('<product sku="%s" status="%s" discounted="%s">\n\t\t\t<name>%s</name>\n\t\t\t<price currency="%s">%.2f</price>\n\t\t\t<quantity>%s</quantity>',
|
||||||
|
sku, status, tostring(discounted), product_name, currency, price, qty)
|
||||||
|
else
|
||||||
|
-- Add discounted attribute for out-of-stock items (always false)
|
||||||
|
replacement = string.format('<product sku="%s" status="%s" discounted="false">\n\t\t\t<name>%s</name>\n\t\t\t<price currency="%s">%s</price>\n\t\t\t<quantity>%s</quantity>',
|
||||||
|
sku, status, product_name, currency, price, qty)
|
||||||
|
end`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 3 {
|
||||||
|
t.Errorf("Expected 3 matches, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 3 {
|
||||||
|
t.Errorf("Expected 3 modifications, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize whitespace for comparison
|
||||||
|
normalizedResult := normalizeWhitespace(result)
|
||||||
|
normalizedExpected := normalizeWhitespace(expected)
|
||||||
|
|
||||||
|
if normalizedResult != normalizedExpected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVariousNamedCaptureFormats(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
<data>
|
||||||
|
<entry id="1" value="100" />
|
||||||
|
<entry id="2" value="200" status="active" />
|
||||||
|
<entry id="3" value="300" status="inactive" />
|
||||||
|
</data>
|
||||||
|
`
|
||||||
|
|
||||||
|
expected := `
|
||||||
|
<data>
|
||||||
|
<entry id="ID-1" value="200" />
|
||||||
|
<entry id="ID-2" value="400" status="ACTIVE" />
|
||||||
|
<entry id="ID-3" value="300" status="inactive" />
|
||||||
|
</data>
|
||||||
|
`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`<entry id="(?<id_num>\d+)" value="(?<val>\d+)"(?: status="(?<status>[^"]*)")? />`,
|
||||||
|
`-- Prefix the ID with "ID-"
|
||||||
|
id_num = "ID-" .. id_num
|
||||||
|
print(id_num)
|
||||||
|
print(val)
|
||||||
|
print(status)
|
||||||
|
|
||||||
|
-- Double the value except for inactive status
|
||||||
|
if not status or status ~= "inactive" then
|
||||||
|
val = val * 2
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert status to uppercase if present and active
|
||||||
|
if status and status == "active" then
|
||||||
|
status = string.upper(status)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Build the replacement based on whether status exists
|
||||||
|
if status then
|
||||||
|
replacement = string.format('<entry id="%s" value="%s" status="%s" />', id_num, val, status)
|
||||||
|
else
|
||||||
|
replacement = string.format('<entry id="%s" value="%s" />', id_num, val)
|
||||||
|
end`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 3 {
|
||||||
|
t.Errorf("Expected 3 matches, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 3 {
|
||||||
|
t.Errorf("Expected 3 modifications, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizedResult := normalizeWhitespace(result)
|
||||||
|
normalizedExpected := normalizeWhitespace(expected)
|
||||||
|
|
||||||
|
if normalizedResult != normalizedExpected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimpleNamedCapture(t *testing.T) {
|
||||||
|
content := `<product name="Widget" price="19.99"/>`
|
||||||
|
|
||||||
|
expected := `<product name="WIDGET" price="19.99"/>`
|
||||||
|
|
||||||
|
p := &RegexProcessor{}
|
||||||
|
result, mods, matches, err := p.ProcessContent(
|
||||||
|
content,
|
||||||
|
`name="(?<product_name>[^"]+)"`,
|
||||||
|
`product_name = string.upper(product_name)`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing content: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches != 1 {
|
||||||
|
t.Errorf("Expected 1 match, got %d", matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mods != 1 {
|
||||||
|
t.Errorf("Expected 1 modification, got %d", mods)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -17,6 +17,7 @@ echo "Tag: $TAG"
|
|||||||
|
|
||||||
echo "Building the thing..."
|
echo "Building the thing..."
|
||||||
go build -o chef.exe .
|
go build -o chef.exe .
|
||||||
|
go install .
|
||||||
|
|
||||||
echo "Creating a release..."
|
echo "Creating a release..."
|
||||||
TOKEN="$GITEA_API_KEY"
|
TOKEN="$GITEA_API_KEY"
|
||||||
|
Reference in New Issue
Block a user