Bump the go-modules-updates group in /backend with 7 updates (#1995)
* Bump the go-modules-updates group in /backend with 7 updates Bumps the go-modules-updates group in /backend with 7 updates: | Package | From | To | | --- | --- | --- | | [github.com/alecthomas/chroma/v2](https://github.com/alecthomas/chroma) | `2.21.1` | `2.23.1` | | [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) | `5.2.3` | `5.2.4` | | [github.com/go-pkgz/rest](https://github.com/go-pkgz/rest) | `1.20.6` | `1.21.0` | | [github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt) | `5.3.0` | `5.3.1` | | [golang.org/x/crypto](https://github.com/golang/crypto) | `0.46.0` | `0.47.0` | | [golang.org/x/image](https://github.com/golang/image) | `0.34.0` | `0.35.0` | | [golang.org/x/net](https://github.com/golang/net) | `0.48.0` | `0.49.0` | Updates `github.com/alecthomas/chroma/v2` from 2.21.1 to 2.23.1 - [Release notes](https://github.com/alecthomas/chroma/releases) - [Commits](https://github.com/alecthomas/chroma/compare/v2.21.1...v2.23.1) Updates `github.com/go-chi/chi/v5` from 5.2.3 to 5.2.4 - [Release notes](https://github.com/go-chi/chi/releases) - [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md) - [Commits](https://github.com/go-chi/chi/compare/v5.2.3...v5.2.4) Updates `github.com/go-pkgz/rest` from 1.20.6 to 1.21.0 - [Release notes](https://github.com/go-pkgz/rest/releases) - [Commits](https://github.com/go-pkgz/rest/compare/v1.20.6...v1.21.0) Updates `github.com/golang-jwt/jwt/v5` from 5.3.0 to 5.3.1 - [Release notes](https://github.com/golang-jwt/jwt/releases) - [Commits](https://github.com/golang-jwt/jwt/compare/v5.3.0...v5.3.1) Updates `golang.org/x/crypto` from 0.46.0 to 0.47.0 - [Commits](https://github.com/golang/crypto/compare/v0.46.0...v0.47.0) Updates `golang.org/x/image` from 0.34.0 to 0.35.0 - [Commits](https://github.com/golang/image/compare/v0.34.0...v0.35.0) Updates `golang.org/x/net` from 0.48.0 to 0.49.0 - [Commits](https://github.com/golang/net/compare/v0.48.0...v0.49.0) --- updated-dependencies: - dependency-name: github.com/alecthomas/chroma/v2 dependency-version: 2.23.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates - dependency-name: github.com/go-chi/chi/v5 dependency-version: 5.2.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-modules-updates - dependency-name: github.com/go-pkgz/rest dependency-version: 1.21.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates - dependency-name: github.com/golang-jwt/jwt/v5 dependency-version: 5.3.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-modules-updates - dependency-name: golang.org/x/crypto dependency-version: 0.47.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates - dependency-name: golang.org/x/image dependency-version: 0.35.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates - dependency-name: golang.org/x/net dependency-version: 0.49.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-modules-updates ... Signed-off-by: dependabot[bot] <support@github.com> * Run go mod tidy in examples directory Co-authored-by: paskal <712534+paskal@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: paskal <712534+paskal@users.noreply.github.com>
This commit is contained in:
co-authored by
paskal
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
parent
e3b0d63648
commit
638fa63e81
@@ -13,12 +13,12 @@ require (
|
||||
require (
|
||||
github.com/Depado/bfchroma/v2 v2.0.0 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.11.0 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.21.1 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.23.1 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||
github.com/go-pkgz/rest v1.20.6 // indirect
|
||||
github.com/go-pkgz/rest v1.21.0 // indirect
|
||||
github.com/go-pkgz/routegroup v1.6.0 // indirect
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
@@ -30,10 +30,10 @@ require (
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
go.etcd.io/bbolt v1.4.3 // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/image v0.34.0 // indirect
|
||||
golang.org/x/net v0.48.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/image v0.36.0 // indirect
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43
|
||||
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.21.1 h1:FaSDrp6N+3pphkNKU6HPCiYLgm8dbe5UXIXcoBhZSWA=
|
||||
github.com/alecthomas/chroma/v2 v2.21.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
||||
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
|
||||
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
@@ -21,8 +21,8 @@ github.com/go-pkgz/jrpc v0.4.0 h1:oD7xiGrzDkndkuCjeHGugQXxbggLSV7O1QmHhoc5pYY=
|
||||
github.com/go-pkgz/jrpc v0.4.0/go.mod h1:JFoY3bRjRyx4M3CbEVDFQStMB1m2gmQ7OjqFK7q3kOo=
|
||||
github.com/go-pkgz/lgr v0.12.1 h1:8GVfG2rSARq3Eaj5PP158rtBR2LHVGkwioIkQBGbvKg=
|
||||
github.com/go-pkgz/lgr v0.12.1/go.mod h1:A4AxjOthFVFK6jRnVYMeusno5SeDAxcLVHd0kI/lN/Y=
|
||||
github.com/go-pkgz/rest v1.20.6 h1:O/IhQ3I2cS4bJYvL1TLcy63w2OcXZTTBG3R+wTIqPS4=
|
||||
github.com/go-pkgz/rest v1.20.6/go.mod h1:NY+MX1is2kJckJt+nHDNovS/5j9jmF4yQuSno4qg7XU=
|
||||
github.com/go-pkgz/rest v1.21.0 h1:Y/C4d/TpclJJDxqnH1RAcS6Hmox0RIReAlkwMcUWXK4=
|
||||
github.com/go-pkgz/rest v1.21.0/go.mod h1:+AHzjHazq7Z3Tk/kRWOhbbAz/YZlUV40feC1Hf4NtbE=
|
||||
github.com/go-pkgz/routegroup v1.6.0 h1:44XHZgF6JIIldRlv+zjg6SygULASmjifnfIQjwCT0e4=
|
||||
github.com/go-pkgz/routegroup v1.6.0/go.mod h1:Pmu04fhgWhRtBMIJ8HXppnnzOPjnL/IEPBIdO2zmeqg=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
@@ -62,10 +62,10 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
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.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8=
|
||||
golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
||||
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
||||
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.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
@@ -80,8 +80,8 @@ 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.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -102,8 +102,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.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.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
||||
+9
-9
@@ -5,9 +5,9 @@ go 1.25
|
||||
require (
|
||||
github.com/Depado/bfchroma/v2 v2.0.0
|
||||
github.com/PuerkitoBio/goquery v1.11.0
|
||||
github.com/alecthomas/chroma/v2 v2.21.1
|
||||
github.com/alecthomas/chroma/v2 v2.23.1
|
||||
github.com/didip/tollbooth/v8 v8.0.1
|
||||
github.com/go-chi/chi/v5 v5.2.3
|
||||
github.com/go-chi/chi/v5 v5.2.5
|
||||
github.com/go-chi/cors v1.2.2
|
||||
github.com/go-pkgz/auth/v2 v2.1.2-0.20260211003156-fbba7f2baa6b
|
||||
github.com/go-pkgz/jrpc v0.4.0
|
||||
@@ -15,9 +15,9 @@ require (
|
||||
github.com/go-pkgz/lgr v0.12.1
|
||||
github.com/go-pkgz/notify v1.3.0
|
||||
github.com/go-pkgz/repeater/v2 v2.2.0
|
||||
github.com/go-pkgz/rest v1.20.6
|
||||
github.com/go-pkgz/rest v1.21.0
|
||||
github.com/go-pkgz/syncs v1.3.2
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/feeds v1.2.0
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
@@ -30,9 +30,9 @@ require (
|
||||
github.com/stretchr/testify v1.11.1
|
||||
go.etcd.io/bbolt v1.4.3
|
||||
go.uber.org/goleak v1.3.0
|
||||
golang.org/x/crypto v0.46.0
|
||||
golang.org/x/image v0.34.0
|
||||
golang.org/x/net v0.48.0
|
||||
golang.org/x/crypto v0.48.0
|
||||
golang.org/x/image v0.36.0
|
||||
golang.org/x/net v0.49.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -67,7 +67,7 @@ require (
|
||||
go.mongodb.org/mongo-driver v1.17.6 // indirect
|
||||
golang.org/x/oauth2 v0.34.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/text v0.32.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
+18
-24
@@ -8,8 +8,8 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.21.1 h1:FaSDrp6N+3pphkNKU6HPCiYLgm8dbe5UXIXcoBhZSWA=
|
||||
github.com/alecthomas/chroma/v2 v2.21.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
||||
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
|
||||
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
|
||||
@@ -42,18 +42,12 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
|
||||
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
|
||||
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
||||
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
|
||||
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
|
||||
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
|
||||
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-oauth2/oauth2/v4 v4.5.4 h1:YjI0tmGW8oxVhn9QSBIxlr641QugWrJY5UWa6XmLcW0=
|
||||
github.com/go-oauth2/oauth2/v4 v4.5.4/go.mod h1:BXiOY+QZtZy2ewbsGk2B5P8TWmtz/Rf7ES5ZttQFxfQ=
|
||||
github.com/go-pkgz/auth/v2 v2.1.1 h1:CBH3Z6ovLT51Nx9TkBcu2L8Dd/xwL6CgJcgqUnC2isQ=
|
||||
github.com/go-pkgz/auth/v2 v2.1.1/go.mod h1:9LwzESczjMavmXNZo1XhYpfYdKWtoCbXt/ZIi0GTvF0=
|
||||
github.com/go-pkgz/auth/v2 v2.1.2-0.20260119213210-5ff800f4c064 h1:+7XirxGV7RV0VzStWbyP6c0edbfaCXB69JeZh6uVpE0=
|
||||
github.com/go-pkgz/auth/v2 v2.1.2-0.20260119213210-5ff800f4c064/go.mod h1:9LwzESczjMavmXNZo1XhYpfYdKWtoCbXt/ZIi0GTvF0=
|
||||
github.com/go-pkgz/auth/v2 v2.1.2-0.20260210234152-7e1ed2cedf71 h1:FxzoRgUemfWKBt0iw9J9Qck5nHB6bNlhmUJneMNL/C8=
|
||||
github.com/go-pkgz/auth/v2 v2.1.2-0.20260210234152-7e1ed2cedf71/go.mod h1:9LwzESczjMavmXNZo1XhYpfYdKWtoCbXt/ZIi0GTvF0=
|
||||
github.com/go-pkgz/auth/v2 v2.1.2-0.20260211003156-fbba7f2baa6b h1:N8iS/o/LgbSL4NLabOuLgfmROjtMLW2Qc3EsMmdYNGs=
|
||||
github.com/go-pkgz/auth/v2 v2.1.2-0.20260211003156-fbba7f2baa6b/go.mod h1:9LwzESczjMavmXNZo1XhYpfYdKWtoCbXt/ZIi0GTvF0=
|
||||
github.com/go-pkgz/email v0.6.0 h1:snZnXldjeF4PgKSjnx9Fa25mtOgFpAOEeWvnQvrxjLE=
|
||||
@@ -72,16 +66,16 @@ github.com/go-pkgz/repeater v1.2.0 h1:oJFvjyKdTDd5RCzpzxlzYIZFFj6Zfl17rE1aUfu6Uj
|
||||
github.com/go-pkgz/repeater v1.2.0/go.mod h1:vypP6xamA53MFmafnGUucqOmALKk36xgKu2hSG73LHM=
|
||||
github.com/go-pkgz/repeater/v2 v2.2.0 h1:8nZR/NaknmLfx2YMHbr78u9OL4Xj+8+romm9dz4FpMg=
|
||||
github.com/go-pkgz/repeater/v2 v2.2.0/go.mod h1:RgX5vUbLKq7PV82QUDP5pFbQS1os4Z+U9XzKymK23A8=
|
||||
github.com/go-pkgz/rest v1.20.6 h1:O/IhQ3I2cS4bJYvL1TLcy63w2OcXZTTBG3R+wTIqPS4=
|
||||
github.com/go-pkgz/rest v1.20.6/go.mod h1:NY+MX1is2kJckJt+nHDNovS/5j9jmF4yQuSno4qg7XU=
|
||||
github.com/go-pkgz/rest v1.21.0 h1:Y/C4d/TpclJJDxqnH1RAcS6Hmox0RIReAlkwMcUWXK4=
|
||||
github.com/go-pkgz/rest v1.21.0/go.mod h1:+AHzjHazq7Z3Tk/kRWOhbbAz/YZlUV40feC1Hf4NtbE=
|
||||
github.com/go-pkgz/routegroup v1.6.0 h1:44XHZgF6JIIldRlv+zjg6SygULASmjifnfIQjwCT0e4=
|
||||
github.com/go-pkgz/routegroup v1.6.0/go.mod h1:Pmu04fhgWhRtBMIJ8HXppnnzOPjnL/IEPBIdO2zmeqg=
|
||||
github.com/go-pkgz/syncs v1.3.2 h1:gmioASlJNy3gNosPlgvWOM2QP0Hdjzn2u+/sUShgd8E=
|
||||
github.com/go-pkgz/syncs v1.3.2/go.mod h1:qjgzpp7OpuhDf7BWsW/FHCu9DLjE32NPy6/vXAXT/Cw=
|
||||
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
||||
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
@@ -207,10 +201,10 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
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.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/image v0.34.0 h1:33gCkyw9hmwbZJeZkct8XyR11yH889EQt/QH4VmXMn8=
|
||||
golang.org/x/image v0.34.0/go.mod h1:2RNFBZRB+vnwwFil8GkMdRvrJOFd1AzdZI6vOY+eJVU=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc=
|
||||
golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4=
|
||||
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.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
@@ -225,8 +219,8 @@ 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.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -249,8 +243,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.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.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -270,8 +264,8 @@ 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.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
Chroma is a syntax highlighting library, tool and web playground for Go. It is based on Pygments and includes importers for it, so most of the same concepts from Pygments apply to Chroma.
|
||||
|
||||
This project is written in Go, uses Hermit to manage tooling, and Just for helper commands. Helper scripts are in ./scripts.
|
||||
|
||||
Language definitions are XML files defined in ./lexers/embedded/*.xml.
|
||||
|
||||
Styles/themes are defined in ./styles/*.xml.
|
||||
|
||||
The CLI can be run with `chroma`.
|
||||
|
||||
The web playground can be run with `chromad --csrf-key=moo`. It blocks, so should generally be run in the background. It also does not hot reload, so has to be manually restarted. The playground has two modes - for local development it uses the server itself to render, while for production running `just chromad` will compile ./cmd/libchromawasm into a WASM module that is bundled into `chromad`.
|
||||
+2
-3
@@ -7,7 +7,6 @@ FROM ubuntu:24.04 AS builder
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
git \
|
||||
make \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -25,8 +24,8 @@ ENV CGO_ENABLED=0
|
||||
ENV GOOS=linux
|
||||
ENV GOARCH=amd64
|
||||
|
||||
# Build the application using make
|
||||
RUN make build/chromad
|
||||
# Build the application using just
|
||||
RUN just chromad
|
||||
|
||||
# Runtime stage
|
||||
FROM alpine:3.23 AS runtime
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
set positional-arguments := true
|
||||
set shell := ["bash", "-c"]
|
||||
|
||||
version := `git describe --tags --dirty --always`
|
||||
export GOOS := env("GOOS", "linux")
|
||||
export GOARCH := env("GOARCH", "amd64")
|
||||
|
||||
_help:
|
||||
@just -l
|
||||
|
||||
# Generate README.md from lexer definitions
|
||||
readme:
|
||||
#!/usr/bin/env bash
|
||||
GOOS= GOARCH= ./table.py
|
||||
|
||||
# Generate tokentype_string.go
|
||||
tokentype-string:
|
||||
go generate
|
||||
|
||||
# Format JavaScript files
|
||||
format-js:
|
||||
biome format --write cmd/chromad/static/index.js cmd/chromad/static/chroma.js
|
||||
|
||||
# Build chromad binary
|
||||
chromad: wasm-exec chroma-wasm
|
||||
#!/usr/bin/env bash
|
||||
rm -rf build
|
||||
mk cmd/chromad/static/index.min.js : cmd/chromad/static/{index,chroma}.js -- \
|
||||
esbuild --platform=browser --format=esm --bundle cmd/chromad/static/index.js --minify --external:./wasm_exec.js --outfile=cmd/chromad/static/index.min.js
|
||||
mk cmd/chromad/static/index.min.css : cmd/chromad/static/index.css -- \
|
||||
esbuild --bundle cmd/chromad/static/index.css --minify --outfile=cmd/chromad/static/index.min.css
|
||||
cd cmd/chromad && CGOENABLED=0 go build -ldflags="-X 'main.version={{ version }}'" -o ../../build/chromad .
|
||||
|
||||
# Copy wasm_exec.js from TinyGo
|
||||
wasm-exec:
|
||||
#!/usr/bin/env bash
|
||||
tinygoroot=$(tinygo env TINYGOROOT)
|
||||
mk cmd/chromad/static/wasm_exec.js : "$tinygoroot/targets/wasm_exec.js" -- \
|
||||
install -m644 "$tinygoroot/targets/wasm_exec.js" cmd/chromad/static/wasm_exec.js
|
||||
|
||||
# Build WASM binary
|
||||
chroma-wasm:
|
||||
#!/usr/bin/env bash
|
||||
if type tinygo > /dev/null 2>&1; then
|
||||
mk cmd/chromad/static/chroma.wasm : cmd/libchromawasm/main.go -- \
|
||||
tinygo build -no-debug -target wasm -o cmd/chromad/static/chroma.wasm cmd/libchromawasm/main.go
|
||||
else
|
||||
mk cmd/chromad/static/chroma.wasm : cmd/libchromawasm/main.go -- \
|
||||
GOOS=js GOARCH=wasm go build -o cmd/chromad/static/chroma.wasm cmd/libchromawasm/main.go
|
||||
fi
|
||||
|
||||
# Upload chromad to server
|
||||
upload: chromad
|
||||
scp build/chromad root@swapoff.org:
|
||||
ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart'
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
.PHONY: chromad upload all
|
||||
|
||||
VERSION ?= $(shell git describe --tags --dirty --always)
|
||||
export GOOS ?= linux
|
||||
export GOARCH ?= amd64
|
||||
|
||||
all: README.md tokentype_string.go
|
||||
|
||||
README.md: lexers/*.go lexers/embedded/*.xml
|
||||
GOOS= GOARCH= ./table.py
|
||||
|
||||
tokentype_string.go: types.go
|
||||
go generate
|
||||
|
||||
.PHONY: format-js
|
||||
format-js:
|
||||
biome format --write cmd/chromad/static/{index.js,chroma.js}
|
||||
|
||||
.PHONY: chromad
|
||||
chromad: build/chromad
|
||||
|
||||
build/chromad: $(shell find cmd/chromad -name '*.go' -o -name '*.html' -o -name '*.css' -o -name '*.js') \
|
||||
cmd/chromad/static/wasm_exec.js \
|
||||
cmd/chromad/static/chroma.wasm
|
||||
rm -rf build
|
||||
esbuild --platform=node --bundle cmd/chromad/static/index.js --minify --outfile=cmd/chromad/static/index.min.js
|
||||
esbuild --bundle cmd/chromad/static/index.css --minify --outfile=cmd/chromad/static/index.min.css
|
||||
(export CGOENABLED=0 ; go build -C cmd/chromad -ldflags="-X 'main.version=$(VERSION)'" -o ../../build/chromad .)
|
||||
|
||||
cmd/chromad/static/wasm_exec.js: $(shell tinygo env TINYGOROOT)/targets/wasm_exec.js
|
||||
install -m644 $< $@
|
||||
|
||||
cmd/chromad/static/chroma.wasm: $(shell git ls-files | grep '\.go|\.xml')
|
||||
if type tinygo > /dev/null; then \
|
||||
tinygo build -no-debug -target wasm -o $@ cmd/libchromawasm/main.go; \
|
||||
else \
|
||||
GOOS=js GOARCH=wasm go build -o $@ cmd/libchromawasm/main.go; \
|
||||
fi
|
||||
|
||||
upload: build/chromad
|
||||
scp build/chromad root@swapoff.org: && \
|
||||
ssh root@swapoff.org 'install -m755 ./chromad /srv/http/swapoff.org/bin && service chromad restart'
|
||||
+1
-1
@@ -48,7 +48,7 @@ translators for Pygments lexers and styles.
|
||||
| J | J, Janet, Java, JavaScript, JSON, JSONata, Jsonnet, Julia, Jungle
|
||||
| K | Kakoune, Kotlin
|
||||
| L | Lean4, Lighttpd configuration file, LLVM, lox, Lua
|
||||
| M | Makefile, Mako, markdown, Mason, Materialize SQL dialect, Mathematica, Matlab, MCFunction, Meson, Metal, MiniZinc, MLIR, Modelica, Modula-2, Mojo, MonkeyC, MoonScript, MorrowindScript, Myghty, MySQL
|
||||
| M | Makefile, Mako, markdown, Markless, Mason, Materialize SQL dialect, Mathematica, Matlab, MCFunction, Meson, Metal, MiniZinc, MLIR, Modelica, Modula-2, Mojo, MonkeyC, MoonScript, MorrowindScript, Myghty, MySQL
|
||||
| N | NASM, Natural, NDISASM, Newspeak, Nginx configuration file, Nim, Nix, NSIS, Nu
|
||||
| O | Objective-C, ObjectPascal, OCaml, Octave, Odin, OnesEnterprise, OpenEdge ABL, OpenSCAD, Org Mode
|
||||
| P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Plutus Core, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerQuery, PowerShell, Prolog, Promela, PromQL, properties, Protocol Buffer, Protocol Buffer Text Format, PRQL, PSL, Puppet, Python, Python 2
|
||||
|
||||
+1
@@ -528,6 +528,7 @@ func (f *Formatter) styleToCSS(style *chroma.Style) map[chroma.TokenType]string
|
||||
}
|
||||
classes[chroma.Background] += `;` + f.tabWidthStyle()
|
||||
classes[chroma.PreWrapper] += classes[chroma.Background]
|
||||
classes[chroma.PreWrapper] += ` -webkit-text-size-adjust: none;`
|
||||
// Make PreWrapper a grid to show highlight style with full width.
|
||||
if len(f.highlightRanges) > 0 && f.customCSS[chroma.PreWrapper] == `` {
|
||||
classes[chroma.PreWrapper] += `display: grid;`
|
||||
|
||||
+3
-1
@@ -12,6 +12,7 @@
|
||||
<filename>*.ebuild</filename>
|
||||
<filename>*.eclass</filename>
|
||||
<filename>.env</filename>
|
||||
<filename>.env.*</filename>
|
||||
<filename>*.env</filename>
|
||||
<filename>*.exheres-0</filename>
|
||||
<filename>*.exlib</filename>
|
||||
@@ -23,6 +24,7 @@
|
||||
<filename>bash_*</filename>
|
||||
<filename>zshrc</filename>
|
||||
<filename>.zshrc</filename>
|
||||
<filename>APKBUILD</filename>
|
||||
<filename>PKGBUILD</filename>
|
||||
<mime_type>application/x-sh</mime_type>
|
||||
<mime_type>application/x-shellscript</mime_type>
|
||||
@@ -217,4 +219,4 @@
|
||||
</rule>
|
||||
</state>
|
||||
</rules>
|
||||
</lexer>
|
||||
</lexer>
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
<lexer>
|
||||
<config>
|
||||
<name>KDL</name>
|
||||
<alias>kdl</alias>
|
||||
<filename>*.kdl</filename>
|
||||
</config>
|
||||
<rules>
|
||||
<state name="root">
|
||||
<rule pattern="((?<={|;)|^)\s*(?![/\\\{\}#;\[\]\=])[<>:\w\-_~,\'`!\?@\$%^&*+|\.\(\)\x{0080}-\x{0001f645}]+\d*?[<>:\w\-_~,\'`!\?@\$%^&*+|\.\(\)\x{0080}-\x{0001f645}]*?"><token type="NameLabel"/></rule>
|
||||
<rule pattern="(#true|#false|#null|#nan|#inf|#-inf)\b"><token type="KeywordConstant"/></rule>
|
||||
<rule pattern="[{}=;\\]"><token type="Operator"/></rule>
|
||||
<rule pattern="(\b([0-9-\+]|-|\+)[0-9_]*?\.[0-9][0-9_]*?([eE][+-]?[0-9_]+)?\b|\b[0-9][0-9_]*?(\.[0-9][0-9_]*?)?[eE][+-]?[0-9_]+\b)"><token type="LiteralNumberFloat"/></rule>
|
||||
<rule pattern="\b[0-9\-\+][0-9_]*\b"><token type="LiteralNumber"/></rule>
|
||||
<rule pattern="\b0x[a-fA-F0-9][a-fA-F0-9_]*?\b"><token type="LiteralNumberHex"/></rule>
|
||||
<rule pattern="\b0o[0-7][0-7_]*\b"><token type="LiteralNumberOct"/></rule>
|
||||
<rule pattern="\b0b[01][01_]*?\b"><token type="LiteralNumberBin"/></rule>
|
||||
<rule pattern="#+(\"""|").*?("""|")#+"><token type="LiteralString"/></rule>
|
||||
<rule pattern="#?""""><token type="LiteralString"/><push state="multiline_string"/></rule>
|
||||
<rule pattern="#?""><token type="LiteralString"/><push state="string"/></rule>
|
||||
<rule pattern="/\*"><token type="CommentMultiline"/><push state="comment"/></rule>
|
||||
<rule pattern="/\*!"><token type="LiteralStringDoc"/><push state="doccomment"/></rule>
|
||||
<rule pattern="/-\s*{"><token type="CommentMultiline"/><push state="slashdash_block_comment"/></rule>
|
||||
<rule pattern="\s*/-\s?[^\s=]*?\s?{"><token type="CommentMultiline"/><push state="slashdash_node_comment"/></rule>
|
||||
<rule pattern="(?<!^)\s*/-\s*(".*"|.*?)?\s"><token type="CommentSingle"/></rule>
|
||||
<rule pattern="(?<=^)\s*/-[^{]+{"><token type="CommentMultiline"/><push state="slashdash_node_with_children_comment"/></rule>
|
||||
<rule pattern="(\/\/(.*?)\n|(?<!^)\s*/-\s*?\s)"><token type="CommentSingle"/></rule>
|
||||
<rule pattern="(?![/\\\{\}#;\[\]\=])[<>:\w\-_~,\'`!\?@\$%^&*+|.\(\)\x{0080}-\x{0001f645}]+\d*?[<>:\w\-_~,\'`!\?@\$%^&*+|.\(\)\x{0080}-\x{0001f645}]*(=)"><token type="NameAttribute"/></rule>
|
||||
<rule pattern="(?![/\\{\}#;\[\]\=])[<>:\w\-_~,\'`!\?@\$%^&*+|.\(\)\x{0080}-\x{0001f645}]+\d*[<>:\w\-_~,\'`!\?@\$%^&*+|.\(\)\x{0080}-\x{0001f645}]*?"><token type="LiteralString"/></rule>
|
||||
<rule pattern="\s"><token type="TextWhitespace"/></rule>
|
||||
</state>
|
||||
<state name="string">
|
||||
<rule pattern=""#?"><token type="LiteralString"/><pop depth="1"/></rule>
|
||||
<rule pattern="\\['"\\nrt]|\\x[0-7][0-9a-fA-F]|\\0|\\u\{[0-9a-fA-F]{1,6}\}"><token type="LiteralStringEscape"/></rule>
|
||||
<rule pattern="[^\\"]+"><token type="LiteralString"/></rule>
|
||||
<rule pattern="\\"><token type="LiteralString"/></rule>
|
||||
</state>
|
||||
<state name="multiline_string">
|
||||
<rule pattern=""""#?"><token type="LiteralString"/><pop depth="1"/></rule>
|
||||
<rule pattern="\\['"\\nrt]|\\x[0-7][0-9a-fA-F]|\\0|\\u\{[0-9a-fA-F]{1,6}\}"><token type="LiteralStringEscape"/></rule>
|
||||
<rule pattern="""><token type="LiteralString"/></rule>
|
||||
<rule pattern="[^\\"]+"><token type="LiteralString"/></rule>
|
||||
<rule pattern="\\"><token type="LiteralString"/></rule>
|
||||
</state>
|
||||
<state name="slashdash_block_comment">
|
||||
<rule pattern="[^}]+"><token type="CommentMultiline"/></rule>
|
||||
<rule pattern="/-\s*{"><token type="CommentMultiline"/><push/></rule>
|
||||
<rule pattern="\}"><token type="CommentMultiline"/><pop depth="1"/></rule>
|
||||
<rule pattern="[\}]"><token type="CommentMultiline"/></rule>
|
||||
</state>
|
||||
<state name="slashdash_node_comment">
|
||||
<rule pattern="[^\}]+"><token type="CommentMultiline"/></rule>
|
||||
<rule pattern="^\s*?/-.*?\s?{"><token type="CommentMultiline"/><push/></rule>
|
||||
<rule pattern="\}"><token type="CommentMultiline"/><pop depth="1"/></rule>
|
||||
<rule pattern="[\}]"><token type="CommentMultiline"/></rule>
|
||||
</state>
|
||||
<state name="slashdash_node_with_children_comment">
|
||||
<rule pattern="[^\}]+"><token type="CommentMultiline"/></rule>
|
||||
<rule pattern="(?<=^)\s*/-[^{]+{"><token type="CommentMultiline"/><push/></rule>
|
||||
<rule pattern="\}"><token type="CommentMultiline"/><pop depth="1"/></rule>
|
||||
<rule pattern="[\}]"><token type="CommentMultiline"/></rule>
|
||||
</state>
|
||||
<state name="comment">
|
||||
<rule pattern="[^*/]+"><token type="CommentMultiline"/></rule>
|
||||
<rule pattern="/\*"><token type="CommentMultiline"/><push/></rule>
|
||||
<rule pattern="\*/"><token type="CommentMultiline"/><pop depth="1"/></rule>
|
||||
<rule pattern="[*/]"><token type="CommentMultiline"/></rule>
|
||||
</state>
|
||||
<state name="doccomment">
|
||||
<rule pattern="[^*/]+"><token type="LiteralStringDoc"/></rule>
|
||||
<rule pattern="/\*"><token type="LiteralStringDoc"/><push/></rule>
|
||||
<rule pattern="\*/"><token type="LiteralStringDoc"/><pop depth="1"/></rule>
|
||||
<rule pattern="[*/]"><token type="LiteralStringDoc"/></rule>
|
||||
</state>
|
||||
</rules>
|
||||
</lexer>
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
<lexer>
|
||||
<config>
|
||||
<name>microcad</name>
|
||||
<alias>µcad</alias>
|
||||
<filename>*.µcad</filename>
|
||||
<filename>*.ucad</filename>
|
||||
<filename>*.mcad</filename>
|
||||
<mime_type>text/microcad</mime_type>
|
||||
<ensure_nl>true</ensure_nl>
|
||||
</config>
|
||||
|
||||
<rules>
|
||||
<!-- Root state -->
|
||||
<state name="root">
|
||||
<rule pattern="\n">
|
||||
<token type="TextWhitespace"/>
|
||||
</rule>
|
||||
<rule pattern="\s+">
|
||||
<token type="TextWhitespace"/>
|
||||
</rule>
|
||||
|
||||
<!-- COMMENTS -->
|
||||
<rule pattern="///.*">
|
||||
<token type="LiteralStringDoc"/>
|
||||
</rule>
|
||||
|
||||
<rule pattern="//.*">
|
||||
<token type="CommentSingle"/>
|
||||
</rule>
|
||||
|
||||
<rule pattern="/\*.*">
|
||||
<token type="CommentMultiline"/>
|
||||
<push state="comment"/>
|
||||
</rule>
|
||||
|
||||
<!-- KEYWORDS -->
|
||||
<rule pattern="\b(pub|sketch|part|op|mod|use|fn|const|prop|init|return|if|else|mat|__builtin|or|and|not|as)\b">
|
||||
<token type="Keyword"/>
|
||||
</rule>
|
||||
|
||||
<!-- TYPES -->
|
||||
<rule pattern="\b(Integer|Scalar|String|Color|Length|Area|Volume|Angle|Weight|Density|Bool|Matrix[0-9])\b">
|
||||
<token type="KeywordType"/>
|
||||
</rule>
|
||||
|
||||
<!-- FUNCTION NAMES -->
|
||||
<rule pattern="\b([a-z_][a-zA-Z0-9_]*)\s*(?=\()">
|
||||
<token type="NameFunction"/>
|
||||
</rule>
|
||||
|
||||
<!-- OPERATORS -->
|
||||
<rule pattern="[+\-*/%&|<>^!@=]">
|
||||
<token type="Operator"/>
|
||||
</rule>
|
||||
|
||||
<!-- NUMBERS + UNITS -->
|
||||
<rule pattern="\b(([0-9]+(\.[0-9]+)?)(%|m²|cm²|mm²|µm²|in²|ft²|yd²|m³|cm³|mm³|µm³|in³|ft³|yd³|ml|cl|l|µl|cm|mm|m|µm|in|ft|yd|deg|°|grad|turn|rad|g|kg|lb|oz)?)|true|false\b">
|
||||
<token type="LiteralNumber"/>
|
||||
</rule>
|
||||
|
||||
<!-- NAMESPACES -->
|
||||
<rule pattern="([a-z_][a-z0-9_]*)(::)">
|
||||
<bygroups>
|
||||
<token type="NameNamespace"/>
|
||||
<token type="Operator"/>
|
||||
</bygroups>
|
||||
</rule>
|
||||
|
||||
<!-- CONSTANTS (ALL CAPS) -->
|
||||
<rule pattern="\b([A-Z_][A-Z0-9_]*)\b">
|
||||
<token type="NameConstant"/>
|
||||
</rule>
|
||||
|
||||
<!-- CUSTOM TYPES (Capitalized identifiers) -->
|
||||
<rule pattern="\b([A-Z_][a-zA-Z0-9_]*)\b">
|
||||
<token type="NameClass"/>
|
||||
</rule>
|
||||
|
||||
<!-- VARIABLES -->
|
||||
<rule pattern="\b([a-z_][a-zA-Z0-9_]*)\b">
|
||||
<token type="Name"/>
|
||||
</rule>
|
||||
|
||||
<!-- STRINGS -->
|
||||
<rule pattern=""[^"]*"">
|
||||
<token type="LiteralString"/>
|
||||
</rule>
|
||||
|
||||
<!-- PAREN GROUP -->
|
||||
<rule pattern="[{}()\[\],.;:]">
|
||||
<token type="Punctuation"/>
|
||||
</rule>
|
||||
|
||||
|
||||
<!-- BRACE GROUP -->
|
||||
<rule pattern="\{">
|
||||
<token type="Punctuation"/>
|
||||
<push state="brace"/>
|
||||
</rule>
|
||||
|
||||
<rule pattern="[\}\)]">
|
||||
<token type="Punctuation"/>
|
||||
</rule>
|
||||
|
||||
</state>
|
||||
|
||||
<!-- Parenthesized expression -->
|
||||
<state name="paren">
|
||||
<rule pattern="\)">
|
||||
<token type="Punctuation"/>
|
||||
<pop/>
|
||||
</rule>
|
||||
<rule>
|
||||
<include state="root"/>
|
||||
</rule>
|
||||
</state>
|
||||
|
||||
<!-- Braced expression -->
|
||||
<state name="brace">
|
||||
<rule pattern="\}">
|
||||
<token type="Punctuation"/>
|
||||
<pop/>
|
||||
</rule>
|
||||
<rule>
|
||||
<include state="root"/>
|
||||
</rule>
|
||||
</state>
|
||||
|
||||
<state name="comment">
|
||||
<!-- End of comment -->
|
||||
<rule pattern="\*/">
|
||||
<token type="CommentMultiline"/>
|
||||
<pop/>
|
||||
</rule>
|
||||
</state>
|
||||
|
||||
|
||||
</rules>
|
||||
</lexer>
|
||||
+105
-105
@@ -1,106 +1,106 @@
|
||||
<lexer>
|
||||
<config>
|
||||
<name>Modelica</name>
|
||||
<alias>modelica</alias>
|
||||
<filename>*.mo</filename>
|
||||
<mime_type>text/x-modelica</mime_type>
|
||||
<dot_all>true</dot_all>
|
||||
<ensure_nl>true</ensure_nl>
|
||||
</config>
|
||||
<rules>
|
||||
<state name="root">
|
||||
<!-- Comments -->
|
||||
<rule pattern="//[^\n\r]*">
|
||||
<token type="CommentSingle"/>
|
||||
</rule>
|
||||
<rule pattern="/[*].*?[*]/">
|
||||
<token type="CommentMultiline"/>
|
||||
</rule>
|
||||
|
||||
<!-- Whitespace and newlines -->
|
||||
<rule pattern="\s+">
|
||||
<token type="Text"/>
|
||||
</rule>
|
||||
<rule pattern="\n">
|
||||
<token type="Text"/>
|
||||
</rule>
|
||||
|
||||
<!-- Keywords (Modelica specific) -->
|
||||
<rule pattern="\b(model|equation|end|extends|function|type|record|connector|parameter|constant|if|then|else|for|in|when|assert|outer|algorithm|flow|discrete|input|output|loop|elseif|return|public|protected|external|real|integer|boolean|string|array|complex|union|tuple|class|der|time|tstart|tstop)\b">
|
||||
<token type="Keyword"/>
|
||||
</rule>
|
||||
|
||||
<!-- Type definitions -->
|
||||
<rule pattern="\b(boolean|integer|real|string|array|record|complex|union|tuple)\b">
|
||||
<token type="KeywordType"/>
|
||||
</rule>
|
||||
|
||||
<!-- Preprocessor directives -->
|
||||
<rule pattern="#[ \t]*(if|else|endif|define|include|error)\b">
|
||||
<token type="CommentPreproc"/>
|
||||
</rule>
|
||||
|
||||
<!-- Literals -->
|
||||
<rule pattern="\\"[^"\n]*\\"">
|
||||
<token type="LiteralString"/>
|
||||
</rule>
|
||||
<rule pattern="'[^'\n]'">
|
||||
<token type="LiteralStringChar"/>
|
||||
</rule>
|
||||
<rule pattern="\d+(\.\d+)?([eE][+-]?\d+)?">
|
||||
<token type="LiteralNumber"/>
|
||||
</rule>
|
||||
|
||||
<!-- Identifiers and names -->
|
||||
<rule pattern="@[A-Za-z_]\w*">
|
||||
<token type="Name"/>
|
||||
</rule>
|
||||
<rule pattern="[A-Za-z_]\w*">
|
||||
<token type="Name"/>
|
||||
</rule>
|
||||
|
||||
<!-- Punctuation -->
|
||||
<rule pattern="[{}(),;=.+\-*/&|!<>^%]">
|
||||
<token type="Punctuation"/>
|
||||
</rule>
|
||||
|
||||
<!-- Operators -->
|
||||
<rule pattern="(\+|\-|\*|\/|\^|\&|\||\<|\>|\%|\=|\!=|\<\=|\>\=)">
|
||||
<token type="Operator"/>
|
||||
</rule>
|
||||
</state>
|
||||
|
||||
<state name="function">
|
||||
<!-- Function name -->
|
||||
<rule pattern="[A-Za-z_]\w*">
|
||||
<token type="NameFunction"/>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
<rule>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
</state>
|
||||
|
||||
<state name="type">
|
||||
<!-- Type definition -->
|
||||
<rule pattern="[A-Za-z_]\w*">
|
||||
<token type="NameClass"/>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
<rule>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
</state>
|
||||
|
||||
<state name="record">
|
||||
<!-- Record definition -->
|
||||
<rule pattern="[A-Za-z_]\w*">
|
||||
<token type="NameClass"/>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
<rule>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
</state>
|
||||
</rules>
|
||||
<lexer>
|
||||
<config>
|
||||
<name>Modelica</name>
|
||||
<alias>modelica</alias>
|
||||
<filename>*.mo</filename>
|
||||
<mime_type>text/x-modelica</mime_type>
|
||||
<dot_all>true</dot_all>
|
||||
<ensure_nl>true</ensure_nl>
|
||||
</config>
|
||||
<rules>
|
||||
<state name="root">
|
||||
<!-- Comments -->
|
||||
<rule pattern="//[^\n\r]*">
|
||||
<token type="CommentSingle"/>
|
||||
</rule>
|
||||
<rule pattern="/[*].*?[*]/">
|
||||
<token type="CommentMultiline"/>
|
||||
</rule>
|
||||
|
||||
<!-- Whitespace and newlines -->
|
||||
<rule pattern="\s+">
|
||||
<token type="Text"/>
|
||||
</rule>
|
||||
<rule pattern="\n">
|
||||
<token type="Text"/>
|
||||
</rule>
|
||||
|
||||
<!-- Keywords (Modelica specific) -->
|
||||
<rule pattern="\b(model|equation|end|extends|function|type|record|connector|parameter|constant|if|then|else|for|in|when|assert|outer|algorithm|flow|discrete|input|output|loop|elseif|return|public|protected|external|real|integer|boolean|string|array|complex|union|tuple|class|der|time|tstart|tstop)\b">
|
||||
<token type="Keyword"/>
|
||||
</rule>
|
||||
|
||||
<!-- Type definitions -->
|
||||
<rule pattern="\b(boolean|integer|real|string|array|record|complex|union|tuple)\b">
|
||||
<token type="KeywordType"/>
|
||||
</rule>
|
||||
|
||||
<!-- Preprocessor directives -->
|
||||
<rule pattern="#[ \t]*(if|else|endif|define|include|error)\b">
|
||||
<token type="CommentPreproc"/>
|
||||
</rule>
|
||||
|
||||
<!-- Literals -->
|
||||
<rule pattern="\\"[^"\n]*\\"">
|
||||
<token type="LiteralString"/>
|
||||
</rule>
|
||||
<rule pattern="'[^'\n]'">
|
||||
<token type="LiteralStringChar"/>
|
||||
</rule>
|
||||
<rule pattern="\d+(\.\d+)?([eE][+-]?\d+)?">
|
||||
<token type="LiteralNumber"/>
|
||||
</rule>
|
||||
|
||||
<!-- Identifiers and names -->
|
||||
<rule pattern="@[A-Za-z_]\w*">
|
||||
<token type="Name"/>
|
||||
</rule>
|
||||
<rule pattern="[A-Za-z_]\w*">
|
||||
<token type="Name"/>
|
||||
</rule>
|
||||
|
||||
<!-- Punctuation -->
|
||||
<rule pattern="[{}(),;=.+\-*/&|!<>^%]">
|
||||
<token type="Punctuation"/>
|
||||
</rule>
|
||||
|
||||
<!-- Operators -->
|
||||
<rule pattern="(\+|\-|\*|\/|\^|\&|\||\<|\>|\%|\=|\!=|\<\=|\>\=)">
|
||||
<token type="Operator"/>
|
||||
</rule>
|
||||
</state>
|
||||
|
||||
<state name="function">
|
||||
<!-- Function name -->
|
||||
<rule pattern="[A-Za-z_]\w*">
|
||||
<token type="NameFunction"/>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
<rule>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
</state>
|
||||
|
||||
<state name="type">
|
||||
<!-- Type definition -->
|
||||
<rule pattern="[A-Za-z_]\w*">
|
||||
<token type="NameClass"/>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
<rule>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
</state>
|
||||
|
||||
<state name="record">
|
||||
<!-- Record definition -->
|
||||
<rule pattern="[A-Za-z_]\w*">
|
||||
<token type="NameClass"/>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
<rule>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
</state>
|
||||
</rules>
|
||||
</lexer>
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
<lexer>
|
||||
<config>
|
||||
<name>MoonBit</name>
|
||||
<alias>moonbit</alias>
|
||||
<alias>mbt</alias>
|
||||
<filename>*.mbt</filename>
|
||||
<ensure_nl>true</ensure_nl>
|
||||
</config>
|
||||
<rules>
|
||||
<state name="root">
|
||||
<rule pattern="#.*$"><token type="CommentPreproc"/></rule>
|
||||
<rule pattern="//.*$"><token type="CommentSingle"/></rule>
|
||||
<rule pattern="b?\'.*\'"><token type="Literal"/></rule>
|
||||
<rule pattern="#\|.*$"><token type="LiteralString"/></rule>
|
||||
<rule pattern="(b)(\")"><bygroups><token type="LiteralStringAffix"/><token type="LiteralString"/></bygroups><push state="string.inline"/></rule>
|
||||
<rule pattern="""><token type="LiteralString"/><push state="string.inline"/></rule>
|
||||
<rule pattern="\$\|"><token type="LiteralString"/><push state="string.multiline"/></rule>
|
||||
<rule pattern="0(b|B)[01]+"><token type="LiteralNumberBin"/></rule>
|
||||
<rule pattern="0(o|O)[0-7]+"><token type="LiteralNumberOct"/></rule>
|
||||
<rule pattern="0(x|X)[0-9a-fA-F][0-9a-fA-F_]*\.[0-9a-fA-F][0-9a-fA-F_]*(P|p)(\+|\-)?[0-9][0-9]*"><token type="LiteralNumberFloat"/></rule>
|
||||
<rule pattern="0(x|X)[0-9a-fA-F][0-9a-fA-F_]*\.?(P|p)(\+|\-)?[0-9][0-9]*"><token type="LiteralNumberFloat"/></rule>
|
||||
<rule pattern="0(x|X)[0-9a-fA-F][0-9a-fA-F_]*\.[0-9a-fA-F][0-9a-fA-F_]*"><token type="LiteralNumberFloat"/></rule>
|
||||
<rule pattern="0(x|X)[0-9a-fA-F][0-9a-fA-F_]*\."><token type="LiteralNumberFloat"/></rule>
|
||||
<rule pattern="0(x|X)[0-9a-fA-F][0-9a-fA-F_]*"><token type="LiteralNumberHex"/></rule>
|
||||
<rule pattern="\d(_|\d)*U?L"><token type="LiteralNumberIntegerLong"/></rule>
|
||||
<rule pattern="\d(_|\d)*U?"><token type="LiteralNumberInteger"/></rule>
|
||||
<rule pattern="\d+(.\d+)?"><token type="LiteralNumber"/></rule>
|
||||
<rule pattern="(type|type!|enum|struct|trait|typealias|traitalias)\b"><token type="KeywordDeclaration"/></rule>
|
||||
<rule pattern="(async|fn|const|let|mut|impl|with|derive|fnalias)\b"><token type="KeywordDeclaration"/></rule>
|
||||
<rule pattern="(self|Self)\b"><token type="Keyword"/></rule>
|
||||
<rule pattern="(guard|if|while|match|else|loop|for|in|is)\b"><token type="Keyword"/></rule>
|
||||
<rule pattern="(return|break|continue)\b"><token type="Keyword"/></rule>
|
||||
<rule pattern="(try|catch|raise|noraise)\b"><token type="Keyword"/></rule>
|
||||
<rule pattern="\bas\b"><token type="Keyword"/></rule>
|
||||
<rule pattern="(extern|pub|priv|pub\(all\)|pub\(readonly\)|pub\(open\)|test)\b"><token type="Keyword"/></rule>
|
||||
<rule pattern="(true|false)\b"><token type="KeywordConstant"/></rule>
|
||||
<rule pattern="(Eq|Compare|Hash|Show|Default|ToJson|FromJson)\b"><token type="NameBuiltin"/></rule>
|
||||
<rule pattern="(Array|FixedArray|Int|Int64|UInt|UInt64|Option|Result|Byte|Bool|Unit|String|Float|Double)\b"><token type="NameBuiltin"/></rule>
|
||||
<rule pattern="(\+|\-|\*|/|%|\|>|>>|<<|\&\&|\|\||\&|\||<|>|==)"><token type="Operator"/></rule>
|
||||
<rule pattern="(not|lsl|lsr|asr|op_add|op_sub|op_div|op_mul|op_mod|\.\.\.)"><token type="OperatorWord"/></rule>
|
||||
<rule pattern="@[A-Za-z][A-Za-z0-9_/]*\."><token type="NameNamespace"/></rule>
|
||||
<rule pattern="([a-z][A-Za-z0-9_]*)(\s+)(as)(\s+)([a-z][A-Za-z0-9_]*)"><bygroups><token type="NameFunction"/><token type="TextWhitespace"/><token type="Keyword"/><token type="TextWhitespace"/><token type="NameFunction"/></bygroups></rule>
|
||||
<rule pattern="([A-Za-z][A-Za-z0-9_]*)(::)([A-Za-z][A-Za-z0-9_]*)(\s+)(as)(\s+)([a-z][A-Za-z0-9_]*)"><bygroups><token type="NameClass"/><token type="Punctuation"/><token type="NameFunction"/><token type="TextWhitespace"/><token type="Keyword"/><token type="TextWhitespace"/><token type="NameFunction"/></bygroups></rule>
|
||||
<rule pattern="([A-Za-z][A-Za-z0-9_]*)(::)([A-Za-z][A-Za-z0-9_]*)"><bygroups><token type="NameClass"/><token type="Punctuation"/><token type="NameFunction"/></bygroups></rule>
|
||||
<rule pattern="([a-z][A-Za-z0-9_]*)(?=!?\()"><token type="NameFunction"/></rule>
|
||||
<rule pattern="Error"><token type="NameException"/></rule>
|
||||
<rule pattern="(=>)|(->)|[\(\)\{\}\[\]:,\.=!?~;]"><token type="Punctuation"/></rule>
|
||||
<rule pattern="[a-z][a-zA-Z0-9_]*"><token type="NameVariable"/></rule>
|
||||
<rule pattern="[A-Z_][a-zA-Z0-9_]*"><token type="NameClass"/></rule>
|
||||
<rule pattern="[\s]"><token type="TextWhitespace"/></rule>
|
||||
</state>
|
||||
<state name="string.inline">
|
||||
<rule><include state="escape"/></rule>
|
||||
<rule pattern="\\{"><token type="LiteralStringEscape"/><push state="interpolation"/></rule>
|
||||
<rule pattern="""><token type="LiteralString"/><pop depth="1"/></rule>
|
||||
<rule pattern="."><token type="LiteralStringDouble"/></rule>
|
||||
</state>
|
||||
<state name="string.multiline">
|
||||
<rule><include state="escape"/></rule>
|
||||
<rule pattern="\\{"><token type="LiteralStringEscape"/><push state="interpolation"/></rule>
|
||||
<rule pattern="\Z"><token type="LiteralString"/><pop depth="1"/></rule>
|
||||
<rule pattern="."><token type="LiteralString"/></rule>
|
||||
</state>
|
||||
<state name="interpolation">
|
||||
<rule pattern="}"><token type="LiteralStringEscape"/><pop depth="1"/></rule>
|
||||
<rule><include state="root"/></rule>
|
||||
</state>
|
||||
<state name="escape">
|
||||
<rule pattern="\\[0\\tnrb\"']"><token type="LiteralStringEscape"/></rule>
|
||||
<rule pattern="\\x[0-9a-fA-f]{2}"><token type="LiteralStringEscape"/></rule>
|
||||
<rule pattern="\\u[0-9a-fA-f]{4}"><token type="LiteralStringEscape"/></rule>
|
||||
<rule pattern="\\u[0-9a-fA-f]*"><token type="LiteralStringEscape"/></rule>
|
||||
</state>
|
||||
</rules>
|
||||
</lexer>
|
||||
+111
-40
@@ -8,7 +8,13 @@
|
||||
</config>
|
||||
<rules>
|
||||
<state name="string">
|
||||
<rule pattern="\\(x[a-fA-F0-9]{2}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{6}|[nr\\t\'"])">
|
||||
<rule pattern="\\x[0-9a-fA-F]{2}">
|
||||
<token type="LiteralStringEscape"/>
|
||||
</rule>
|
||||
<rule pattern="\\u\{[0-9a-fA-F]+\}">
|
||||
<token type="LiteralStringEscape"/>
|
||||
</rule>
|
||||
<rule pattern="\\[nrt'"\\]">
|
||||
<token type="LiteralStringEscape"/>
|
||||
</rule>
|
||||
<rule pattern="[^\\"\n]+">
|
||||
@@ -18,99 +24,164 @@
|
||||
<token type="LiteralString"/>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
<rule pattern="\\">
|
||||
<token type="LiteralString"/>
|
||||
</rule>
|
||||
</state>
|
||||
<state name="quoted_ident">
|
||||
<rule pattern="\\x[0-9a-fA-F]{2}">
|
||||
<token type="LiteralStringEscape"/>
|
||||
</rule>
|
||||
<rule pattern="\\u\{[0-9a-fA-F]+\}">
|
||||
<token type="LiteralStringEscape"/>
|
||||
</rule>
|
||||
<rule pattern="\\[nrt'"\\]">
|
||||
<token type="LiteralStringEscape"/>
|
||||
</rule>
|
||||
<rule pattern="[^\\"\n]+">
|
||||
<token type="Name"/>
|
||||
</rule>
|
||||
<rule pattern=""">
|
||||
<token type="Name"/>
|
||||
<pop depth="1"/>
|
||||
</rule>
|
||||
<rule pattern="\\">
|
||||
<token type="Name"/>
|
||||
</rule>
|
||||
</state>
|
||||
<state name="root">
|
||||
<!-- Whitespace -->
|
||||
<rule pattern="\n">
|
||||
<token type="TextWhitespace"/>
|
||||
</rule>
|
||||
<rule pattern="\s+">
|
||||
<token type="TextWhitespace"/>
|
||||
</rule>
|
||||
<rule pattern="//.*?\n">
|
||||
<!-- Comments -->
|
||||
<rule pattern="//!.*$">
|
||||
<token type="CommentSpecial"/>
|
||||
</rule>
|
||||
<rule pattern="///.*$">
|
||||
<token type="CommentSpecial"/>
|
||||
</rule>
|
||||
<rule pattern="//.*$">
|
||||
<token type="CommentSingle"/>
|
||||
</rule>
|
||||
<rule pattern="(unreachable|continue|errdefer|suspend|return|resume|cancel|break|catch|async|await|defer|asm|try)\b">
|
||||
<!-- Statement keywords -->
|
||||
<rule pattern="(break|return|continue|asm|defer|errdefer|unreachable|try|catch|suspend|resume|nosuspend)\b">
|
||||
<token type="Keyword"/>
|
||||
</rule>
|
||||
<rule pattern="(threadlocal|linksection|allowzero|stdcallcc|volatile|comptime|noalias|nakedcc|inline|export|packed|extern|align|const|pub|var)\b">
|
||||
<!-- Storage/reserved keywords -->
|
||||
<rule pattern="(const|var|extern|packed|export|pub|noalias|inline|noinline|comptime|volatile|allowzero|align|addrspace|linksection|threadlocal|callconv)\b">
|
||||
<token type="KeywordReserved"/>
|
||||
</rule>
|
||||
<rule pattern="(struct|union|error|enum)\b">
|
||||
<!-- Structure keywords -->
|
||||
<rule pattern="(struct|enum|union|error|opaque)\b">
|
||||
<token type="Keyword"/>
|
||||
</rule>
|
||||
<!-- Repeat keywords -->
|
||||
<rule pattern="(while|for)\b">
|
||||
<token type="Keyword"/>
|
||||
</rule>
|
||||
<rule pattern="(comptime_float|comptime_int|c_longdouble|c_ulonglong|c_longlong|c_voidi8|noreturn|c_ushort|anyerror|promise|c_short|c_ulong|c_uint|c_long|isize|c_int|usize|void|f128|i128|type|bool|u128|u16|f64|f32|u64|i16|f16|i32|u32|i64|u8|i0|u0)\b">
|
||||
<!-- Type keywords -->
|
||||
<rule pattern="(bool|void|noreturn|type|anyerror|anyopaque|f16|f32|f64|f80|f128|i8|u8|i16|u16|i32|u32|i64|u64|i128|u128|isize|usize|comptime_int|comptime_float|c_char|c_short|c_ushort|c_int|c_uint|c_long|c_ulong|c_longlong|c_ulonglong|c_longdouble)\b">
|
||||
<token type="KeywordType"/>
|
||||
</rule>
|
||||
<rule pattern="(undefined|false|true|null)\b">
|
||||
<!-- Constant keywords -->
|
||||
<rule pattern="(true|false|null|undefined)\b">
|
||||
<token type="KeywordConstant"/>
|
||||
</rule>
|
||||
<rule pattern="(switch|orelse|else|and|if|or)\b">
|
||||
<!-- Conditional keywords -->
|
||||
<rule pattern="(if|else|switch|and|or|orelse)\b">
|
||||
<token type="Keyword"/>
|
||||
</rule>
|
||||
<rule pattern="(usingnamespace|test|fn)\b">
|
||||
<!-- Other keywords -->
|
||||
<rule pattern="(fn|test|anyframe|anytype)\b">
|
||||
<token type="Keyword"/>
|
||||
</rule>
|
||||
<rule pattern="0x[0-9a-fA-F]+\.[0-9a-fA-F]+([pP][\-+]?[0-9a-fA-F]+)?">
|
||||
<!-- Hex float -->
|
||||
<rule pattern="0x[0-9a-fA-F][0-9a-fA-F_]*(?:\.[0-9a-fA-F][0-9a-fA-F_]*(?:[pP][-+]?[0-9][0-9_]*)?|[pP][-+]?[0-9][0-9_]*)">
|
||||
<token type="LiteralNumberFloat"/>
|
||||
</rule>
|
||||
<rule pattern="0x[0-9a-fA-F]+\.?[pP][\-+]?[0-9a-fA-F]+">
|
||||
<!-- Decimal float -->
|
||||
<rule pattern="[0-9][0-9_]*(?:\.[0-9][0-9_]*(?:[eE][-+]?[0-9][0-9_]*)?|[eE][-+]?[0-9][0-9_]*)">
|
||||
<token type="LiteralNumberFloat"/>
|
||||
</rule>
|
||||
<rule pattern="[0-9]+\.[0-9]+([eE][-+]?[0-9]+)?">
|
||||
<token type="LiteralNumberFloat"/>
|
||||
</rule>
|
||||
<rule pattern="[0-9]+\.?[eE][-+]?[0-9]+">
|
||||
<token type="LiteralNumberFloat"/>
|
||||
</rule>
|
||||
<rule pattern="0b(?:_?[01])+">
|
||||
<!-- Binary -->
|
||||
<rule pattern="0b[01][01_]*">
|
||||
<token type="LiteralNumberBin"/>
|
||||
</rule>
|
||||
<rule pattern="0o(?:_?[0-7])+">
|
||||
<!-- Octal -->
|
||||
<rule pattern="0o[0-7][0-7_]*">
|
||||
<token type="LiteralNumberOct"/>
|
||||
</rule>
|
||||
<rule pattern="0x(?:_?[0-9a-fA-F])+">
|
||||
<!-- Hex integer -->
|
||||
<rule pattern="0x[0-9a-fA-F][0-9a-fA-F_]*">
|
||||
<token type="LiteralNumberHex"/>
|
||||
</rule>
|
||||
<rule pattern="(?:_?[0-9])+">
|
||||
<!-- Decimal integer -->
|
||||
<rule pattern="[0-9][0-9_]*">
|
||||
<token type="LiteralNumberInteger"/>
|
||||
</rule>
|
||||
<rule pattern="\b[A-Za-z_]\w*(?=\s*\()">
|
||||
<token type="NameFunction"/>
|
||||
<!-- Quoted identifier -->
|
||||
<rule pattern="@"">
|
||||
<token type="Name"/>
|
||||
<push state="quoted_ident"/>
|
||||
</rule>
|
||||
<rule pattern="@[a-zA-Z_]\w*">
|
||||
<!-- Builtin -->
|
||||
<rule pattern="@[a-zA-Z_][a-zA-Z0-9_]*">
|
||||
<token type="NameBuiltin"/>
|
||||
</rule>
|
||||
<rule pattern="[a-zA-Z_]\w*">
|
||||
<!-- Function call -->
|
||||
<rule pattern="[a-zA-Z_][a-zA-Z0-9_]*(?=\s*\()">
|
||||
<token type="NameFunction"/>
|
||||
</rule>
|
||||
<!-- Identifier -->
|
||||
<rule pattern="[a-zA-Z_][a-zA-Z0-9_]*">
|
||||
<token type="Name"/>
|
||||
</rule>
|
||||
<rule pattern="\'\\\'\'">
|
||||
<token type="LiteralStringEscape"/>
|
||||
</rule>
|
||||
<rule pattern="\'\\(|x[a-fA-F0-9]{2}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{6}|[nr\\t\'"])\'">
|
||||
<token type="LiteralStringEscape"/>
|
||||
</rule>
|
||||
<rule pattern="\'[^\\\']\'">
|
||||
<token type="LiteralString"/>
|
||||
<!-- Character literal -->
|
||||
<rule pattern="'(?:\\x[0-9a-fA-F]{2}|\\u\{[0-9a-fA-F]+\}|\\[nrt'"\\]|[^\\'\n])'">
|
||||
<token type="LiteralStringChar"/>
|
||||
</rule>
|
||||
<!-- Multiline string -->
|
||||
<rule pattern="\\\\[^\n]*">
|
||||
<token type="LiteralStringHeredoc"/>
|
||||
</rule>
|
||||
<rule pattern="c\\\\[^\n]*">
|
||||
<token type="LiteralStringHeredoc"/>
|
||||
</rule>
|
||||
<rule pattern="c?"">
|
||||
<!-- String start -->
|
||||
<rule pattern=""">
|
||||
<token type="LiteralString"/>
|
||||
<push state="string"/>
|
||||
</rule>
|
||||
<rule pattern="[+%=><|^!?/\-*&~:]">
|
||||
<!-- 4-char operators -->
|
||||
<rule pattern="<<\|=">
|
||||
<token type="Operator"/>
|
||||
</rule>
|
||||
<rule pattern="[{}()\[\],.;]">
|
||||
<!-- 3-char operators -->
|
||||
<rule pattern="(?:\+%=|-%=|\*%=|\+\|=|-\|=|\*\|=|<<=|>>=|<<\|)">
|
||||
<token type="Operator"/>
|
||||
</rule>
|
||||
<!-- 2-char operators -->
|
||||
<rule pattern="(?:\+\+|\*\*|\|\||<<|>>|\+%|-%|\*%|\+\||-\||\*\||==|!=|<=|>=|\+=|-=|\*=|/=|%=|&=|\|=|\^=|\.\*|\.\?|\.\.)">
|
||||
<token type="Operator"/>
|
||||
</rule>
|
||||
<!-- 1-char operators -->
|
||||
<rule pattern="[+\-*/%&|^~!<>=]">
|
||||
<token type="Operator"/>
|
||||
</rule>
|
||||
<!-- Punctuation -->
|
||||
<rule pattern="\.\.\.">
|
||||
<token type="Punctuation"/>
|
||||
</rule>
|
||||
<rule pattern="=>">
|
||||
<token type="Punctuation"/>
|
||||
</rule>
|
||||
<rule pattern="->">
|
||||
<token type="Punctuation"/>
|
||||
</rule>
|
||||
<rule pattern="[{}()\[\],.;:?]">
|
||||
<token type="Punctuation"/>
|
||||
</rule>
|
||||
</state>
|
||||
</rules>
|
||||
</lexer>
|
||||
</lexer>
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
package lexers
|
||||
|
||||
import (
|
||||
. "github.com/alecthomas/chroma/v2" // nolint
|
||||
)
|
||||
|
||||
// Markless lexer.
|
||||
var Markless = Register(MustNewLexer(
|
||||
&Config{
|
||||
Name: "Markless",
|
||||
Aliases: []string{"mess"},
|
||||
Filenames: []string{"*.mess", "*.markless"},
|
||||
MimeTypes: []string{"text/x-markless"},
|
||||
},
|
||||
marklessRules,
|
||||
))
|
||||
|
||||
func marklessRules() Rules {
|
||||
return Rules{
|
||||
"root": {
|
||||
Include("block"),
|
||||
},
|
||||
// Block directives
|
||||
"block": {
|
||||
Include("header"),
|
||||
Include("ordered-list"),
|
||||
Include("unordered-list"),
|
||||
Include("code-block"),
|
||||
Include("blockquote"),
|
||||
Include("blockquote-header"),
|
||||
Include("align"),
|
||||
Include("comment"),
|
||||
Include("instruction"),
|
||||
Include("embed"),
|
||||
Include("footnote"),
|
||||
Include("horizontal-rule"),
|
||||
Include("paragraph"),
|
||||
},
|
||||
"header": {
|
||||
{`(# )(.*)$`, ByGroups(Keyword, GenericHeading), Push("inline")},
|
||||
{`(##+)(.*)$`, ByGroups(Keyword, GenericSubheading), Push("inline")},
|
||||
},
|
||||
"ordered-list": {
|
||||
{`([0-9]+\.)`, Keyword, nil},
|
||||
},
|
||||
"unordered-list": {
|
||||
{`(- )`, Keyword, nil},
|
||||
},
|
||||
"code-block": {
|
||||
{`(::+)( *)(\w*)([^\n]*)(\n)([\w\W]*?)(^\1$)`, UsingByGroup(3, 6, Keyword, TextWhitespace, NameFunction, String, TextWhitespace, Text, Keyword), nil},
|
||||
},
|
||||
"blockquote": {
|
||||
{`(\| )(.*)$`, ByGroups(Keyword, GenericInserted), nil},
|
||||
},
|
||||
"blockquote-header": {
|
||||
{`(~ )([^|\n]+)(\| )(.*?\n)`, ByGroups(Keyword, NameEntity, Keyword, GenericInserted), Push("inline-blockquote")},
|
||||
{`(~ )(.*)$`, ByGroups(Keyword, NameEntity), nil},
|
||||
},
|
||||
"inline-blockquote": {
|
||||
{`^( +)(\| )(.*$)`, ByGroups(TextWhitespace, Keyword, GenericInserted), nil},
|
||||
Default(Pop(1)),
|
||||
},
|
||||
"align": {
|
||||
{`(\|\|)|(\|<)|(\|>)|(><)`, Keyword, nil},
|
||||
},
|
||||
"comment": {
|
||||
{`(;[; ]).*?$`, CommentSingle, nil},
|
||||
},
|
||||
"instruction": {
|
||||
{`(! )([^ ]+)(.+?)$`, ByGroups(Keyword, NameFunction, NameVariable), nil},
|
||||
},
|
||||
"embed": {
|
||||
{`(\[ )([^ ]+)( )([^,]+)`, ByGroups(Keyword, NameFunction, TextWhitespace, String), Push("embed-options")},
|
||||
},
|
||||
"embed-options": {
|
||||
{`\\.`, Text, nil},
|
||||
{`,`, Punctuation, nil},
|
||||
{`\]?$`, Keyword, Pop(1)},
|
||||
// Generic key or key/value pair
|
||||
{`( *)([^, \]]+)([^,\]]+)?`, ByGroups(TextWhitespace, NameFunction, String), nil},
|
||||
{`.`, Text, nil},
|
||||
},
|
||||
"footnote": {
|
||||
{`(\[)([0-9]+)(\])`, ByGroups(Keyword, NameVariable, Keyword), Push("inline")},
|
||||
},
|
||||
"horizontal-rule": {
|
||||
{`(==+)$`, LiteralOther, nil},
|
||||
},
|
||||
"paragraph": {
|
||||
{` *`, TextWhitespace, Push("inline")},
|
||||
},
|
||||
// Inline directives
|
||||
"inline": {
|
||||
Include("escapes"),
|
||||
Include("dashes"),
|
||||
Include("newline"),
|
||||
Include("italic"),
|
||||
Include("underline"),
|
||||
Include("bold"),
|
||||
Include("strikethrough"),
|
||||
Include("code"),
|
||||
Include("compound"),
|
||||
Include("footnote-reference"),
|
||||
Include("subtext"),
|
||||
Include("subtext"),
|
||||
Include("url"),
|
||||
{`.`, Text, nil},
|
||||
{`\n`, TextWhitespace, Pop(1)},
|
||||
},
|
||||
"escapes": {
|
||||
{`\\.`, Text, nil},
|
||||
},
|
||||
"dashes": {
|
||||
{`-{2,3}`, TextPunctuation, nil},
|
||||
},
|
||||
"newline": {
|
||||
{`-/-`, TextWhitespace, nil},
|
||||
},
|
||||
"italic": {
|
||||
{`(//)(.*?)(\1)`, ByGroups(Keyword, GenericEmph, Keyword), nil},
|
||||
},
|
||||
"underline": {
|
||||
{`(__)(.*?)(\1)`, ByGroups(Keyword, GenericUnderline, Keyword), nil},
|
||||
},
|
||||
"bold": {
|
||||
{`(\*\*)(.*?)(\1)`, ByGroups(Keyword, GenericStrong, Keyword), nil},
|
||||
},
|
||||
"strikethrough": {
|
||||
{`(<-)(.*?)(->)`, ByGroups(Keyword, GenericDeleted, Keyword), nil},
|
||||
},
|
||||
"code": {
|
||||
{"(``+)(.*?)(\\1)", ByGroups(Keyword, LiteralStringBacktick, Keyword), nil},
|
||||
},
|
||||
"compound": {
|
||||
{`(''+)(.*?)(''\()`, ByGroups(Keyword, UsingSelf("inline"), Keyword), Push("compound-options")},
|
||||
},
|
||||
"compound-options": {
|
||||
{`\\.`, Text, nil},
|
||||
{`,`, Punctuation, nil},
|
||||
{`\)`, Keyword, Pop(1)},
|
||||
// Hex Color
|
||||
{` *#[0-9A-Fa-f]{3,6} *`, LiteralNumberHex, nil},
|
||||
// Named Color
|
||||
{` *(indian-red|light-coral|salmon|dark-salmon|light-salmon|crimson|red|firebrick|dark-red|pink|light-pink|hot-pink|deep-pink|medium-violet-red|pale-violet-red|coral|tomato|orange-red|dark-orange|orange|gold|yellow|light-yellow|lemon-chiffon|light-goldenrod-yellow|papayawhip|moccasin|peachpuff|pale-goldenrod|khaki|dark-khaki|lavender|thistle|plum|violet|orchid|fuchsia|magenta|medium-orchid|medium-purple|rebecca-purple|blue-violet|dark-violet|dark-orchid|dark-magenta|purple|indigo|slate-blue|dark-slate-blue|medium-slate-blue|green-yellow|chartreuse|lawn-green|lime|lime-green|pale-green|light-green|medium-spring-green|spring-green|medium-sea-green|sea-green|forest-green|green|dark-green|yellow-green|olive-drab|olive|dark-olive-green|medium-aquamarine|dark-sea-green|light-sea-green|dark-cyan|teal|aqua|cyan|light-cyan|pale-turquoise|aquamarine|turquoise|medium-turquoise|dark-turquoise|cadet-blue|steel-blue|light-steel-blue|powder-blue|light-blue|sky-blue|light-sky-blue|deep-sky-blue|dodger-blue|cornflower-blue|royal-blue|blue|medium-blue|dark-blue|navy|midnight-blue|cornsilk|blanched-almond|bisque|navajo-white|wheat|burlywood|tan|rosy-brown|sandy-brown|goldenrod|dark-goldenrod|peru|chocolate|saddle-brown|sienna|brown|maroon|white|snow|honeydew|mintcream|azure|alice-blue|ghost-white|white-smoke|seashell|beige|oldlace|floral-white|ivory|antique-white|linen|lavenderblush|mistyrose|gainsboro|light-gray|silver|dark-gray|gray|dim-gray|light-slate-gray|slate-gray|dark-slate-gray) *`, LiteralOther, nil},
|
||||
// Named size
|
||||
{` *(microscopic|tiny|small|normal|big|large|huge|gigantic) *`, NameTag, nil},
|
||||
// Options
|
||||
{` *(bold|italic|underline|strikethrough|subtext|supertext|spoiler) *`, NameBuiltin, nil},
|
||||
// URL. Note the missing ) and , in the match.
|
||||
{` *\w[-\w+.]*://[\w$\-_.+!*'(&/:;=?@z%#\\]+ *`, String, nil},
|
||||
// Generic key or key/value pair
|
||||
{`( *)([^, )]+)( [^,)]+)?`, ByGroups(TextWhitespace, NameFunction, String), nil},
|
||||
{`.`, Text, nil},
|
||||
},
|
||||
"footnote-reference": {
|
||||
{`(\[)([0-9]+)(\])`, ByGroups(Keyword, NameVariable, Keyword), nil},
|
||||
},
|
||||
"subtext": {
|
||||
{`(v\()(.*?)(\))`, ByGroups(Keyword, UsingSelf("inline"), Keyword), nil},
|
||||
},
|
||||
"supertext": {
|
||||
{`(\^\()(.*?)(\))`, ByGroups(Keyword, UsingSelf("inline"), Keyword), nil},
|
||||
},
|
||||
"url": {
|
||||
{`\w[-\w+.]*://[\w\$\-_.+!*'()&,/:;=?@z%#\\]+`, String, nil},
|
||||
},
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -101,7 +101,7 @@
|
||||
<entry type="GenericTraceback" style="#c55858"/>
|
||||
|
||||
<!-- Punctuation -->
|
||||
<entry type="Punctuation" style="#bdbdbd"/>
|
||||
<entry type="Punctuation" style="#c17ac8"/>
|
||||
<entry type="Text" style="#bdbdbd"/>
|
||||
<entry type="TextWhitespace" style="#bdbdbd"/>
|
||||
</style>
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@
|
||||
<entry type="GenericTraceback" style="#ff6767"/>
|
||||
|
||||
<!-- Punctuation -->
|
||||
<entry type="Punctuation" style="#edecee"/>
|
||||
<entry type="Punctuation" style="#f694ff"/>
|
||||
<entry type="Text" style="#edecee"/>
|
||||
<entry type="TextWhitespace" style="#edecee"/>
|
||||
</style>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// Package chi is a small, idiomatic and composable router for building HTTP services.
|
||||
//
|
||||
// chi requires Go 1.14 or newer.
|
||||
// chi supports the four most recent major versions of Go.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
|
||||
+2
-7
@@ -2,6 +2,7 @@ package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -29,13 +30,7 @@ func contentEncoding(ce string, charsets ...string) bool {
|
||||
_, ce = split(strings.ToLower(ce), ";")
|
||||
_, ce = split(ce, "charset=")
|
||||
ce, _ = split(ce, ";")
|
||||
for _, c := range charsets {
|
||||
if ce == c {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return slices.Contains(charsets, ce)
|
||||
}
|
||||
|
||||
// Split a string in two parts, cleaning any whitespace.
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@ const RequestIDKey ctxKeyRequestID = 0
|
||||
var RequestIDHeader = "X-Request-Id"
|
||||
|
||||
var prefix string
|
||||
var reqid uint64
|
||||
var reqid atomic.Uint64
|
||||
|
||||
// A quick note on the statistics here: we're trying to calculate the chance that
|
||||
// two randomly generated base62 prefixes will collide. We use the formula from
|
||||
@@ -69,7 +69,7 @@ func RequestID(next http.Handler) http.Handler {
|
||||
ctx := r.Context()
|
||||
requestID := r.Header.Get(RequestIDHeader)
|
||||
if requestID == "" {
|
||||
myid := atomic.AddUint64(&reqid, 1)
|
||||
myid := reqid.Add(1)
|
||||
requestID = fmt.Sprintf("%s-%06d", prefix, myid)
|
||||
}
|
||||
ctx = context.WithValue(ctx, RequestIDKey, requestID)
|
||||
@@ -92,5 +92,5 @@ func GetReqID(ctx context.Context) string {
|
||||
|
||||
// NextRequestID generates the next request ID in the sequence.
|
||||
func NextRequestID() uint64 {
|
||||
return atomic.AddUint64(&reqid, 1)
|
||||
return reqid.Add(1)
|
||||
}
|
||||
|
||||
+1
@@ -79,6 +79,7 @@ func (hr HeaderRouter) Handler(next http.Handler) http.Handler {
|
||||
if len(hr) == 0 {
|
||||
// skip if no routes set
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// find first matching header route, and continue
|
||||
|
||||
+9
-2
@@ -47,15 +47,22 @@ func RedirectSlashes(next http.Handler) http.Handler {
|
||||
} else {
|
||||
path = r.URL.Path
|
||||
}
|
||||
|
||||
if len(path) > 1 && path[len(path)-1] == '/' {
|
||||
// Trim all leading and trailing slashes (e.g., "//evil.com", "/some/path//")
|
||||
path = "/" + strings.Trim(path, "/")
|
||||
// Normalize backslashes to forward slashes to prevent "/\evil.com" style redirects
|
||||
// that some clients may interpret as protocol-relative.
|
||||
path = strings.ReplaceAll(path, `\`, `/`)
|
||||
|
||||
// Collapse leading/trailing slashes and force a single leading slash.
|
||||
path := "/" + strings.Trim(path, "/")
|
||||
|
||||
if r.URL.RawQuery != "" {
|
||||
path = fmt.Sprintf("%s?%s", path, r.URL.RawQuery)
|
||||
}
|
||||
http.Redirect(w, r, path, 301)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
|
||||
+4
-2
@@ -467,8 +467,10 @@ func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Find the route
|
||||
if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil {
|
||||
if supportsPathValue {
|
||||
setPathValue(rctx, r)
|
||||
// Set http.Request path values from our request context
|
||||
for i, key := range rctx.URLParams.Keys {
|
||||
value := rctx.URLParams.Values[i]
|
||||
r.SetPathValue(key, value)
|
||||
}
|
||||
if supportsPattern {
|
||||
setPattern(rctx, r)
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
//go:build go1.22 && !tinygo
|
||||
// +build go1.22,!tinygo
|
||||
|
||||
|
||||
package chi
|
||||
|
||||
import "net/http"
|
||||
|
||||
// supportsPathValue is true if the Go version is 1.22 and above.
|
||||
//
|
||||
// If this is true, `net/http.Request` has methods `SetPathValue` and `PathValue`.
|
||||
const supportsPathValue = true
|
||||
|
||||
// setPathValue sets the path values in the Request value
|
||||
// based on the provided request context.
|
||||
func setPathValue(rctx *Context, r *http.Request) {
|
||||
for i, key := range rctx.URLParams.Keys {
|
||||
value := rctx.URLParams.Values[i]
|
||||
r.SetPathValue(key, value)
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
//go:build !go1.22 || tinygo
|
||||
// +build !go1.22 tinygo
|
||||
|
||||
package chi
|
||||
|
||||
import "net/http"
|
||||
|
||||
// supportsPathValue is true if the Go version is 1.22 and above.
|
||||
//
|
||||
// If this is true, `net/http.Request` has methods `SetPathValue` and `PathValue`.
|
||||
const supportsPathValue = false
|
||||
|
||||
// setPathValue sets the path values in the Request value
|
||||
// based on the provided request context.
|
||||
//
|
||||
// setPathValue is only supported in Go 1.22 and above so
|
||||
// this is just a blank function so that it compiles.
|
||||
func setPathValue(rctx *Context, r *http.Request) {
|
||||
}
|
||||
+7
-14
@@ -71,6 +71,7 @@ func RegisterMethod(method string) {
|
||||
}
|
||||
mt := methodTyp(2 << n)
|
||||
methodMap[method] = mt
|
||||
reverseMethodMap[mt] = method
|
||||
mALL |= mt
|
||||
}
|
||||
|
||||
@@ -328,7 +329,7 @@ func (n *node) replaceChild(label, tail byte, child *node) {
|
||||
|
||||
func (n *node) getEdge(ntyp nodeTyp, label, tail byte, prefix string) *node {
|
||||
nds := n.children[ntyp]
|
||||
for i := 0; i < len(nds); i++ {
|
||||
for i := range nds {
|
||||
if nds[i].label == label && nds[i].tail == tail {
|
||||
if ntyp == ntRegexp && nds[i].prefix != prefix {
|
||||
continue
|
||||
@@ -429,9 +430,7 @@ func (n *node) findRoute(rctx *Context, method methodTyp, path string) *node {
|
||||
}
|
||||
|
||||
// serially loop through each node grouped by the tail delimiter
|
||||
for idx := 0; idx < len(nds); idx++ {
|
||||
xn = nds[idx]
|
||||
|
||||
for _, xn = range nds {
|
||||
// label for param nodes is the delimiter byte
|
||||
p := strings.IndexByte(xsearch, xn.tail)
|
||||
|
||||
@@ -770,20 +769,14 @@ func patParamKeys(pattern string) []string {
|
||||
}
|
||||
}
|
||||
|
||||
// longestPrefix finds the length of the shared prefix
|
||||
// of two strings
|
||||
func longestPrefix(k1, k2 string) int {
|
||||
max := len(k1)
|
||||
if l := len(k2); l < max {
|
||||
max = l
|
||||
}
|
||||
var i int
|
||||
for i = 0; i < max; i++ {
|
||||
// longestPrefix finds the length of the shared prefix of two strings
|
||||
func longestPrefix(k1, k2 string) (i int) {
|
||||
for i = 0; i < min(len(k1), len(k2)); i++ {
|
||||
if k1[i] != k2[i] {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i
|
||||
return
|
||||
}
|
||||
|
||||
type nodes []*node
|
||||
|
||||
+2
@@ -19,6 +19,8 @@ linters:
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- modernize
|
||||
- testifylint
|
||||
settings:
|
||||
goconst:
|
||||
min-len: 2
|
||||
|
||||
+141
@@ -143,6 +143,22 @@ The `Rewrite` middleware is designed to rewrite the URL path based on a given ru
|
||||
|
||||
For example, `Rewrite("^/sites/(.*)/settings/$", "/sites/settings/$1")` will change request's URL from `/sites/id1/settings/` to `/sites/settings/id1`
|
||||
|
||||
### CleanPath middleware
|
||||
|
||||
Cleans double slashes from URL path. For example, requests to `/users//1` or `//users////1` will be cleaned to `/users/1` before routing. Trailing slashes are preserved: `/api//v1/` becomes `/api/v1/`. Note: dot segments (`.` and `..`) are intentionally not cleaned to preserve routing semantics.
|
||||
|
||||
```go
|
||||
router.Use(rest.CleanPath)
|
||||
```
|
||||
|
||||
### StripSlashes middleware
|
||||
|
||||
Removes trailing slashes from URL path. For example, `/users/` becomes `/users`. The root path `/` is preserved.
|
||||
|
||||
```go
|
||||
router.Use(rest.StripSlashes)
|
||||
```
|
||||
|
||||
### NoCache middleware
|
||||
|
||||
Sets a number of HTTP headers to prevent a router (handler's) response from being cached by an upstream proxy and/or client.
|
||||
@@ -166,6 +182,131 @@ RealIP is a middleware that sets a http.Request's RemoteAddr to the results of p
|
||||
|
||||
Only public IPs are accepted from headers; private/loopback/link-local IPs are skipped. This makes the middleware compatible with CDN setups like Cloudflare where the leftmost IP in `X-Forwarded-For` is the actual client.
|
||||
|
||||
### CORS middleware
|
||||
|
||||
Handles Cross-Origin Resource Sharing, allowing controlled access from different origins.
|
||||
|
||||
```go
|
||||
// allow all origins (default)
|
||||
router.Use(rest.CORS())
|
||||
|
||||
// specific origins with credentials
|
||||
router.Use(rest.CORS(
|
||||
rest.CorsAllowedOrigins("https://app.example.com", "https://admin.example.com"),
|
||||
rest.CorsAllowCredentials(true),
|
||||
rest.CorsMaxAge(86400),
|
||||
))
|
||||
|
||||
// full configuration
|
||||
router.Use(rest.CORS(
|
||||
rest.CorsAllowedOrigins("https://app.example.com"),
|
||||
rest.CorsAllowedMethods("GET", "POST", "PUT", "DELETE"),
|
||||
rest.CorsAllowedHeaders("Authorization", "Content-Type", "X-Custom-Header"),
|
||||
rest.CorsExposedHeaders("X-Request-Id", "X-Total-Count"),
|
||||
rest.CorsAllowCredentials(true),
|
||||
rest.CorsMaxAge(3600),
|
||||
))
|
||||
```
|
||||
|
||||
Features:
|
||||
- Automatic preflight (OPTIONS) handling
|
||||
- Origin validation with case-insensitive matching
|
||||
- Credentials support (reflects origin instead of `*`)
|
||||
- Configurable cache duration for preflight results
|
||||
|
||||
Available options:
|
||||
- `CorsAllowedOrigins(origins...)` - allowed origins (default: `*`)
|
||||
- `CorsAllowedMethods(methods...)` - allowed HTTP methods (default: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD)
|
||||
- `CorsAllowedHeaders(headers...)` - allowed request headers (default: Accept, Content-Type, Authorization, X-Requested-With)
|
||||
- `CorsExposedHeaders(headers...)` - headers exposed to client
|
||||
- `CorsAllowCredentials(bool)` - enable credentials (cookies, auth headers)
|
||||
- `CorsMaxAge(seconds)` - preflight cache duration
|
||||
|
||||
### Secure middleware
|
||||
|
||||
Adds security headers to responses. By default sets: `X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`, `X-XSS-Protection`, and `Strict-Transport-Security` (for HTTPS only).
|
||||
|
||||
```go
|
||||
// with sensible defaults
|
||||
router.Use(rest.Secure())
|
||||
|
||||
// with full security headers for web apps (adds CSP and Permissions-Policy)
|
||||
router.Use(rest.Secure(rest.SecAllHeaders()))
|
||||
|
||||
// with custom options
|
||||
router.Use(rest.Secure(
|
||||
rest.SecFrameOptions("SAMEORIGIN"),
|
||||
rest.SecReferrerPolicy("no-referrer"),
|
||||
rest.SecHSTS(86400, true, true),
|
||||
rest.SecContentSecurityPolicy("default-src 'self'"),
|
||||
rest.SecPermissionsPolicy("geolocation=(), camera=()"),
|
||||
))
|
||||
```
|
||||
|
||||
Default headers:
|
||||
- `X-Frame-Options: DENY` - prevents clickjacking
|
||||
- `X-Content-Type-Options: nosniff` - prevents MIME-type sniffing
|
||||
- `Referrer-Policy: strict-origin-when-cross-origin` - controls referrer information
|
||||
- `X-XSS-Protection: 1; mode=block` - enables XSS filtering (legacy browsers)
|
||||
- `Strict-Transport-Security: max-age=31536000; includeSubDomains` - enforces HTTPS (only sent over HTTPS)
|
||||
|
||||
Available options:
|
||||
- `SecFrameOptions(value)` - set X-Frame-Options (DENY, SAMEORIGIN)
|
||||
- `SecContentTypeNosniff(enable)` - enable/disable nosniff
|
||||
- `SecReferrerPolicy(policy)` - set Referrer-Policy
|
||||
- `SecContentSecurityPolicy(policy)` - set Content-Security-Policy
|
||||
- `SecPermissionsPolicy(policy)` - set Permissions-Policy
|
||||
- `SecHSTS(maxAge, includeSubdomains, preload)` - configure HSTS
|
||||
- `SecXSSProtection(value)` - set X-XSS-Protection
|
||||
- `SecAllHeaders()` - convenience option that sets CSP and Permissions-Policy with restrictive defaults
|
||||
|
||||
### CSRF middleware
|
||||
|
||||
Provides Cross-Site Request Forgery protection using modern browser Fetch metadata headers (`Sec-Fetch-Site`, `Origin`). For Go 1.25+, this wraps the stdlib's `http.CrossOriginProtection`. For earlier versions, a compatible custom implementation is used.
|
||||
|
||||
```go
|
||||
// basic protection
|
||||
protection := rest.NewCrossOriginProtection()
|
||||
router.Use(protection.Handler)
|
||||
|
||||
// with trusted origins for cross-origin requests
|
||||
protection := rest.NewCrossOriginProtection()
|
||||
if err := protection.AddTrustedOrigin("https://mobile.example.com"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := protection.AddTrustedOrigin("https://admin.example.com"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
router.Use(protection.Handler)
|
||||
|
||||
// with bypass patterns for webhooks or OAuth
|
||||
protection := rest.NewCrossOriginProtection()
|
||||
protection.AddBypassPattern("/api/webhook")
|
||||
protection.AddBypassPattern("/oauth/")
|
||||
router.Use(protection.Handler)
|
||||
|
||||
// with custom deny handler
|
||||
protection := rest.NewCrossOriginProtection()
|
||||
protection.SetDenyHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "CSRF validation failed", http.StatusForbidden)
|
||||
}))
|
||||
router.Use(protection.Handler)
|
||||
```
|
||||
|
||||
How it works:
|
||||
- Safe methods (GET, HEAD, OPTIONS) are always allowed
|
||||
- Checks `Sec-Fetch-Site` header for "same-origin" or "none"
|
||||
- Falls back to comparing `Origin` header with request `Host`
|
||||
- Requests without these headers are assumed same-origin (non-browser clients)
|
||||
|
||||
Available methods:
|
||||
- `NewCrossOriginProtection()` - creates new CSRF protection middleware
|
||||
- `AddTrustedOrigin(origin)` - adds origin allowed for cross-origin requests (format: "scheme://host[:port]")
|
||||
- `AddBypassPattern(pattern)` - adds URL pattern that bypasses protection (for webhooks, OAuth, etc.)
|
||||
- `SetDenyHandler(handler)` - sets custom handler for rejected requests (default: 403 Forbidden)
|
||||
- `Check(request)` - manually validates a request, returns error if blocked
|
||||
- `Handler(handler)` - wraps an http.Handler with CSRF protection
|
||||
|
||||
### Maybe middleware
|
||||
|
||||
Maybe middleware allows changing the flow of the middleware stack execution depending on the return
|
||||
|
||||
+1
-4
@@ -156,10 +156,7 @@ func (b *Benchmarks) Stats(interval time.Duration) BenchmarkStats {
|
||||
}
|
||||
|
||||
// ensure we calculate rate based on actual interval
|
||||
actualInterval := fnInterval.Sub(stInterval)
|
||||
if actualInterval < time.Second {
|
||||
actualInterval = time.Second
|
||||
}
|
||||
actualInterval := max(fnInterval.Sub(stInterval), time.Second)
|
||||
|
||||
return BenchmarkStats{
|
||||
Requests: requests,
|
||||
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CORSConfig defines CORS middleware configuration.
|
||||
// Use CorsOpt functions to customize.
|
||||
type CORSConfig struct {
|
||||
// AllowedOrigins is a list of origins that may access the resource.
|
||||
// use "*" to allow all origins (not recommended with credentials).
|
||||
// default: ["*"]
|
||||
AllowedOrigins []string
|
||||
// AllowedMethods is a list of methods the client is allowed to use.
|
||||
// default: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD
|
||||
AllowedMethods []string
|
||||
// AllowedHeaders is a list of headers the client is allowed to send.
|
||||
// default: Accept, Content-Type, Authorization, X-Requested-With
|
||||
AllowedHeaders []string
|
||||
// ExposedHeaders is a list of headers that are safe to expose to the client.
|
||||
// default: empty
|
||||
ExposedHeaders []string
|
||||
// AllowCredentials indicates whether the request can include credentials.
|
||||
// when true, AllowedOrigins cannot be "*" (browser security restriction).
|
||||
// default: false
|
||||
AllowCredentials bool
|
||||
// MaxAge indicates how long (in seconds) the results of a preflight can be cached.
|
||||
// default: 0 (no caching)
|
||||
MaxAge int
|
||||
}
|
||||
|
||||
// CorsOpt is a functional option for CORSConfig
|
||||
type CorsOpt func(*CORSConfig)
|
||||
|
||||
// defaultCORSConfig returns config with sensible defaults
|
||||
func defaultCORSConfig() CORSConfig {
|
||||
return CORSConfig{
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"},
|
||||
AllowedHeaders: []string{"Accept", "Content-Type", "Authorization", "X-Requested-With"},
|
||||
ExposedHeaders: []string{},
|
||||
AllowCredentials: false,
|
||||
MaxAge: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// CorsAllowedOrigins sets the list of allowed origins.
|
||||
// Use "*" to allow all origins (not recommended with credentials).
|
||||
func CorsAllowedOrigins(origins ...string) CorsOpt {
|
||||
return func(c *CORSConfig) {
|
||||
c.AllowedOrigins = origins
|
||||
}
|
||||
}
|
||||
|
||||
// CorsAllowedMethods sets the list of allowed HTTP methods.
|
||||
func CorsAllowedMethods(methods ...string) CorsOpt {
|
||||
return func(c *CORSConfig) {
|
||||
c.AllowedMethods = methods
|
||||
}
|
||||
}
|
||||
|
||||
// CorsAllowedHeaders sets the list of allowed request headers.
|
||||
func CorsAllowedHeaders(headers ...string) CorsOpt {
|
||||
return func(c *CORSConfig) {
|
||||
c.AllowedHeaders = headers
|
||||
}
|
||||
}
|
||||
|
||||
// CorsExposedHeaders sets the list of headers exposed to the client.
|
||||
func CorsExposedHeaders(headers ...string) CorsOpt {
|
||||
return func(c *CORSConfig) {
|
||||
c.ExposedHeaders = headers
|
||||
}
|
||||
}
|
||||
|
||||
// CorsAllowCredentials enables or disables credentials.
|
||||
// When true, AllowedOrigins cannot be "*".
|
||||
func CorsAllowCredentials(allow bool) CorsOpt {
|
||||
return func(c *CORSConfig) {
|
||||
c.AllowCredentials = allow
|
||||
}
|
||||
}
|
||||
|
||||
// CorsMaxAge sets how long (in seconds) preflight results can be cached.
|
||||
func CorsMaxAge(seconds int) CorsOpt {
|
||||
return func(c *CORSConfig) {
|
||||
c.MaxAge = seconds
|
||||
}
|
||||
}
|
||||
|
||||
// CORS is middleware that handles Cross-Origin Resource Sharing.
|
||||
// It handles preflight OPTIONS requests and sets appropriate headers.
|
||||
// By default allows all origins with common methods and headers.
|
||||
func CORS(opts ...CorsOpt) func(http.Handler) http.Handler {
|
||||
cfg := defaultCORSConfig()
|
||||
for _, opt := range opts {
|
||||
opt(&cfg)
|
||||
}
|
||||
|
||||
// pre-compute joined strings for performance
|
||||
methodsStr := strings.Join(cfg.AllowedMethods, ", ")
|
||||
headersStr := strings.Join(cfg.AllowedHeaders, ", ")
|
||||
exposedStr := strings.Join(cfg.ExposedHeaders, ", ")
|
||||
|
||||
// check if wildcard is used
|
||||
allowAll := len(cfg.AllowedOrigins) == 1 && cfg.AllowedOrigins[0] == "*"
|
||||
|
||||
// build origin lookup for O(1) check (only when not allowing all)
|
||||
var originSet map[string]bool
|
||||
if !allowAll {
|
||||
originSet = make(map[string]bool, len(cfg.AllowedOrigins))
|
||||
for _, o := range cfg.AllowedOrigins {
|
||||
originSet[strings.ToLower(o)] = true
|
||||
}
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
origin := r.Header.Get("Origin")
|
||||
|
||||
// no origin header means same-origin or non-browser request
|
||||
if origin == "" {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// check if origin is allowed
|
||||
var allowed bool
|
||||
if allowAll {
|
||||
allowed = true
|
||||
} else {
|
||||
allowed = originSet[strings.ToLower(origin)]
|
||||
}
|
||||
if !allowed {
|
||||
// origin not allowed, proceed without CORS headers
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// set Vary header for caching
|
||||
w.Header().Add("Vary", "Origin")
|
||||
|
||||
// set allowed origin
|
||||
if allowAll && !cfg.AllowCredentials {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
} else {
|
||||
// reflect the specific origin (required for credentials)
|
||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
}
|
||||
|
||||
// set credentials header if enabled
|
||||
if cfg.AllowCredentials {
|
||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
}
|
||||
|
||||
// handle preflight request
|
||||
if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
|
||||
// preflight request
|
||||
w.Header().Set("Access-Control-Allow-Methods", methodsStr)
|
||||
w.Header().Set("Access-Control-Allow-Headers", headersStr)
|
||||
|
||||
if cfg.MaxAge > 0 {
|
||||
w.Header().Set("Access-Control-Max-Age", strconv.Itoa(cfg.MaxAge))
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
// actual request - set exposed headers
|
||||
if exposedStr != "" {
|
||||
w.Header().Set("Access-Control-Expose-Headers", exposedStr)
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
//go:build !go1.25
|
||||
|
||||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// CrossOriginProtection provides CSRF protection using modern browser Fetch metadata.
|
||||
// It validates requests using Sec-Fetch-Site and Origin headers, rejecting cross-origin
|
||||
// state-changing requests. Safe methods (GET, HEAD, OPTIONS) are always allowed.
|
||||
//
|
||||
// For Go 1.25+, this wraps the stdlib http.CrossOriginProtection.
|
||||
// For earlier versions, it provides an equivalent custom implementation.
|
||||
type CrossOriginProtection struct {
|
||||
mu sync.RWMutex
|
||||
trustedOrigins map[string]bool
|
||||
bypassPatterns []string
|
||||
denyHandler http.Handler
|
||||
}
|
||||
|
||||
// NewCrossOriginProtection creates a new CSRF protection middleware.
|
||||
func NewCrossOriginProtection() *CrossOriginProtection {
|
||||
return &CrossOriginProtection{
|
||||
trustedOrigins: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// AddTrustedOrigin adds an origin that should be allowed to make cross-origin requests.
|
||||
// The origin must be in the format "scheme://host" or "scheme://host:port".
|
||||
// Returns an error if the origin format is invalid.
|
||||
func (c *CrossOriginProtection) AddTrustedOrigin(origin string) error {
|
||||
u, err := url.Parse(origin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid origin: %w", err)
|
||||
}
|
||||
if u.Scheme == "" || u.Host == "" {
|
||||
return fmt.Errorf("origin must have scheme and host: %s", origin)
|
||||
}
|
||||
if u.Path != "" && u.Path != "/" {
|
||||
return fmt.Errorf("origin must not have path: %s", origin)
|
||||
}
|
||||
if u.RawQuery != "" || u.Fragment != "" {
|
||||
return fmt.Errorf("origin must not have query or fragment: %s", origin)
|
||||
}
|
||||
|
||||
normalized := strings.ToLower(u.Scheme) + "://" + strings.ToLower(u.Host)
|
||||
|
||||
c.mu.Lock()
|
||||
c.trustedOrigins[normalized] = true
|
||||
c.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddBypassPattern adds a URL pattern that should bypass CSRF protection.
|
||||
// Patterns follow the same syntax as http.ServeMux (e.g., "/api/webhook", "/oauth/").
|
||||
// Use sparingly and only for endpoints that have alternative authentication.
|
||||
func (c *CrossOriginProtection) AddBypassPattern(pattern string) {
|
||||
c.mu.Lock()
|
||||
c.bypassPatterns = append(c.bypassPatterns, pattern)
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// SetDenyHandler sets a custom handler for rejected requests.
|
||||
// If not set, rejected requests receive a 403 Forbidden response.
|
||||
func (c *CrossOriginProtection) SetDenyHandler(h http.Handler) {
|
||||
c.mu.Lock()
|
||||
c.denyHandler = h
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// Check validates a request against CSRF protection rules.
|
||||
// Returns nil if the request is allowed, or an error describing why it was rejected.
|
||||
func (c *CrossOriginProtection) Check(r *http.Request) error {
|
||||
// safe methods are always allowed
|
||||
if isSafeMethod(r.Method) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check bypass patterns
|
||||
if c.matchesBypassPattern(r.URL.Path) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check Sec-Fetch-Site header (modern browsers)
|
||||
secFetchSite := r.Header.Get("Sec-Fetch-Site")
|
||||
if secFetchSite != "" {
|
||||
switch secFetchSite {
|
||||
case "same-origin", "none":
|
||||
return nil
|
||||
case "cross-site", "same-site":
|
||||
// check if origin is trusted
|
||||
origin := r.Header.Get("Origin")
|
||||
if origin != "" && c.isOriginTrusted(origin) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("cross-origin request blocked: Sec-Fetch-Site=%s", secFetchSite)
|
||||
}
|
||||
}
|
||||
|
||||
// fallback: check Origin header against Host
|
||||
origin := r.Header.Get("Origin")
|
||||
if origin != "" {
|
||||
// check if origin is trusted
|
||||
if c.isOriginTrusted(origin) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// compare origin host with request host
|
||||
originURL, err := url.Parse(origin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid Origin header: %w", err)
|
||||
}
|
||||
|
||||
requestHost := r.Host
|
||||
if requestHost == "" {
|
||||
requestHost = r.URL.Host
|
||||
}
|
||||
|
||||
// normalize hosts for comparison
|
||||
originHost := strings.ToLower(originURL.Host)
|
||||
requestHost = strings.ToLower(requestHost)
|
||||
|
||||
if originHost != requestHost {
|
||||
return fmt.Errorf("cross-origin request blocked: origin %s does not match host %s", originHost, requestHost)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// no Sec-Fetch-Site or Origin headers - assume same-origin or non-browser request
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handler wraps an http.Handler with CSRF protection.
|
||||
// Rejected requests receive a 403 Forbidden response (or custom deny handler).
|
||||
func (c *CrossOriginProtection) Handler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := c.Check(r); err != nil {
|
||||
c.mu.RLock()
|
||||
deny := c.denyHandler
|
||||
c.mu.RUnlock()
|
||||
|
||||
if deny != nil {
|
||||
deny.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
http.Error(w, "Forbidden - CSRF check failed", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// isSafeMethod returns true for HTTP methods that don't modify state.
|
||||
func isSafeMethod(method string) bool {
|
||||
switch method {
|
||||
case http.MethodGet, http.MethodHead, http.MethodOptions:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isOriginTrusted checks if the origin is in the trusted list.
|
||||
func (c *CrossOriginProtection) isOriginTrusted(origin string) bool {
|
||||
u, err := url.Parse(origin)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
normalized := strings.ToLower(u.Scheme) + "://" + strings.ToLower(u.Host)
|
||||
|
||||
c.mu.RLock()
|
||||
trusted := c.trustedOrigins[normalized]
|
||||
c.mu.RUnlock()
|
||||
return trusted
|
||||
}
|
||||
|
||||
// matchesBypassPattern checks if the path matches any bypass pattern.
|
||||
func (c *CrossOriginProtection) matchesBypassPattern(path string) bool {
|
||||
c.mu.RLock()
|
||||
patterns := make([]string, len(c.bypassPatterns))
|
||||
copy(patterns, c.bypassPatterns)
|
||||
c.mu.RUnlock()
|
||||
|
||||
for _, pattern := range patterns {
|
||||
if matchPattern(pattern, path) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// matchPattern implements simple pattern matching similar to http.ServeMux.
|
||||
func matchPattern(pattern, path string) bool {
|
||||
// exact match
|
||||
if pattern == path {
|
||||
return true
|
||||
}
|
||||
// prefix match for patterns ending with /
|
||||
if strings.HasSuffix(pattern, "/") && strings.HasPrefix(path, pattern) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
//go:build go1.25
|
||||
|
||||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CrossOriginProtection provides CSRF protection using modern browser Fetch metadata.
|
||||
// It validates requests using Sec-Fetch-Site and Origin headers, rejecting cross-origin
|
||||
// state-changing requests. Safe methods (GET, HEAD, OPTIONS) are always allowed.
|
||||
//
|
||||
// For Go 1.25+, this wraps the stdlib http.CrossOriginProtection.
|
||||
// For earlier versions, it provides an equivalent custom implementation.
|
||||
type CrossOriginProtection struct {
|
||||
stdlib *http.CrossOriginProtection
|
||||
}
|
||||
|
||||
// NewCrossOriginProtection creates a new CSRF protection middleware.
|
||||
func NewCrossOriginProtection() *CrossOriginProtection {
|
||||
return &CrossOriginProtection{
|
||||
stdlib: http.NewCrossOriginProtection(),
|
||||
}
|
||||
}
|
||||
|
||||
// AddTrustedOrigin adds an origin that should be allowed to make cross-origin requests.
|
||||
// The origin must be in the format "scheme://host" or "scheme://host:port".
|
||||
// Returns an error if the origin format is invalid.
|
||||
func (c *CrossOriginProtection) AddTrustedOrigin(origin string) error {
|
||||
u, err := url.Parse(origin)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid origin: %w", err)
|
||||
}
|
||||
if u.Scheme == "" || u.Host == "" {
|
||||
return fmt.Errorf("origin must have scheme and host: %s", origin)
|
||||
}
|
||||
if u.Path != "" && u.Path != "/" {
|
||||
return fmt.Errorf("origin must not have path: %s", origin)
|
||||
}
|
||||
if u.RawQuery != "" || u.Fragment != "" {
|
||||
return fmt.Errorf("origin must not have query or fragment: %s", origin)
|
||||
}
|
||||
|
||||
// normalize to lowercase for consistent case-insensitive matching
|
||||
normalized := strings.ToLower(u.Scheme) + "://" + strings.ToLower(u.Host)
|
||||
return c.stdlib.AddTrustedOrigin(normalized)
|
||||
}
|
||||
|
||||
// AddBypassPattern adds a URL pattern that should bypass CSRF protection.
|
||||
// Patterns follow the same syntax as http.ServeMux (e.g., "/api/webhook", "/oauth/").
|
||||
// Use sparingly and only for endpoints that have alternative authentication.
|
||||
func (c *CrossOriginProtection) AddBypassPattern(pattern string) {
|
||||
c.stdlib.AddInsecureBypassPattern(pattern)
|
||||
}
|
||||
|
||||
// SetDenyHandler sets a custom handler for rejected requests.
|
||||
// If not set, rejected requests receive a 403 Forbidden response.
|
||||
func (c *CrossOriginProtection) SetDenyHandler(h http.Handler) {
|
||||
c.stdlib.SetDenyHandler(h)
|
||||
}
|
||||
|
||||
// Check validates a request against CSRF protection rules.
|
||||
// Returns nil if the request is allowed, or an error describing why it was rejected.
|
||||
func (c *CrossOriginProtection) Check(r *http.Request) error {
|
||||
// the stdlib Check method panics or returns void, so we use our own check logic
|
||||
// by creating a test handler and seeing if it gets called
|
||||
|
||||
// safe methods are always allowed
|
||||
switch r.Method {
|
||||
case http.MethodGet, http.MethodHead, http.MethodOptions:
|
||||
return nil
|
||||
}
|
||||
|
||||
// use a test to determine if request would be allowed
|
||||
allowed := false
|
||||
testHandler := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
|
||||
allowed = true
|
||||
})
|
||||
|
||||
// create a response recorder to capture the result
|
||||
rec := &discardResponseWriter{}
|
||||
c.stdlib.Handler(testHandler).ServeHTTP(rec, r)
|
||||
|
||||
if !allowed {
|
||||
return fmt.Errorf("cross-origin request blocked by CSRF protection")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handler wraps an http.Handler with CSRF protection.
|
||||
// Rejected requests receive a 403 Forbidden response (or custom deny handler).
|
||||
func (c *CrossOriginProtection) Handler(h http.Handler) http.Handler {
|
||||
return c.stdlib.Handler(h)
|
||||
}
|
||||
|
||||
// discardResponseWriter is a minimal ResponseWriter for testing.
|
||||
type discardResponseWriter struct {
|
||||
header http.Header
|
||||
}
|
||||
|
||||
func (d *discardResponseWriter) Header() http.Header {
|
||||
if d.header == nil {
|
||||
d.header = make(http.Header)
|
||||
}
|
||||
return d.header
|
||||
}
|
||||
func (d *discardResponseWriter) Write(b []byte) (int, error) { return len(b), nil }
|
||||
func (d *discardResponseWriter) WriteHeader(_ int) {}
|
||||
+1
-1
@@ -20,7 +20,7 @@ var gzDefaultContentTypes = []string{
|
||||
}
|
||||
|
||||
var gzPool = sync.Pool{
|
||||
New: func() interface{} { return gzip.NewWriter(io.Discard) },
|
||||
New: func() any { return gzip.NewWriter(io.Discard) },
|
||||
}
|
||||
|
||||
type gzipResponseWriter struct {
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ type Middleware struct {
|
||||
|
||||
// Backend is logging backend
|
||||
type Backend interface {
|
||||
Logf(format string, args ...interface{})
|
||||
Logf(format string, args ...any)
|
||||
}
|
||||
|
||||
type logParts struct {
|
||||
@@ -51,7 +51,7 @@ type logParts struct {
|
||||
|
||||
type stdBackend struct{}
|
||||
|
||||
func (s stdBackend) Logf(format string, args ...interface{}) {
|
||||
func (s stdBackend) Logf(format string, args ...any) {
|
||||
log.Printf(format, args...)
|
||||
}
|
||||
|
||||
|
||||
+7
-4
@@ -36,14 +36,17 @@ func AppInfo(app, author, version string) func(http.Handler) http.Handler {
|
||||
return f
|
||||
}
|
||||
|
||||
// Ping middleware response with pong to /ping. Stops chain if ping request detected
|
||||
// Ping middleware response with pong to /ping. Stops chain if ping request detected.
|
||||
// Handles both GET and HEAD methods - HEAD returns headers only without body,
|
||||
// which is useful for lightweight health checks by monitoring tools.
|
||||
func Ping(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if r.Method == "GET" && strings.HasSuffix(strings.ToLower(r.URL.Path), "/ping") {
|
||||
if (r.Method == "GET" || r.Method == "HEAD") && strings.HasSuffix(strings.ToLower(r.URL.Path), "/ping") {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("pong"))
|
||||
if r.Method == "GET" {
|
||||
_, _ = w.Write([]byte("pong"))
|
||||
}
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
|
||||
+1
-2
@@ -58,8 +58,7 @@ func Get(r *http.Request) (string, error) {
|
||||
|
||||
// check X-Forwarded-For, find leftmost public IP
|
||||
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
||||
addresses := strings.Split(xff, ",")
|
||||
for _, addr := range addresses {
|
||||
for addr := range strings.SplitSeq(xff, ",") {
|
||||
ip := strings.TrimSpace(addr)
|
||||
if parsedIP := net.ParseIP(ip); isPublicIP(parsedIP) {
|
||||
return ip, nil
|
||||
|
||||
+4
-5
@@ -13,7 +13,7 @@ import (
|
||||
type JSON map[string]any
|
||||
|
||||
// RenderJSON sends data as json
|
||||
func RenderJSON(w http.ResponseWriter, data interface{}) {
|
||||
func RenderJSON(w http.ResponseWriter, data any) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(true)
|
||||
@@ -35,9 +35,8 @@ func RenderJSONFromBytes(w http.ResponseWriter, r *http.Request, data []byte) er
|
||||
}
|
||||
|
||||
// RenderJSONWithHTML allows html tags and forces charset=utf-8
|
||||
func RenderJSONWithHTML(w http.ResponseWriter, r *http.Request, v interface{}) error {
|
||||
|
||||
encodeJSONWithHTML := func(v interface{}) ([]byte, error) {
|
||||
func RenderJSONWithHTML(w http.ResponseWriter, r *http.Request, v any) error {
|
||||
encodeJSONWithHTML := func(v any) ([]byte, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
@@ -55,7 +54,7 @@ func RenderJSONWithHTML(w http.ResponseWriter, r *http.Request, v interface{}) e
|
||||
}
|
||||
|
||||
// renderJSONWithStatus sends data as json and enforces status code
|
||||
func renderJSONWithStatus(w http.ResponseWriter, data interface{}, code int) {
|
||||
func renderJSONWithStatus(w http.ResponseWriter, data any, code int) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(true)
|
||||
|
||||
+73
@@ -9,6 +9,79 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CleanPath middleware cleans double slashes from URL path.
|
||||
// For example, if a request is made to /users//1 or //users////1,
|
||||
// it will be cleaned to /users/1 before routing.
|
||||
// Trailing slashes are preserved: /users//1/ becomes /users/1/.
|
||||
// Dot segments (. and ..) are intentionally NOT cleaned to preserve routing semantics.
|
||||
func CleanPath(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rctx := r.Context()
|
||||
// skip if already cleaned
|
||||
if _, ok := rctx.Value(contextKey("cleanpath")).(bool); ok {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
p := r.URL.Path
|
||||
cleaned := cleanDoubleSlashes(p)
|
||||
|
||||
if cleaned != p {
|
||||
r.URL.Path = cleaned
|
||||
if r.URL.RawPath != "" {
|
||||
// clean double slashes in RawPath separately to preserve percent-encoding
|
||||
r.URL.RawPath = cleanDoubleSlashes(r.URL.RawPath)
|
||||
}
|
||||
rctx = context.WithValue(rctx, contextKey("cleanpath"), true)
|
||||
r = r.WithContext(rctx)
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// cleanDoubleSlashes removes consecutive slashes from path while preserving
|
||||
// trailing slashes and dot segments (. and ..).
|
||||
func cleanDoubleSlashes(p string) string {
|
||||
if p == "" || p == "/" {
|
||||
return p
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
b.Grow(len(p))
|
||||
|
||||
prevSlash := false
|
||||
for i := 0; i < len(p); i++ {
|
||||
c := p[i]
|
||||
if c == '/' {
|
||||
if !prevSlash {
|
||||
b.WriteByte(c)
|
||||
}
|
||||
prevSlash = true
|
||||
} else {
|
||||
b.WriteByte(c)
|
||||
prevSlash = false
|
||||
}
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// StripSlashes middleware removes trailing slashes from URL path.
|
||||
// For example, /users/1/ becomes /users/1.
|
||||
// The root path "/" is preserved.
|
||||
func StripSlashes(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
p := r.URL.Path
|
||||
if len(p) > 1 && p[len(p)-1] == '/' {
|
||||
r.URL.Path = p[:len(p)-1]
|
||||
if r.URL.RawPath != "" {
|
||||
r.URL.RawPath = strings.TrimSuffix(r.URL.RawPath, "/")
|
||||
}
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// Rewrite middleware with from->to rule. Supports regex (like nginx) and prevents multiple rewrites
|
||||
// example: Rewrite(`^/sites/(.*)/settings/$`, `/sites/settings/$1`
|
||||
func Rewrite(from, to string) func(http.Handler) http.Handler {
|
||||
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SecureConfig defines security headers configuration.
|
||||
// Use SecOpt functions to customize.
|
||||
type SecureConfig struct {
|
||||
// xFrameOptions sets X-Frame-Options header. Default: DENY
|
||||
XFrameOptions string
|
||||
// xContentTypeOptions sets X-Content-Type-Options. Default: nosniff
|
||||
XContentTypeOptions string
|
||||
// ReferrerPolicy sets Referrer-Policy header. Default: strict-origin-when-cross-origin
|
||||
ReferrerPolicy string
|
||||
// ContentSecurityPolicy sets Content-Security-Policy header. Default: empty (not set)
|
||||
ContentSecurityPolicy string
|
||||
// PermissionsPolicy sets Permissions-Policy header. Default: empty (not set)
|
||||
PermissionsPolicy string
|
||||
// sTSSeconds sets max-age for Strict-Transport-Security. 0 disables.
|
||||
// only sent when request uses HTTPS. Default: 31536000 (1 year)
|
||||
STSSeconds int
|
||||
// sTSIncludeSubdomains adds includeSubDomains to HSTS. Default: true
|
||||
STSIncludeSubdomains bool
|
||||
// sTSPreload adds preload flag to HSTS. Default: false
|
||||
STSPreload bool
|
||||
// xSSProtection sets X-XSS-Protection header. Default: 1; mode=block
|
||||
// note: this header is deprecated in modern browsers but still useful for older ones
|
||||
XSSProtection string
|
||||
}
|
||||
|
||||
// SecOpt is a functional option for SecureConfig
|
||||
type SecOpt func(*SecureConfig)
|
||||
|
||||
// defaultSecureConfig returns config with sensible defaults
|
||||
func defaultSecureConfig() SecureConfig {
|
||||
return SecureConfig{
|
||||
XFrameOptions: "DENY",
|
||||
XContentTypeOptions: "nosniff",
|
||||
ReferrerPolicy: "strict-origin-when-cross-origin",
|
||||
STSSeconds: 31536000, // 1 year
|
||||
STSIncludeSubdomains: true,
|
||||
STSPreload: false,
|
||||
XSSProtection: "1; mode=block",
|
||||
}
|
||||
}
|
||||
|
||||
// SecFrameOptions sets X-Frame-Options header.
|
||||
// Common values: "DENY", "SAMEORIGIN"
|
||||
func SecFrameOptions(value string) SecOpt {
|
||||
return func(c *SecureConfig) {
|
||||
c.XFrameOptions = value
|
||||
}
|
||||
}
|
||||
|
||||
// SecContentTypeNosniff enables or disables X-Content-Type-Options: nosniff
|
||||
func SecContentTypeNosniff(enable bool) SecOpt {
|
||||
return func(c *SecureConfig) {
|
||||
if enable {
|
||||
c.XContentTypeOptions = "nosniff"
|
||||
} else {
|
||||
c.XContentTypeOptions = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SecReferrerPolicy sets Referrer-Policy header.
|
||||
// Common values: "no-referrer", "same-origin", "strict-origin", "strict-origin-when-cross-origin"
|
||||
func SecReferrerPolicy(policy string) SecOpt {
|
||||
return func(c *SecureConfig) {
|
||||
c.ReferrerPolicy = policy
|
||||
}
|
||||
}
|
||||
|
||||
// SecContentSecurityPolicy sets Content-Security-Policy header.
|
||||
// Example: "default-src 'self'; script-src 'self'"
|
||||
func SecContentSecurityPolicy(policy string) SecOpt {
|
||||
return func(c *SecureConfig) {
|
||||
c.ContentSecurityPolicy = policy
|
||||
}
|
||||
}
|
||||
|
||||
// SecPermissionsPolicy sets Permissions-Policy header.
|
||||
// Example: "geolocation=(), microphone=()"
|
||||
func SecPermissionsPolicy(policy string) SecOpt {
|
||||
return func(c *SecureConfig) {
|
||||
c.PermissionsPolicy = policy
|
||||
}
|
||||
}
|
||||
|
||||
// SecHSTS configures Strict-Transport-Security header.
|
||||
// maxAge is in seconds (0 disables HSTS), includeSubdomains and preload are optional flags.
|
||||
// Note: HSTS header is only sent when the request is over HTTPS.
|
||||
func SecHSTS(maxAge int, includeSubdomains, preload bool) SecOpt {
|
||||
return func(c *SecureConfig) {
|
||||
c.STSSeconds = maxAge
|
||||
c.STSIncludeSubdomains = includeSubdomains
|
||||
c.STSPreload = preload
|
||||
}
|
||||
}
|
||||
|
||||
// SecXSSProtection sets X-XSS-Protection header.
|
||||
// Set to empty string to disable. Common values: "0", "1", "1; mode=block"
|
||||
func SecXSSProtection(value string) SecOpt {
|
||||
return func(c *SecureConfig) {
|
||||
c.XSSProtection = value
|
||||
}
|
||||
}
|
||||
|
||||
// SecAllHeaders is a convenience option to set common headers for secure web applications.
|
||||
// Sets CSP with self-only policy and restrictive permissions.
|
||||
func SecAllHeaders() SecOpt {
|
||||
return func(c *SecureConfig) {
|
||||
c.ContentSecurityPolicy = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; form-action 'self'; frame-ancestors 'none'"
|
||||
c.PermissionsPolicy = "geolocation=(), microphone=(), camera=()"
|
||||
}
|
||||
}
|
||||
|
||||
// Secure is middleware that adds security headers to responses.
|
||||
// By default it sets: X-Frame-Options, X-Content-Type-Options, Referrer-Policy,
|
||||
// X-XSS-Protection, and Strict-Transport-Security (for HTTPS only).
|
||||
// Use SecOpt functions to customize the configuration.
|
||||
func Secure(opts ...SecOpt) func(http.Handler) http.Handler {
|
||||
cfg := defaultSecureConfig()
|
||||
for _, opt := range opts {
|
||||
opt(&cfg)
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// set security headers
|
||||
if cfg.XFrameOptions != "" {
|
||||
w.Header().Set("X-Frame-Options", cfg.XFrameOptions)
|
||||
}
|
||||
if cfg.XContentTypeOptions != "" {
|
||||
w.Header().Set("X-Content-Type-Options", cfg.XContentTypeOptions)
|
||||
}
|
||||
if cfg.ReferrerPolicy != "" {
|
||||
w.Header().Set("Referrer-Policy", cfg.ReferrerPolicy)
|
||||
}
|
||||
if cfg.XSSProtection != "" {
|
||||
w.Header().Set("X-XSS-Protection", cfg.XSSProtection)
|
||||
}
|
||||
if cfg.ContentSecurityPolicy != "" {
|
||||
w.Header().Set("Content-Security-Policy", cfg.ContentSecurityPolicy)
|
||||
}
|
||||
if cfg.PermissionsPolicy != "" {
|
||||
w.Header().Set("Permissions-Policy", cfg.PermissionsPolicy)
|
||||
}
|
||||
|
||||
// HSTS only for HTTPS connections
|
||||
if cfg.STSSeconds > 0 && isHTTPS(r) {
|
||||
sts := "max-age=" + strconv.Itoa(cfg.STSSeconds)
|
||||
if cfg.STSIncludeSubdomains {
|
||||
sts += "; includeSubDomains"
|
||||
}
|
||||
if cfg.STSPreload {
|
||||
sts += "; preload"
|
||||
}
|
||||
w.Header().Set("Strict-Transport-Security", sts)
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// isHTTPS checks if the request is over HTTPS by examining TLS state and common proxy headers
|
||||
func isHTTPS(r *http.Request) bool {
|
||||
// direct TLS connection
|
||||
if r.TLS != nil {
|
||||
return true
|
||||
}
|
||||
// check common proxy headers (case-insensitive)
|
||||
if strings.EqualFold(r.Header.Get("X-Forwarded-Proto"), "https") {
|
||||
return true
|
||||
}
|
||||
// check RFC 7239 Forwarded header
|
||||
if forwarded := r.Header.Get("Forwarded"); forwarded != "" {
|
||||
if forwardedProtoIsHTTPS(forwarded) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// forwardedProtoIsHTTPS parses RFC 7239 Forwarded header to check for proto=https.
|
||||
// The header format is: Forwarded: for=1.2.3.4;proto=https;by=proxy, for=5.6.7.8
|
||||
// Parameters are separated by semicolons, multiple forwarded elements by commas.
|
||||
func forwardedProtoIsHTTPS(header string) bool {
|
||||
// split by comma to get individual forwarded elements
|
||||
for element := range strings.SplitSeq(header, ",") {
|
||||
// split by semicolon to get parameters within element
|
||||
for param := range strings.SplitSeq(element, ";") {
|
||||
param = strings.TrimSpace(param)
|
||||
// check for proto=https (case-insensitive per RFC 7239)
|
||||
if len(param) > 6 && strings.EqualFold(param[:6], "proto=") {
|
||||
if strings.EqualFold(strings.TrimSpace(param[6:]), "https") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
+6
-5
@@ -140,11 +140,12 @@ A common use case would be integrating with different 3rd party signature
|
||||
providers, like key management services from various cloud providers or Hardware
|
||||
Security Modules (HSMs) or to implement additional standards.
|
||||
|
||||
| Extension | Purpose | Repo |
|
||||
| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
|
||||
| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go |
|
||||
| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms |
|
||||
| JWKS | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc |
|
||||
| Extension | Purpose | Repo |
|
||||
| --------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
|
||||
| GCP | Integrates with multiple Google Cloud Platform signing tools (AppEngine, IAM API, Cloud KMS) | https://github.com/someone1/gcp-jwt-go |
|
||||
| AWS | Integrates with AWS Key Management Service, KMS | https://github.com/matelang/jwt-go-aws-kms |
|
||||
| JWKS | Provides support for JWKS ([RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517)) as a `jwt.Keyfunc` | https://github.com/MicahParks/keyfunc |
|
||||
| TPM | Integrates with Trusted Platform Module (TPM) | https://github.com/salrashid123/golang-jwt-tpm |
|
||||
|
||||
*Disclaimer*: Unless otherwise specified, these integrations are maintained by
|
||||
third parties and should not be considered as a primary offer by any of the
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ Backwards compatible API change that was missed in 2.0.0.
|
||||
|
||||
There were two major reasons for breaking backwards compatibility with this update. The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations. There will likely be no required code changes to support this change.
|
||||
|
||||
The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
|
||||
The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods. Not all keys used for all signing methods have a single standard on-disk representation. Requiring `[]byte` as the type for all keys proved too limiting. Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys. Backwards compatibility has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
|
||||
|
||||
It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
|
||||
|
||||
|
||||
+13
-11
@@ -76,13 +76,6 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
|
||||
}
|
||||
}
|
||||
|
||||
// Decode signature
|
||||
token.Signature, err = p.DecodeSegment(parts[2])
|
||||
if err != nil {
|
||||
return token, newError("could not base64 decode signature", ErrTokenMalformed, err)
|
||||
}
|
||||
text := strings.Join(parts[0:2], ".")
|
||||
|
||||
// Lookup key(s)
|
||||
if keyFunc == nil {
|
||||
// keyFunc was not provided. short circuiting validation
|
||||
@@ -94,11 +87,14 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
|
||||
return token, newError("error while executing keyfunc", ErrTokenUnverifiable, err)
|
||||
}
|
||||
|
||||
// Join together header and claims in order to verify them with the signature
|
||||
text := strings.Join(parts[0:2], ".")
|
||||
switch have := got.(type) {
|
||||
case VerificationKeySet:
|
||||
if len(have.Keys) == 0 {
|
||||
return token, newError("keyfunc returned empty verification key set", ErrTokenUnverifiable)
|
||||
}
|
||||
|
||||
// Iterate through keys and verify signature, skipping the rest when a match is found.
|
||||
// Return the last error if no match is found.
|
||||
for _, key := range have.Keys {
|
||||
@@ -131,7 +127,7 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// ParseUnverified parses the token but doesn't validate the signature.
|
||||
// ParseUnverified parses the token but does not validate the signature.
|
||||
//
|
||||
// WARNING: Don't use this method unless you know what you're doing.
|
||||
//
|
||||
@@ -146,7 +142,7 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
|
||||
|
||||
token = &Token{Raw: tokenString}
|
||||
|
||||
// parse Header
|
||||
// Parse Header
|
||||
var headerBytes []byte
|
||||
if headerBytes, err = p.DecodeSegment(parts[0]); err != nil {
|
||||
return token, parts, newError("could not base64 decode header", ErrTokenMalformed, err)
|
||||
@@ -155,7 +151,7 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
|
||||
return token, parts, newError("could not JSON decode header", ErrTokenMalformed, err)
|
||||
}
|
||||
|
||||
// parse Claims
|
||||
// Parse Claims
|
||||
token.Claims = claims
|
||||
|
||||
claimBytes, err := p.DecodeSegment(parts[1])
|
||||
@@ -196,6 +192,12 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
|
||||
return token, parts, newError("signing method (alg) is unspecified", ErrTokenUnverifiable)
|
||||
}
|
||||
|
||||
// Parse token signature
|
||||
token.Signature, err = p.DecodeSegment(parts[2])
|
||||
if err != nil {
|
||||
return token, parts, newError("could not base64 decode signature", ErrTokenMalformed, err)
|
||||
}
|
||||
|
||||
return token, parts, nil
|
||||
}
|
||||
|
||||
@@ -216,7 +218,7 @@ func splitToken(token string) ([]string, bool) {
|
||||
parts[1] = claims
|
||||
// One more cut to ensure the signature is the last part of the token and there are no more
|
||||
// delimiters. This avoids an issue where malicious input could contain additional delimiters
|
||||
// causing unecessary overhead parsing tokens.
|
||||
// causing unnecessary overhead parsing tokens.
|
||||
signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
|
||||
if unexpected {
|
||||
return nil, false
|
||||
|
||||
+9
-3
@@ -3,9 +3,7 @@ package jwt
|
||||
import "time"
|
||||
|
||||
// ParserOption is used to implement functional-style options that modify the
|
||||
// behavior of the parser. To add new options, just create a function (ideally
|
||||
// beginning with With or Without) that returns an anonymous function that takes
|
||||
// a *Parser type as input and manipulates its configuration accordingly.
|
||||
// behavior of the parser.
|
||||
type ParserOption func(*Parser)
|
||||
|
||||
// WithValidMethods is an option to supply algorithm methods that the parser
|
||||
@@ -66,6 +64,14 @@ func WithExpirationRequired() ParserOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithNotBeforeRequired returns the ParserOption to make nbf claim required.
|
||||
// By default nbf claim is optional.
|
||||
func WithNotBeforeRequired() ParserOption {
|
||||
return func(p *Parser) {
|
||||
p.validator.requireNbf = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithAudience configures the validator to require any of the specified
|
||||
// audiences in the `aud` claim. Validation will fail if the audience is not
|
||||
// listed in the token or the `aud` claim is missing.
|
||||
|
||||
+4
-2
@@ -32,8 +32,8 @@ type Token struct {
|
||||
Method SigningMethod // Method is the signing method used or to be used
|
||||
Header map[string]any // Header is the first segment of the token in decoded form
|
||||
Claims Claims // Claims is the second segment of the token in decoded form
|
||||
Signature []byte // Signature is the third segment of the token in decoded form. Populated when you Parse a token
|
||||
Valid bool // Valid specifies if the token is valid. Populated when you Parse/Verify a token
|
||||
Signature []byte // Signature is the third segment of the token in decoded form. Populated when you [Parse] or sign a token
|
||||
Valid bool // Valid specifies if the token is valid. Populated when you [Parse] a token
|
||||
}
|
||||
|
||||
// New creates a new [Token] with the specified signing method and an empty map
|
||||
@@ -71,6 +71,8 @@ func (t *Token) SignedString(key any) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
t.Signature = sig
|
||||
|
||||
return sstr + "." + t.EncodeSegment(sig), nil
|
||||
}
|
||||
|
||||
|
||||
+6
-2
@@ -44,6 +44,9 @@ type Validator struct {
|
||||
// requireExp specifies whether the exp claim is required
|
||||
requireExp bool
|
||||
|
||||
// requireNbf specifies whether the nbf claim is required
|
||||
requireNbf bool
|
||||
|
||||
// verifyIat specifies whether the iat (Issued At) claim will be verified.
|
||||
// According to https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 this
|
||||
// only specifies the age of the token, but no validation check is
|
||||
@@ -111,8 +114,9 @@ func (v *Validator) Validate(claims Claims) error {
|
||||
}
|
||||
|
||||
// We always need to check not-before, but usage of the claim itself is
|
||||
// OPTIONAL.
|
||||
if err = v.verifyNotBefore(claims, now, false); err != nil {
|
||||
// OPTIONAL by default. requireNbf overrides this behavior and makes
|
||||
// the nbf claim mandatory.
|
||||
if err = v.verifyNotBefore(claims, now, v.requireNbf); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -196,6 +196,9 @@ func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) {
|
||||
if N <= 1 || N&(N-1) != 0 {
|
||||
return nil, errors.New("scrypt: N must be > 1 and a power of 2")
|
||||
}
|
||||
if r <= 0 || p <= 0 {
|
||||
return nil, errors.New("scrypt: parameters must be > 0")
|
||||
}
|
||||
if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r {
|
||||
return nil, errors.New("scrypt: parameters are too large")
|
||||
}
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ func archInit() {
|
||||
switch runtime.GOOS {
|
||||
case "freebsd":
|
||||
readARM64Registers()
|
||||
case "linux", "netbsd", "openbsd":
|
||||
case "linux", "netbsd", "openbsd", "windows":
|
||||
doinit()
|
||||
default:
|
||||
// Many platforms don't seem to allow reading these registers.
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !linux && !netbsd && !openbsd && arm64
|
||||
//go:build !linux && !netbsd && !openbsd && !windows && arm64
|
||||
|
||||
package cpu
|
||||
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func doinit() {
|
||||
// set HasASIMD and HasFP to true as per
|
||||
// https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#base-requirements
|
||||
//
|
||||
// The ARM64 version of Windows always presupposes that it's running on an ARMv8 or later architecture.
|
||||
// Both floating-point and NEON support are presumed to be present in hardware.
|
||||
//
|
||||
ARM64.HasASIMD = true
|
||||
ARM64.HasFP = true
|
||||
|
||||
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasAES = true
|
||||
ARM64.HasPMULL = true
|
||||
ARM64.HasSHA1 = true
|
||||
ARM64.HasSHA2 = true
|
||||
}
|
||||
ARM64.HasSHA3 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasCRC32 = windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSHA512 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasATOMICS = windows.IsProcessorFeaturePresent(windows.PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
|
||||
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasASIMDDP = true
|
||||
ARM64.HasASIMDRDM = true
|
||||
}
|
||||
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasLRCPC = true
|
||||
ARM64.HasSM3 = true
|
||||
}
|
||||
ARM64.HasSVE = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSVE2 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasJSCVT = windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
|
||||
}
|
||||
+122
-48
@@ -64,6 +64,80 @@ func initOptions() {
|
||||
|
||||
func archInit() {
|
||||
|
||||
// From internal/cpu
|
||||
const (
|
||||
// eax bits
|
||||
cpuid_AVXVNNI = 1 << 4
|
||||
|
||||
// ecx bits
|
||||
cpuid_SSE3 = 1 << 0
|
||||
cpuid_PCLMULQDQ = 1 << 1
|
||||
cpuid_AVX512VBMI = 1 << 1
|
||||
cpuid_AVX512VBMI2 = 1 << 6
|
||||
cpuid_SSSE3 = 1 << 9
|
||||
cpuid_AVX512GFNI = 1 << 8
|
||||
cpuid_AVX512VAES = 1 << 9
|
||||
cpuid_AVX512VNNI = 1 << 11
|
||||
cpuid_AVX512BITALG = 1 << 12
|
||||
cpuid_FMA = 1 << 12
|
||||
cpuid_AVX512VPOPCNTDQ = 1 << 14
|
||||
cpuid_SSE41 = 1 << 19
|
||||
cpuid_SSE42 = 1 << 20
|
||||
cpuid_POPCNT = 1 << 23
|
||||
cpuid_AES = 1 << 25
|
||||
cpuid_OSXSAVE = 1 << 27
|
||||
cpuid_AVX = 1 << 28
|
||||
|
||||
// "Extended Feature Flag" bits returned in EBX for CPUID EAX=0x7 ECX=0x0
|
||||
cpuid_BMI1 = 1 << 3
|
||||
cpuid_AVX2 = 1 << 5
|
||||
cpuid_BMI2 = 1 << 8
|
||||
cpuid_ERMS = 1 << 9
|
||||
cpuid_AVX512F = 1 << 16
|
||||
cpuid_AVX512DQ = 1 << 17
|
||||
cpuid_ADX = 1 << 19
|
||||
cpuid_AVX512CD = 1 << 28
|
||||
cpuid_SHA = 1 << 29
|
||||
cpuid_AVX512BW = 1 << 30
|
||||
cpuid_AVX512VL = 1 << 31
|
||||
|
||||
// "Extended Feature Flag" bits returned in ECX for CPUID EAX=0x7 ECX=0x0
|
||||
cpuid_AVX512_VBMI = 1 << 1
|
||||
cpuid_AVX512_VBMI2 = 1 << 6
|
||||
cpuid_GFNI = 1 << 8
|
||||
cpuid_AVX512VPCLMULQDQ = 1 << 10
|
||||
cpuid_AVX512_BITALG = 1 << 12
|
||||
|
||||
// edx bits
|
||||
cpuid_FSRM = 1 << 4
|
||||
// edx bits for CPUID 0x80000001
|
||||
cpuid_RDTSCP = 1 << 27
|
||||
)
|
||||
// Additional constants not in internal/cpu
|
||||
const (
|
||||
// eax=1: edx
|
||||
cpuid_SSE2 = 1 << 26
|
||||
// eax=1: ecx
|
||||
cpuid_CX16 = 1 << 13
|
||||
cpuid_RDRAND = 1 << 30
|
||||
// eax=7,ecx=0: ebx
|
||||
cpuid_RDSEED = 1 << 18
|
||||
cpuid_AVX512IFMA = 1 << 21
|
||||
cpuid_AVX512PF = 1 << 26
|
||||
cpuid_AVX512ER = 1 << 27
|
||||
// eax=7,ecx=0: edx
|
||||
cpuid_AVX5124VNNIW = 1 << 2
|
||||
cpuid_AVX5124FMAPS = 1 << 3
|
||||
cpuid_AMXBF16 = 1 << 22
|
||||
cpuid_AMXTile = 1 << 24
|
||||
cpuid_AMXInt8 = 1 << 25
|
||||
// eax=7,ecx=1: eax
|
||||
cpuid_AVX512BF16 = 1 << 5
|
||||
cpuid_AVXIFMA = 1 << 23
|
||||
// eax=7,ecx=1: edx
|
||||
cpuid_AVXVNNIInt8 = 1 << 4
|
||||
)
|
||||
|
||||
Initialized = true
|
||||
|
||||
maxID, _, _, _ := cpuid(0, 0)
|
||||
@@ -73,90 +147,90 @@ func archInit() {
|
||||
}
|
||||
|
||||
_, _, ecx1, edx1 := cpuid(1, 0)
|
||||
X86.HasSSE2 = isSet(26, edx1)
|
||||
X86.HasSSE2 = isSet(edx1, cpuid_SSE2)
|
||||
|
||||
X86.HasSSE3 = isSet(0, ecx1)
|
||||
X86.HasPCLMULQDQ = isSet(1, ecx1)
|
||||
X86.HasSSSE3 = isSet(9, ecx1)
|
||||
X86.HasFMA = isSet(12, ecx1)
|
||||
X86.HasCX16 = isSet(13, ecx1)
|
||||
X86.HasSSE41 = isSet(19, ecx1)
|
||||
X86.HasSSE42 = isSet(20, ecx1)
|
||||
X86.HasPOPCNT = isSet(23, ecx1)
|
||||
X86.HasAES = isSet(25, ecx1)
|
||||
X86.HasOSXSAVE = isSet(27, ecx1)
|
||||
X86.HasRDRAND = isSet(30, ecx1)
|
||||
X86.HasSSE3 = isSet(ecx1, cpuid_SSE3)
|
||||
X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ)
|
||||
X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3)
|
||||
X86.HasFMA = isSet(ecx1, cpuid_FMA)
|
||||
X86.HasCX16 = isSet(ecx1, cpuid_CX16)
|
||||
X86.HasSSE41 = isSet(ecx1, cpuid_SSE41)
|
||||
X86.HasSSE42 = isSet(ecx1, cpuid_SSE42)
|
||||
X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT)
|
||||
X86.HasAES = isSet(ecx1, cpuid_AES)
|
||||
X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE)
|
||||
X86.HasRDRAND = isSet(ecx1, cpuid_RDRAND)
|
||||
|
||||
var osSupportsAVX, osSupportsAVX512 bool
|
||||
// For XGETBV, OSXSAVE bit is required and sufficient.
|
||||
if X86.HasOSXSAVE {
|
||||
eax, _ := xgetbv()
|
||||
// Check if XMM and YMM registers have OS support.
|
||||
osSupportsAVX = isSet(1, eax) && isSet(2, eax)
|
||||
osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2)
|
||||
|
||||
if runtime.GOOS == "darwin" {
|
||||
// Darwin requires special AVX512 checks, see cpu_darwin_x86.go
|
||||
osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512()
|
||||
} else {
|
||||
// Check if OPMASK and ZMM registers have OS support.
|
||||
osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax)
|
||||
osSupportsAVX512 = osSupportsAVX && isSet(eax, 1<<5) && isSet(eax, 1<<6) && isSet(eax, 1<<7)
|
||||
}
|
||||
}
|
||||
|
||||
X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
|
||||
X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX
|
||||
|
||||
if maxID < 7 {
|
||||
return
|
||||
}
|
||||
|
||||
eax7, ebx7, ecx7, edx7 := cpuid(7, 0)
|
||||
X86.HasBMI1 = isSet(3, ebx7)
|
||||
X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
|
||||
X86.HasBMI2 = isSet(8, ebx7)
|
||||
X86.HasERMS = isSet(9, ebx7)
|
||||
X86.HasRDSEED = isSet(18, ebx7)
|
||||
X86.HasADX = isSet(19, ebx7)
|
||||
X86.HasBMI1 = isSet(ebx7, cpuid_BMI1)
|
||||
X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX
|
||||
X86.HasBMI2 = isSet(ebx7, cpuid_BMI2)
|
||||
X86.HasERMS = isSet(ebx7, cpuid_ERMS)
|
||||
X86.HasRDSEED = isSet(ebx7, cpuid_RDSEED)
|
||||
X86.HasADX = isSet(ebx7, cpuid_ADX)
|
||||
|
||||
X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension
|
||||
X86.HasAVX512 = isSet(ebx7, cpuid_AVX512F) && osSupportsAVX512 // Because avx-512 foundation is the core required extension
|
||||
if X86.HasAVX512 {
|
||||
X86.HasAVX512F = true
|
||||
X86.HasAVX512CD = isSet(28, ebx7)
|
||||
X86.HasAVX512ER = isSet(27, ebx7)
|
||||
X86.HasAVX512PF = isSet(26, ebx7)
|
||||
X86.HasAVX512VL = isSet(31, ebx7)
|
||||
X86.HasAVX512BW = isSet(30, ebx7)
|
||||
X86.HasAVX512DQ = isSet(17, ebx7)
|
||||
X86.HasAVX512IFMA = isSet(21, ebx7)
|
||||
X86.HasAVX512VBMI = isSet(1, ecx7)
|
||||
X86.HasAVX5124VNNIW = isSet(2, edx7)
|
||||
X86.HasAVX5124FMAPS = isSet(3, edx7)
|
||||
X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7)
|
||||
X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7)
|
||||
X86.HasAVX512VNNI = isSet(11, ecx7)
|
||||
X86.HasAVX512GFNI = isSet(8, ecx7)
|
||||
X86.HasAVX512VAES = isSet(9, ecx7)
|
||||
X86.HasAVX512VBMI2 = isSet(6, ecx7)
|
||||
X86.HasAVX512BITALG = isSet(12, ecx7)
|
||||
X86.HasAVX512CD = isSet(ebx7, cpuid_AVX512CD)
|
||||
X86.HasAVX512ER = isSet(ebx7, cpuid_AVX512ER)
|
||||
X86.HasAVX512PF = isSet(ebx7, cpuid_AVX512PF)
|
||||
X86.HasAVX512VL = isSet(ebx7, cpuid_AVX512VL)
|
||||
X86.HasAVX512BW = isSet(ebx7, cpuid_AVX512BW)
|
||||
X86.HasAVX512DQ = isSet(ebx7, cpuid_AVX512DQ)
|
||||
X86.HasAVX512IFMA = isSet(ebx7, cpuid_AVX512IFMA)
|
||||
X86.HasAVX512VBMI = isSet(ecx7, cpuid_AVX512_VBMI)
|
||||
X86.HasAVX5124VNNIW = isSet(edx7, cpuid_AVX5124VNNIW)
|
||||
X86.HasAVX5124FMAPS = isSet(edx7, cpuid_AVX5124FMAPS)
|
||||
X86.HasAVX512VPOPCNTDQ = isSet(ecx7, cpuid_AVX512VPOPCNTDQ)
|
||||
X86.HasAVX512VPCLMULQDQ = isSet(ecx7, cpuid_AVX512VPCLMULQDQ)
|
||||
X86.HasAVX512VNNI = isSet(ecx7, cpuid_AVX512VNNI)
|
||||
X86.HasAVX512GFNI = isSet(ecx7, cpuid_AVX512GFNI)
|
||||
X86.HasAVX512VAES = isSet(ecx7, cpuid_AVX512VAES)
|
||||
X86.HasAVX512VBMI2 = isSet(ecx7, cpuid_AVX512VBMI2)
|
||||
X86.HasAVX512BITALG = isSet(ecx7, cpuid_AVX512BITALG)
|
||||
}
|
||||
|
||||
X86.HasAMXTile = isSet(24, edx7)
|
||||
X86.HasAMXInt8 = isSet(25, edx7)
|
||||
X86.HasAMXBF16 = isSet(22, edx7)
|
||||
X86.HasAMXTile = isSet(edx7, cpuid_AMXTile)
|
||||
X86.HasAMXInt8 = isSet(edx7, cpuid_AMXInt8)
|
||||
X86.HasAMXBF16 = isSet(edx7, cpuid_AMXBF16)
|
||||
|
||||
// These features depend on the second level of extended features.
|
||||
if eax7 >= 1 {
|
||||
eax71, _, _, edx71 := cpuid(7, 1)
|
||||
if X86.HasAVX512 {
|
||||
X86.HasAVX512BF16 = isSet(5, eax71)
|
||||
X86.HasAVX512BF16 = isSet(eax71, cpuid_AVX512BF16)
|
||||
}
|
||||
if X86.HasAVX {
|
||||
X86.HasAVXIFMA = isSet(23, eax71)
|
||||
X86.HasAVXVNNI = isSet(4, eax71)
|
||||
X86.HasAVXVNNIInt8 = isSet(4, edx71)
|
||||
X86.HasAVXIFMA = isSet(eax71, cpuid_AVXIFMA)
|
||||
X86.HasAVXVNNI = isSet(eax71, cpuid_AVXVNNI)
|
||||
X86.HasAVXVNNIInt8 = isSet(edx71, cpuid_AVXVNNIInt8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isSet(bitpos uint, value uint32) bool {
|
||||
return value&(1<<bitpos) != 0
|
||||
func isSet(hwc uint32, value uint32) bool {
|
||||
return hwc&value != 0
|
||||
}
|
||||
|
||||
+8
-3
@@ -6,9 +6,7 @@
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
import "unsafe"
|
||||
|
||||
// ioctl itself should not be exposed directly, but additional get/set
|
||||
// functions for specific types are permissible.
|
||||
@@ -28,6 +26,13 @@ func IoctlSetPointerInt(fd int, req int, value int) error {
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&v))
|
||||
}
|
||||
|
||||
// IoctlSetString performs an ioctl operation which sets a string value
|
||||
// on fd, using the specified request number.
|
||||
func IoctlSetString(fd int, req int, value string) error {
|
||||
bs := append([]byte(value), 0)
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
|
||||
}
|
||||
|
||||
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
//
|
||||
// To change fd's window size, the req argument should be TIOCSWINSZ.
|
||||
|
||||
+8
-3
@@ -6,9 +6,7 @@
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
import "unsafe"
|
||||
|
||||
// ioctl itself should not be exposed directly, but additional get/set
|
||||
// functions for specific types are permissible.
|
||||
@@ -28,6 +26,13 @@ func IoctlSetPointerInt(fd int, req uint, value int) error {
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&v))
|
||||
}
|
||||
|
||||
// IoctlSetString performs an ioctl operation which sets a string value
|
||||
// on fd, using the specified request number.
|
||||
func IoctlSetString(fd int, req uint, value string) error {
|
||||
bs := append([]byte(value), 0)
|
||||
return ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
|
||||
}
|
||||
|
||||
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
//
|
||||
// To change fd's window size, the req argument should be TIOCSWINSZ.
|
||||
|
||||
-8
@@ -1052,14 +1052,6 @@ func IoctlSetIntRetInt(fd int, req int, arg int) (int, error) {
|
||||
return ioctlRet(fd, req, uintptr(arg))
|
||||
}
|
||||
|
||||
func IoctlSetString(fd int, req int, val string) error {
|
||||
bs := make([]byte, len(val)+1)
|
||||
copy(bs[:len(bs)-1], val)
|
||||
err := ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
|
||||
runtime.KeepAlive(&bs[0])
|
||||
return err
|
||||
}
|
||||
|
||||
// Lifreq Helpers
|
||||
|
||||
func (l *Lifreq) SetName(name string) error {
|
||||
|
||||
+7
-3
@@ -367,7 +367,9 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
|
||||
iov[0].SetLen(len(p))
|
||||
}
|
||||
var rsa RawSockaddrAny
|
||||
n, oobn, recvflags, err = recvmsgRaw(fd, iov[:], oob, flags, &rsa)
|
||||
if n, oobn, recvflags, err = recvmsgRaw(fd, iov[:], oob, flags, &rsa); err != nil {
|
||||
return
|
||||
}
|
||||
// source address is only specified if the socket is unconnected
|
||||
if rsa.Addr.Family != AF_UNSPEC {
|
||||
from, err = anyToSockaddr(fd, &rsa)
|
||||
@@ -389,8 +391,10 @@ func RecvmsgBuffers(fd int, buffers [][]byte, oob []byte, flags int) (n, oobn in
|
||||
}
|
||||
}
|
||||
var rsa RawSockaddrAny
|
||||
n, oobn, recvflags, err = recvmsgRaw(fd, iov, oob, flags, &rsa)
|
||||
if err == nil && rsa.Addr.Family != AF_UNSPEC {
|
||||
if n, oobn, recvflags, err = recvmsgRaw(fd, iov, oob, flags, &rsa); err != nil {
|
||||
return
|
||||
}
|
||||
if rsa.Addr.Family != AF_UNSPEC {
|
||||
from, err = anyToSockaddr(fd, &rsa)
|
||||
}
|
||||
return
|
||||
|
||||
+1
@@ -900,6 +900,7 @@ const socket_error = uintptr(^uint32(0))
|
||||
//sys NotifyRouteChange2(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyRouteChange2
|
||||
//sys NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyUnicastIpAddressChange
|
||||
//sys CancelMibChangeNotify2(notificationHandle Handle) (errcode error) = iphlpapi.CancelMibChangeNotify2
|
||||
//sys IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) = kernel32.IsProcessorFeaturePresent
|
||||
|
||||
// For testing: clients can set this flag to force
|
||||
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||
|
||||
+85
@@ -3938,3 +3938,88 @@ const (
|
||||
MOUSE_EVENT = 0x0002
|
||||
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||
)
|
||||
|
||||
// The processor features to be tested for IsProcessorFeaturePresent, see
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
|
||||
const (
|
||||
PF_ARM_64BIT_LOADSTORE_ATOMIC = 25
|
||||
PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE = 24
|
||||
PF_ARM_EXTERNAL_CACHE_AVAILABLE = 26
|
||||
PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE = 27
|
||||
PF_ARM_VFP_32_REGISTERS_AVAILABLE = 18
|
||||
PF_3DNOW_INSTRUCTIONS_AVAILABLE = 7
|
||||
PF_CHANNELS_ENABLED = 16
|
||||
PF_COMPARE_EXCHANGE_DOUBLE = 2
|
||||
PF_COMPARE_EXCHANGE128 = 14
|
||||
PF_COMPARE64_EXCHANGE128 = 15
|
||||
PF_FASTFAIL_AVAILABLE = 23
|
||||
PF_FLOATING_POINT_EMULATED = 1
|
||||
PF_FLOATING_POINT_PRECISION_ERRATA = 0
|
||||
PF_MMX_INSTRUCTIONS_AVAILABLE = 3
|
||||
PF_NX_ENABLED = 12
|
||||
PF_PAE_ENABLED = 9
|
||||
PF_RDTSC_INSTRUCTION_AVAILABLE = 8
|
||||
PF_RDWRFSGSBASE_AVAILABLE = 22
|
||||
PF_SECOND_LEVEL_ADDRESS_TRANSLATION = 20
|
||||
PF_SSE3_INSTRUCTIONS_AVAILABLE = 13
|
||||
PF_SSSE3_INSTRUCTIONS_AVAILABLE = 36
|
||||
PF_SSE4_1_INSTRUCTIONS_AVAILABLE = 37
|
||||
PF_SSE4_2_INSTRUCTIONS_AVAILABLE = 38
|
||||
PF_AVX_INSTRUCTIONS_AVAILABLE = 39
|
||||
PF_AVX2_INSTRUCTIONS_AVAILABLE = 40
|
||||
PF_AVX512F_INSTRUCTIONS_AVAILABLE = 41
|
||||
PF_VIRT_FIRMWARE_ENABLED = 21
|
||||
PF_XMMI_INSTRUCTIONS_AVAILABLE = 6
|
||||
PF_XMMI64_INSTRUCTIONS_AVAILABLE = 10
|
||||
PF_XSAVE_ENABLED = 17
|
||||
PF_ARM_V8_INSTRUCTIONS_AVAILABLE = 29
|
||||
PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30
|
||||
PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31
|
||||
PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34
|
||||
PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE = 43
|
||||
PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44
|
||||
PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE = 45
|
||||
PF_ARM_SVE_INSTRUCTIONS_AVAILABLE = 46
|
||||
PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE = 47
|
||||
PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE = 48
|
||||
PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE = 49
|
||||
PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE = 50
|
||||
PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE = 51
|
||||
PF_ARM_SVE_BF16_INSTRUCTIONS_AVAILABLE = 52
|
||||
PF_ARM_SVE_EBF16_INSTRUCTIONS_AVAILABLE = 53
|
||||
PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE = 54
|
||||
PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE = 55
|
||||
PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE = 56
|
||||
PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE = 57
|
||||
PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE = 58
|
||||
PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE = 59
|
||||
PF_BMI2_INSTRUCTIONS_AVAILABLE = 60
|
||||
PF_MOVDIR64B_INSTRUCTION_AVAILABLE = 61
|
||||
PF_ARM_LSE2_AVAILABLE = 62
|
||||
PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE = 64
|
||||
PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE = 65
|
||||
PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE = 66
|
||||
PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE = 67
|
||||
PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE = 68
|
||||
PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE = 69
|
||||
PF_ARM_SME_INSTRUCTIONS_AVAILABLE = 70
|
||||
PF_ARM_SME2_INSTRUCTIONS_AVAILABLE = 71
|
||||
PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE = 72
|
||||
PF_ARM_SME2_2_INSTRUCTIONS_AVAILABLE = 73
|
||||
PF_ARM_SME_AES_INSTRUCTIONS_AVAILABLE = 74
|
||||
PF_ARM_SME_SBITPERM_INSTRUCTIONS_AVAILABLE = 75
|
||||
PF_ARM_SME_SF8MM4_INSTRUCTIONS_AVAILABLE = 76
|
||||
PF_ARM_SME_SF8MM8_INSTRUCTIONS_AVAILABLE = 77
|
||||
PF_ARM_SME_SF8DP2_INSTRUCTIONS_AVAILABLE = 78
|
||||
PF_ARM_SME_SF8DP4_INSTRUCTIONS_AVAILABLE = 79
|
||||
PF_ARM_SME_SF8FMA_INSTRUCTIONS_AVAILABLE = 80
|
||||
PF_ARM_SME_F8F32_INSTRUCTIONS_AVAILABLE = 81
|
||||
PF_ARM_SME_F8F16_INSTRUCTIONS_AVAILABLE = 82
|
||||
PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE = 83
|
||||
PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE = 84
|
||||
PF_ARM_SME_F64F64_INSTRUCTIONS_AVAILABLE = 85
|
||||
PF_ARM_SME_I16I64_INSTRUCTIONS_AVAILABLE = 86
|
||||
PF_ARM_SME_LUTv2_INSTRUCTIONS_AVAILABLE = 87
|
||||
PF_ARM_SME_FA64_INSTRUCTIONS_AVAILABLE = 88
|
||||
PF_UMONITOR_INSTRUCTION_AVAILABLE = 89
|
||||
)
|
||||
|
||||
+7
@@ -320,6 +320,7 @@ var (
|
||||
procGetVolumePathNamesForVolumeNameW = modkernel32.NewProc("GetVolumePathNamesForVolumeNameW")
|
||||
procGetWindowsDirectoryW = modkernel32.NewProc("GetWindowsDirectoryW")
|
||||
procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList")
|
||||
procIsProcessorFeaturePresent = modkernel32.NewProc("IsProcessorFeaturePresent")
|
||||
procIsWow64Process = modkernel32.NewProc("IsWow64Process")
|
||||
procIsWow64Process2 = modkernel32.NewProc("IsWow64Process2")
|
||||
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
|
||||
@@ -2786,6 +2787,12 @@ func initializeProcThreadAttributeList(attrlist *ProcThreadAttributeList, attrco
|
||||
return
|
||||
}
|
||||
|
||||
func IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) {
|
||||
r0, _, _ := syscall.SyscallN(procIsProcessorFeaturePresent.Addr(), uintptr(ProcessorFeature))
|
||||
ret = r0 != 0
|
||||
return
|
||||
}
|
||||
|
||||
func IsWow64Process(handle Handle, isWow64 *bool) (err error) {
|
||||
var _p0 uint32
|
||||
if *isWow64 {
|
||||
|
||||
+4
@@ -334,3 +334,7 @@ func (t *Transformer) advanceString(s string) (n int, ok bool) {
|
||||
}
|
||||
return n, true
|
||||
}
|
||||
|
||||
func (t *Transformer) isFinal() bool {
|
||||
return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial
|
||||
}
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.10
|
||||
|
||||
package bidirule
|
||||
|
||||
func (t *Transformer) isFinal() bool {
|
||||
return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.10
|
||||
|
||||
package bidirule
|
||||
|
||||
func (t *Transformer) isFinal() bool {
|
||||
if !t.isRTL() {
|
||||
return true
|
||||
}
|
||||
return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial
|
||||
}
|
||||
-1815
File diff suppressed because it is too large
Load Diff
-1887
File diff suppressed because it is too large
Load Diff
-1923
File diff suppressed because it is too large
Load Diff
-1955
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,6 +1,6 @@
|
||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
//go:build !go1.27
|
||||
|
||||
package bidi
|
||||
|
||||
|
||||
+2135
File diff suppressed because it is too large
Load Diff
-1781
File diff suppressed because it is too large
Load Diff
+18
-8
@@ -13,15 +13,18 @@ import "encoding/binary"
|
||||
// a rune to a uint16. The values take two forms. For v >= 0x8000:
|
||||
// bits
|
||||
// 15: 1 (inverse of NFD_QC bit of qcInfo)
|
||||
// 13..7: qcInfo (see below). isYesD is always true (no decomposition).
|
||||
// 12..7: qcInfo (see below). isYesD is always true (no decomposition).
|
||||
// 6..0: ccc (compressed CCC value).
|
||||
// For v < 0x8000, the respective rune has a decomposition and v is an index
|
||||
// into a byte array of UTF-8 decomposition sequences and additional info and
|
||||
// has the form:
|
||||
// <header> <decomp_byte>* [<tccc> [<lccc>]]
|
||||
// The header contains the number of bytes in the decomposition (excluding this
|
||||
// length byte). The two most significant bits of this length byte correspond
|
||||
// to bit 5 and 4 of qcInfo (see below). The byte sequence itself starts at v+1.
|
||||
// length byte), with 33 mapped to 31 to fit in 5 bits.
|
||||
// (If any 31- or 32-byte decompositions come along, we could switch to using
|
||||
// use a general lookup table as long as there are at most 32 distinct lengths.)
|
||||
// The three most significant bits of this length byte correspond
|
||||
// to bit 5, 4, and 3 of qcInfo (see below). The byte sequence itself starts at v+1.
|
||||
// The byte sequence is followed by a trailing and leading CCC if the values
|
||||
// for these are not zero. The value of v determines which ccc are appended
|
||||
// to the sequences. For v < firstCCC, there are none, for v >= firstCCC,
|
||||
@@ -32,8 +35,8 @@ import "encoding/binary"
|
||||
|
||||
const (
|
||||
qcInfoMask = 0x3F // to clear all but the relevant bits in a qcInfo
|
||||
headerLenMask = 0x3F // extract the length value from the header byte
|
||||
headerFlagsMask = 0xC0 // extract the qcInfo bits from the header byte
|
||||
headerLenMask = 0x1F // extract the length value from the header byte (31 => 33)
|
||||
headerFlagsMask = 0xE0 // extract the qcInfo bits from the header byte
|
||||
)
|
||||
|
||||
// Properties provides access to normalization properties of a rune.
|
||||
@@ -109,14 +112,14 @@ func (p Properties) BoundaryAfter() bool {
|
||||
return p.isInert()
|
||||
}
|
||||
|
||||
// We pack quick check data in 4 bits:
|
||||
// We pack quick check data in 6 bits:
|
||||
//
|
||||
// 5: Combines forward (0 == false, 1 == true)
|
||||
// 4..3: NFC_QC Yes(00), No (10), or Maybe (11)
|
||||
// 2: NFD_QC Yes (0) or No (1). No also means there is a decomposition.
|
||||
// 1..0: Number of trailing non-starters.
|
||||
//
|
||||
// When all 4 bits are zero, the character is inert, meaning it is never
|
||||
// When all 6 bits are zero, the character is inert, meaning it is never
|
||||
// influenced by normalization.
|
||||
type qcInfo uint8
|
||||
|
||||
@@ -152,6 +155,9 @@ func (p Properties) Decomposition() []byte {
|
||||
}
|
||||
i := p.index
|
||||
n := decomps[i] & headerLenMask
|
||||
if n == 31 {
|
||||
n = 33
|
||||
}
|
||||
i++
|
||||
return decomps[i : i+uint16(n)]
|
||||
}
|
||||
@@ -260,7 +266,11 @@ func compInfo(v uint16, sz int) Properties {
|
||||
f := (qcInfo(h&headerFlagsMask) >> 2) | 0x4
|
||||
p := Properties{size: uint8(sz), flags: f, index: v}
|
||||
if v >= firstCCC {
|
||||
v += uint16(h&headerLenMask) + 1
|
||||
n := uint16(h & headerLenMask)
|
||||
if n == 31 {
|
||||
n = 33
|
||||
}
|
||||
v += n + 1
|
||||
c := decomps[v]
|
||||
p.tccc = c >> 2
|
||||
p.flags |= qcInfo(c & 0x3)
|
||||
|
||||
-7657
File diff suppressed because it is too large
Load Diff
-7693
File diff suppressed because it is too large
Load Diff
-7710
File diff suppressed because it is too large
Load Diff
+1478
-1478
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+3532
-3188
File diff suppressed because it is too large
Load Diff
-7637
File diff suppressed because it is too large
Load Diff
Vendored
+10
-10
@@ -7,7 +7,7 @@ github.com/Depado/bfchroma/v2
|
||||
# github.com/PuerkitoBio/goquery v1.11.0
|
||||
## explicit; go 1.24.0
|
||||
github.com/PuerkitoBio/goquery
|
||||
# github.com/alecthomas/chroma/v2 v2.21.1
|
||||
# github.com/alecthomas/chroma/v2 v2.23.1
|
||||
## explicit; go 1.22
|
||||
github.com/alecthomas/chroma/v2
|
||||
github.com/alecthomas/chroma/v2/formatters/html
|
||||
@@ -44,8 +44,8 @@ github.com/didip/tollbooth/v8/limiter
|
||||
## explicit; go 1.13
|
||||
github.com/dlclark/regexp2
|
||||
github.com/dlclark/regexp2/syntax
|
||||
# github.com/go-chi/chi/v5 v5.2.3
|
||||
## explicit; go 1.20
|
||||
# github.com/go-chi/chi/v5 v5.2.5
|
||||
## explicit; go 1.22
|
||||
github.com/go-chi/chi/v5
|
||||
github.com/go-chi/chi/v5/middleware
|
||||
# github.com/go-chi/cors v1.2.2
|
||||
@@ -91,7 +91,7 @@ github.com/go-pkgz/repeater/strategy
|
||||
# github.com/go-pkgz/repeater/v2 v2.2.0
|
||||
## explicit; go 1.23
|
||||
github.com/go-pkgz/repeater/v2
|
||||
# github.com/go-pkgz/rest v1.20.6
|
||||
# github.com/go-pkgz/rest v1.21.0
|
||||
## explicit; go 1.24.0
|
||||
github.com/go-pkgz/rest
|
||||
github.com/go-pkgz/rest/logger
|
||||
@@ -102,7 +102,7 @@ github.com/go-pkgz/routegroup
|
||||
# github.com/go-pkgz/syncs v1.3.2
|
||||
## explicit; go 1.20
|
||||
github.com/go-pkgz/syncs
|
||||
# github.com/golang-jwt/jwt/v5 v5.3.0
|
||||
# github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
## explicit; go 1.21
|
||||
github.com/golang-jwt/jwt/v5
|
||||
# github.com/golang/snappy v1.0.0
|
||||
@@ -272,7 +272,7 @@ go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage
|
||||
## explicit; go 1.20
|
||||
go.uber.org/goleak
|
||||
go.uber.org/goleak/internal/stack
|
||||
# golang.org/x/crypto v0.46.0
|
||||
# golang.org/x/crypto v0.48.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/crypto/acme
|
||||
golang.org/x/crypto/acme/autocert
|
||||
@@ -283,11 +283,11 @@ golang.org/x/crypto/blowfish
|
||||
golang.org/x/crypto/ocsp
|
||||
golang.org/x/crypto/pbkdf2
|
||||
golang.org/x/crypto/scrypt
|
||||
# golang.org/x/image v0.34.0
|
||||
# golang.org/x/image v0.36.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/image/draw
|
||||
golang.org/x/image/math/f64
|
||||
# golang.org/x/net v0.48.0
|
||||
# golang.org/x/net v0.49.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/net/html
|
||||
golang.org/x/net/html/atom
|
||||
@@ -313,13 +313,13 @@ golang.org/x/oauth2/yandex
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/sync/errgroup
|
||||
golang.org/x/sync/singleflight
|
||||
# golang.org/x/sys v0.39.0
|
||||
# golang.org/x/sys v0.41.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/sys/cpu
|
||||
golang.org/x/sys/unix
|
||||
golang.org/x/sys/windows
|
||||
golang.org/x/sys/windows/registry
|
||||
# golang.org/x/text v0.32.0
|
||||
# golang.org/x/text v0.34.0
|
||||
## explicit; go 1.24.0
|
||||
golang.org/x/text/secure/bidirule
|
||||
golang.org/x/text/transform
|
||||
|
||||
Reference in New Issue
Block a user