13 Commits

Author SHA1 Message Date
a9b6f7f984 Implement printing from lua 2025-03-26 13:37:39 +01:00
10c39b02a0 Fix some regex tests 2025-03-26 13:13:53 +01:00
7f4392b10e Implement "replacement" variable that simply replaces the match 2025-03-26 13:00:52 +01:00
7e19cf4e2c Rework named captures to be array
To comply with the whole reverse replacing
2025-03-26 12:50:55 +01:00
c5fb20e96a Implement named capture groups 2025-03-26 12:28:28 +01:00
a8c2257f20 Add named capture group tests 2025-03-26 12:17:01 +01:00
b63b4d1352 Add some more shorthands for regex 2025-03-26 12:06:04 +01:00
6a3d44ccd0 Redo what claude removed 2025-03-26 11:42:00 +01:00
c22e6ff41f Code polish 2025-03-26 11:40:23 +01:00
068c64d714 Fix up file reseting 2025-03-26 11:10:43 +01:00
2c7a4f5d97 Add a lot more logs to regex
What the fuck is going on?
2025-03-26 03:30:08 +01:00
0d7d251e76 Implement git reset 2025-03-26 03:23:16 +01:00
0d8c447ff6 Add support for git ie. automatically resetting changes to ensure clean slate 2025-03-26 03:22:05 +01:00
7 changed files with 1134 additions and 30 deletions

27
go.mod
View File

@@ -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
View File

@@ -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=

111
main.go
View File

@@ -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"
) )
@@ -25,6 +29,10 @@ 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
}

View File

@@ -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 {

View File

@@ -2,6 +2,7 @@ package processor
import ( import (
"fmt" "fmt"
"log"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@@ -65,27 +66,46 @@ 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)
} }
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 +113,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,50 +142,104 @@ 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
} }
replacement := ""
replacementVar := L.GetGlobal("replacement")
if replacementVar.Type() != lua.LTNil {
replacement = replacementVar.String()
}
if replacement == "" {
// Apply the modifications to the original match // Apply the modifications to the original match
replacement := match replacement = match
for i := len(modsMap) - 1; i >= 0; i-- { for i := len(modsMap) - 1; i >= 0; i-- {
newVal := modsMap[i] newVal := modsMap[i]
log.Printf("Applying modification: %s", newVal)
// Indices of the group are relative to content // Indices of the group are relative to content
// To relate them to match we have to subtract the match start index // To relate them to match we have to subtract the match start index
groupStart := groups[i*2] - matchIndices[0] groupStart := groups[i*2] - matchIndices[0]
@@ -158,9 +247,22 @@ func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr
replacement = replacement[:groupStart] + newVal + replacement[groupEnd:] 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
} }

View File

@@ -547,3 +547,760 @@ 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 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)
}
}

View File

@@ -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"