mirror of
https://github.com/go-gitea/gitea
synced 2025-09-13 12:18:13 +00:00
Fix different behavior in status check pattern matching with double stars (#35474)
Drop the minimatch dependency, use our own glob compiler. Fix #35473
This commit is contained in:
@@ -37,7 +37,6 @@
|
|||||||
"jquery": "3.7.1",
|
"jquery": "3.7.1",
|
||||||
"katex": "0.16.22",
|
"katex": "0.16.22",
|
||||||
"mermaid": "11.11.0",
|
"mermaid": "11.11.0",
|
||||||
"minimatch": "10.0.3",
|
|
||||||
"monaco-editor": "0.53.0",
|
"monaco-editor": "0.53.0",
|
||||||
"monaco-editor-webpack-plugin": "7.1.0",
|
"monaco-editor-webpack-plugin": "7.1.0",
|
||||||
"online-3d-viewer": "0.16.0",
|
"online-3d-viewer": "0.16.0",
|
||||||
|
26
pnpm-lock.yaml
generated
26
pnpm-lock.yaml
generated
@@ -119,9 +119,6 @@ importers:
|
|||||||
mermaid:
|
mermaid:
|
||||||
specifier: 11.11.0
|
specifier: 11.11.0
|
||||||
version: 11.11.0
|
version: 11.11.0
|
||||||
minimatch:
|
|
||||||
specifier: 10.0.3
|
|
||||||
version: 10.0.3
|
|
||||||
monaco-editor:
|
monaco-editor:
|
||||||
specifier: 0.53.0
|
specifier: 0.53.0
|
||||||
version: 0.53.0
|
version: 0.53.0
|
||||||
@@ -989,56 +986,67 @@ packages:
|
|||||||
resolution: {integrity: sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==}
|
resolution: {integrity: sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.50.1':
|
'@rollup/rollup-linux-arm-musleabihf@4.50.1':
|
||||||
resolution: {integrity: sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==}
|
resolution: {integrity: sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.50.1':
|
'@rollup/rollup-linux-arm64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==}
|
resolution: {integrity: sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.50.1':
|
'@rollup/rollup-linux-arm64-musl@4.50.1':
|
||||||
resolution: {integrity: sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==}
|
resolution: {integrity: sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-loongarch64-gnu@4.50.1':
|
'@rollup/rollup-linux-loongarch64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==}
|
resolution: {integrity: sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-gnu@4.50.1':
|
'@rollup/rollup-linux-ppc64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==}
|
resolution: {integrity: sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.50.1':
|
'@rollup/rollup-linux-riscv64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==}
|
resolution: {integrity: sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-musl@4.50.1':
|
'@rollup/rollup-linux-riscv64-musl@4.50.1':
|
||||||
resolution: {integrity: sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==}
|
resolution: {integrity: sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.50.1':
|
'@rollup/rollup-linux-s390x-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==}
|
resolution: {integrity: sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.50.1':
|
'@rollup/rollup-linux-x64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==}
|
resolution: {integrity: sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.50.1':
|
'@rollup/rollup-linux-x64-musl@4.50.1':
|
||||||
resolution: {integrity: sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==}
|
resolution: {integrity: sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rollup/rollup-openharmony-arm64@4.50.1':
|
'@rollup/rollup-openharmony-arm64@4.50.1':
|
||||||
resolution: {integrity: sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==}
|
resolution: {integrity: sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==}
|
||||||
@@ -1074,21 +1082,25 @@ packages:
|
|||||||
resolution: {integrity: sha512-NeDJJRNTLx8wOQT+si90th7cdt04I2F697Mp5w0a3Jf3XHAmsraBMn0phdLGWJoUWrrfVGthjgZDl5lcc1UHEA==}
|
resolution: {integrity: sha512-NeDJJRNTLx8wOQT+si90th7cdt04I2F697Mp5w0a3Jf3XHAmsraBMn0phdLGWJoUWrrfVGthjgZDl5lcc1UHEA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rspack/binding-linux-arm64-musl@1.5.3':
|
'@rspack/binding-linux-arm64-musl@1.5.3':
|
||||||
resolution: {integrity: sha512-M9utPq9s7zJkKapUlyfwwYT/rjZ+XM56NHQMUH9MVYgMJIl+66QURgWUXCAbuogxf1XWayUGQaZsgypoOrTG9A==}
|
resolution: {integrity: sha512-M9utPq9s7zJkKapUlyfwwYT/rjZ+XM56NHQMUH9MVYgMJIl+66QURgWUXCAbuogxf1XWayUGQaZsgypoOrTG9A==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rspack/binding-linux-x64-gnu@1.5.3':
|
'@rspack/binding-linux-x64-gnu@1.5.3':
|
||||||
resolution: {integrity: sha512-AsKqU4pIg0yYg1VvSEU0NspIwCexqXD2AYE0wujAAwBo0hOfbt5dl1JCK7idiZdIQvoFg86HbfGwdHIVcFLI0w==}
|
resolution: {integrity: sha512-AsKqU4pIg0yYg1VvSEU0NspIwCexqXD2AYE0wujAAwBo0hOfbt5dl1JCK7idiZdIQvoFg86HbfGwdHIVcFLI0w==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@rspack/binding-linux-x64-musl@1.5.3':
|
'@rspack/binding-linux-x64-musl@1.5.3':
|
||||||
resolution: {integrity: sha512-0aHuvDef92pFZaHhk8Mp8RP9TfTzhQ+Pjqrc2ixRS/FeJA+jVB2CSaYlAPP4QrgXdmW7tewSxEw8hYhF9CNv/A==}
|
resolution: {integrity: sha512-0aHuvDef92pFZaHhk8Mp8RP9TfTzhQ+Pjqrc2ixRS/FeJA+jVB2CSaYlAPP4QrgXdmW7tewSxEw8hYhF9CNv/A==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@rspack/binding-wasm32-wasi@1.5.3':
|
'@rspack/binding-wasm32-wasi@1.5.3':
|
||||||
resolution: {integrity: sha512-Y7KN/ZRuWcFdjCzuZE0JsPwTqJAz1aipJsEOI3whBUj9Va2RwbR9r3vbW6OscS0Wm3rTJAfqH0xwx9x3GksnAw==}
|
resolution: {integrity: sha512-Y7KN/ZRuWcFdjCzuZE0JsPwTqJAz1aipJsEOI3whBUj9Va2RwbR9r3vbW6OscS0Wm3rTJAfqH0xwx9x3GksnAw==}
|
||||||
@@ -1647,41 +1659,49 @@ packages:
|
|||||||
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
|
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
|
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
|
||||||
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
|
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
|
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
|
||||||
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
|
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
|
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
|
||||||
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
|
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
|
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
|
||||||
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
|
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
|
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
|
||||||
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
|
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
|
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
|
||||||
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
|
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
|
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
|
||||||
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
|
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
|
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
|
||||||
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
|
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import {minimatch} from 'minimatch';
|
|
||||||
import {createMonaco} from './codeeditor.ts';
|
import {createMonaco} from './codeeditor.ts';
|
||||||
import {onInputDebounce, queryElems, toggleElem} from '../utils/dom.ts';
|
import {onInputDebounce, queryElems, toggleElem} from '../utils/dom.ts';
|
||||||
import {POST} from '../modules/fetch.ts';
|
import {POST} from '../modules/fetch.ts';
|
||||||
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';
|
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';
|
||||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||||
|
import {globMatch} from '../utils/glob.ts';
|
||||||
|
|
||||||
const {appSubUrl, csrfToken} = window.config;
|
const {appSubUrl, csrfToken} = window.config;
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ function initRepoSettingsBranches() {
|
|||||||
let matched = false;
|
let matched = false;
|
||||||
const statusCheck = el.getAttribute('data-status-check');
|
const statusCheck = el.getAttribute('data-status-check');
|
||||||
for (const pattern of validPatterns) {
|
for (const pattern of validPatterns) {
|
||||||
if (minimatch(statusCheck, pattern, {noext: true})) { // https://github.com/go-gitea/gitea/issues/33121 disable extended glob syntax
|
if (globMatch(statusCheck, pattern, '/')) {
|
||||||
matched = true;
|
matched = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
129
web_src/js/utils/glob.test.ts
Normal file
129
web_src/js/utils/glob.test.ts
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import {readFile} from 'node:fs/promises';
|
||||||
|
import * as path from 'node:path';
|
||||||
|
import {globCompile} from './glob.ts';
|
||||||
|
|
||||||
|
async function loadGlobTestData(): Promise<{caseNames: string[], caseDataMap: Record<string, string>}> {
|
||||||
|
const fileContent = await readFile(path.join(import.meta.dirname, 'glob.test.txt'), 'utf8');
|
||||||
|
const fileLines = fileContent.split('\n');
|
||||||
|
const caseDataMap: Record<string, string> = {};
|
||||||
|
const caseNameMap: Record<string, boolean> = {};
|
||||||
|
for (let line of fileLines) {
|
||||||
|
line = line.trim();
|
||||||
|
if (!line || line.startsWith('#')) continue;
|
||||||
|
const parts = line.split('=', 2);
|
||||||
|
if (parts.length !== 2) throw new Error(`Invalid test case line: ${line}`);
|
||||||
|
|
||||||
|
const key = parts[0].trim();
|
||||||
|
let value = parts[1].trim();
|
||||||
|
value = value.substring(1, value.length - 1); // remove quotes
|
||||||
|
value = value.replace(/\\\\/g, '\\').replaceAll(/\\\//g, '/');
|
||||||
|
caseDataMap[key] = value;
|
||||||
|
if (key.startsWith('pattern_')) caseNameMap[key.substring('pattern_'.length)] = true;
|
||||||
|
}
|
||||||
|
return {caseNames: Object.keys(caseNameMap), caseDataMap};
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadGlobGolangCases() {
|
||||||
|
// https://github.com/gobwas/glob/blob/master/glob_test.go
|
||||||
|
function glob(matched: boolean, pattern: string, input: string, separators: string = '') {
|
||||||
|
return {matched, pattern, input, separators};
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
glob(true, '* ?at * eyes', 'my cat has very bright eyes'),
|
||||||
|
|
||||||
|
glob(true, '', ''),
|
||||||
|
glob(false, '', 'b'),
|
||||||
|
|
||||||
|
glob(true, '*ä', 'åä'),
|
||||||
|
glob(true, 'abc', 'abc'),
|
||||||
|
glob(true, 'a*c', 'abc'),
|
||||||
|
glob(true, 'a*c', 'a12345c'),
|
||||||
|
glob(true, 'a?c', 'a1c'),
|
||||||
|
glob(true, 'a.b', 'a.b', '.'),
|
||||||
|
glob(true, 'a.*', 'a.b', '.'),
|
||||||
|
glob(true, 'a.**', 'a.b.c', '.'),
|
||||||
|
glob(true, 'a.?.c', 'a.b.c', '.'),
|
||||||
|
glob(true, 'a.?.?', 'a.b.c', '.'),
|
||||||
|
glob(true, '?at', 'cat'),
|
||||||
|
glob(true, '?at', 'fat'),
|
||||||
|
glob(true, '*', 'abc'),
|
||||||
|
glob(true, `\\*`, '*'),
|
||||||
|
glob(true, '**', 'a.b.c', '.'),
|
||||||
|
|
||||||
|
glob(false, '?at', 'at'),
|
||||||
|
glob(false, '?at', 'fat', 'f'),
|
||||||
|
glob(false, 'a.*', 'a.b.c', '.'),
|
||||||
|
glob(false, 'a.?.c', 'a.bb.c', '.'),
|
||||||
|
glob(false, '*', 'a.b.c', '.'),
|
||||||
|
|
||||||
|
glob(true, '*test', 'this is a test'),
|
||||||
|
glob(true, 'this*', 'this is a test'),
|
||||||
|
glob(true, '*is *', 'this is a test'),
|
||||||
|
glob(true, '*is*a*', 'this is a test'),
|
||||||
|
glob(true, '**test**', 'this is a test'),
|
||||||
|
glob(true, '**is**a***test*', 'this is a test'),
|
||||||
|
|
||||||
|
glob(false, '*is', 'this is a test'),
|
||||||
|
glob(false, '*no*', 'this is a test'),
|
||||||
|
glob(true, '[!a]*', 'this is a test3'),
|
||||||
|
|
||||||
|
glob(true, '*abc', 'abcabc'),
|
||||||
|
glob(true, '**abc', 'abcabc'),
|
||||||
|
glob(true, '???', 'abc'),
|
||||||
|
glob(true, '?*?', 'abc'),
|
||||||
|
glob(true, '?*?', 'ac'),
|
||||||
|
glob(false, 'sta', 'stagnation'),
|
||||||
|
glob(true, 'sta*', 'stagnation'),
|
||||||
|
glob(false, 'sta?', 'stagnation'),
|
||||||
|
glob(false, 'sta?n', 'stagnation'),
|
||||||
|
|
||||||
|
glob(true, '{abc,def}ghi', 'defghi'),
|
||||||
|
glob(true, '{abc,abcd}a', 'abcda'),
|
||||||
|
glob(true, '{a,ab}{bc,f}', 'abc'),
|
||||||
|
glob(true, '{*,**}{a,b}', 'ab'),
|
||||||
|
glob(false, '{*,**}{a,b}', 'ac'),
|
||||||
|
|
||||||
|
glob(true, '/{rate,[a-z][a-z][a-z]}*', '/rate'),
|
||||||
|
glob(true, '/{rate,[0-9][0-9][0-9]}*', '/rate'),
|
||||||
|
glob(true, '/{rate,[a-z][a-z][a-z]}*', '/usd'),
|
||||||
|
|
||||||
|
glob(true, '{*.google.*,*.yandex.*}', 'www.google.com', '.'),
|
||||||
|
glob(true, '{*.google.*,*.yandex.*}', 'www.yandex.com', '.'),
|
||||||
|
glob(false, '{*.google.*,*.yandex.*}', 'yandex.com', '.'),
|
||||||
|
glob(false, '{*.google.*,*.yandex.*}', 'google.com', '.'),
|
||||||
|
|
||||||
|
glob(true, '{*.google.*,yandex.*}', 'www.google.com', '.'),
|
||||||
|
glob(true, '{*.google.*,yandex.*}', 'yandex.com', '.'),
|
||||||
|
glob(false, '{*.google.*,yandex.*}', 'www.yandex.com', '.'),
|
||||||
|
glob(false, '{*.google.*,yandex.*}', 'google.com', '.'),
|
||||||
|
|
||||||
|
glob(true, '*//{,*.}example.com', 'https://www.example.com'),
|
||||||
|
glob(true, '*//{,*.}example.com', 'http://example.com'),
|
||||||
|
glob(false, '*//{,*.}example.com', 'http://example.com.net'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
test('GlobCompiler', async () => {
|
||||||
|
const {caseNames, caseDataMap} = await loadGlobTestData();
|
||||||
|
expect(caseNames.length).toBe(10); // should have 10 test cases
|
||||||
|
for (const caseName of caseNames) {
|
||||||
|
const pattern = caseDataMap[`pattern_${caseName}`];
|
||||||
|
const regexp = caseDataMap[`regexp_${caseName}`];
|
||||||
|
expect(globCompile(pattern).regexpPattern).toBe(regexp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const golangCases = loadGlobGolangCases();
|
||||||
|
expect(golangCases.length).toBe(60);
|
||||||
|
for (const c of golangCases) {
|
||||||
|
const compiled = globCompile(c.pattern, c.separators);
|
||||||
|
const msg = `pattern: ${c.pattern}, input: ${c.input}, separators: ${c.separators || '(none)'}, compiled: ${compiled.regexpPattern}`;
|
||||||
|
// eslint-disable-next-line @vitest/valid-expect -- Unlike Jest, Vitest supports a message as the second argument
|
||||||
|
expect(compiled.regexp.test(c.input), msg).toBe(c.matched);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then our cases
|
||||||
|
expect(globCompile('*/**/x').regexpPattern).toBe('^.*/.*/x$');
|
||||||
|
expect(globCompile('*/**/x', '/').regexpPattern).toBe('^[^/]*/.*/x$');
|
||||||
|
expect(globCompile('[a-b][^-\\]]', '/').regexpPattern).toBe('^[a-b][^-\\]]$');
|
||||||
|
expect(globCompile('.+^$()|', '/').regexpPattern).toBe('^\\.\\+\\^\\$\\(\\)\\|$');
|
||||||
|
});
|
44
web_src/js/utils/glob.test.txt
Normal file
44
web_src/js/utils/glob.test.txt
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# test cases are from https://github.com/gobwas/glob/blob/master/glob_test.go
|
||||||
|
|
||||||
|
pattern_all = "[a-z][!a-x]*cat*[h][!b]*eyes*"
|
||||||
|
regexp_all = `^[a-z][^a-x].*cat.*[h][^b].*eyes.*$`
|
||||||
|
fixture_all_match = "my cat has very bright eyes"
|
||||||
|
fixture_all_mismatch = "my dog has very bright eyes"
|
||||||
|
|
||||||
|
pattern_plain = "google.com"
|
||||||
|
regexp_plain = `^google\.com$`
|
||||||
|
fixture_plain_match = "google.com"
|
||||||
|
fixture_plain_mismatch = "gobwas.com"
|
||||||
|
|
||||||
|
pattern_multiple = "https://*.google.*"
|
||||||
|
regexp_multiple = `^https:\/\/.*\.google\..*$`
|
||||||
|
fixture_multiple_match = "https://account.google.com"
|
||||||
|
fixture_multiple_mismatch = "https://google.com"
|
||||||
|
|
||||||
|
pattern_alternatives = "{https://*.google.*,*yandex.*,*yahoo.*,*mail.ru}"
|
||||||
|
regexp_alternatives = `^(https:\/\/.*\.google\..*|.*yandex\..*|.*yahoo\..*|.*mail\.ru)$`
|
||||||
|
fixture_alternatives_match = "http://yahoo.com"
|
||||||
|
fixture_alternatives_mismatch = "http://google.com"
|
||||||
|
|
||||||
|
pattern_alternatives_suffix = "{https://*gobwas.com,http://exclude.gobwas.com}"
|
||||||
|
regexp_alternatives_suffix = `^(https:\/\/.*gobwas\.com|http://exclude\.gobwas\.com)$`
|
||||||
|
fixture_alternatives_suffix_first_match = "https://safe.gobwas.com"
|
||||||
|
fixture_alternatives_suffix_first_mismatch = "http://safe.gobwas.com"
|
||||||
|
fixture_alternatives_suffix_second = "http://exclude.gobwas.com"
|
||||||
|
|
||||||
|
pattern_prefix = "abc*"
|
||||||
|
regexp_prefix = `^abc.*$`
|
||||||
|
pattern_suffix = "*def"
|
||||||
|
regexp_suffix = `^.*def$`
|
||||||
|
pattern_prefix_suffix = "ab*ef"
|
||||||
|
regexp_prefix_suffix = `^ab.*ef$`
|
||||||
|
fixture_prefix_suffix_match = "abcdef"
|
||||||
|
fixture_prefix_suffix_mismatch = "af"
|
||||||
|
|
||||||
|
pattern_alternatives_combine_lite = "{abc*def,abc?def,abc[zte]def}"
|
||||||
|
regexp_alternatives_combine_lite = `^(abc.*def|abc.def|abc[zte]def)$`
|
||||||
|
fixture_alternatives_combine_lite = "abczdef"
|
||||||
|
|
||||||
|
pattern_alternatives_combine_hard = "{abc*[a-c]def,abc?[d-g]def,abc[zte]?def}"
|
||||||
|
regexp_alternatives_combine_hard = `^(abc.*[a-c]def|abc.[d-g]def|abc[zte].def)$`
|
||||||
|
fixture_alternatives_combine_hard = "abczqdef"
|
127
web_src/js/utils/glob.ts
Normal file
127
web_src/js/utils/glob.ts
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
// Reference: https://github.com/gobwas/glob/blob/master/glob.go
|
||||||
|
//
|
||||||
|
// Compile creates Glob for given pattern and strings (if any present after pattern) as separators.
|
||||||
|
// The pattern syntax is:
|
||||||
|
//
|
||||||
|
// pattern:
|
||||||
|
// { term }
|
||||||
|
//
|
||||||
|
// term:
|
||||||
|
// `*` matches any sequence of non-separator characters
|
||||||
|
// `**` matches any sequence of characters
|
||||||
|
// `?` matches any single non-separator character
|
||||||
|
// `[` [ `!` ] { character-range } `]`
|
||||||
|
// character class (must be non-empty)
|
||||||
|
// `{` pattern-list `}`
|
||||||
|
// pattern alternatives
|
||||||
|
// c matches character c (c != `*`, `**`, `?`, `\`, `[`, `{`, `}`)
|
||||||
|
// `\` c matches character c
|
||||||
|
//
|
||||||
|
// character-range:
|
||||||
|
// c matches character c (c != `\\`, `-`, `]`)
|
||||||
|
// `\` c matches character c
|
||||||
|
// lo `-` hi matches character c for lo <= c <= hi
|
||||||
|
//
|
||||||
|
// pattern-list:
|
||||||
|
// pattern { `,` pattern }
|
||||||
|
// comma-separated (without spaces) patterns
|
||||||
|
//
|
||||||
|
|
||||||
|
class GlobCompiler {
|
||||||
|
nonSeparatorChars: string;
|
||||||
|
globPattern: string;
|
||||||
|
regexpPattern: string;
|
||||||
|
regexp: RegExp;
|
||||||
|
pos: number = 0;
|
||||||
|
|
||||||
|
#compileChars(): string {
|
||||||
|
let result = '';
|
||||||
|
if (this.globPattern[this.pos] === '!') {
|
||||||
|
this.pos++;
|
||||||
|
result += '^';
|
||||||
|
}
|
||||||
|
while (this.pos < this.globPattern.length) {
|
||||||
|
const c = this.globPattern[this.pos];
|
||||||
|
this.pos++;
|
||||||
|
if (c === ']') {
|
||||||
|
return `[${result}]`;
|
||||||
|
}
|
||||||
|
if (c === '\\') {
|
||||||
|
if (this.pos >= this.globPattern.length) {
|
||||||
|
throw new Error('Unterminated character class escape');
|
||||||
|
}
|
||||||
|
this.pos++;
|
||||||
|
result += `\\${this.globPattern[this.pos]}`;
|
||||||
|
} else {
|
||||||
|
result += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('Unterminated character class');
|
||||||
|
}
|
||||||
|
|
||||||
|
#compile(subPattern: boolean = false): string {
|
||||||
|
let result = '';
|
||||||
|
while (this.pos < this.globPattern.length) {
|
||||||
|
const c = this.globPattern[this.pos];
|
||||||
|
this.pos++;
|
||||||
|
if (subPattern && c === '}') {
|
||||||
|
return `(${result})`;
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case '*':
|
||||||
|
if (this.globPattern[this.pos] !== '*') {
|
||||||
|
result += `${this.nonSeparatorChars}*`; // match any sequence of non-separator characters
|
||||||
|
} else {
|
||||||
|
this.pos++;
|
||||||
|
result += '.*'; // match any sequence of characters
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
result += this.nonSeparatorChars; // match any single non-separator character
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
result += this.#compileChars();
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
result += this.#compile(true);
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
result += subPattern ? '|' : ',';
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
if (this.pos >= this.globPattern.length) {
|
||||||
|
throw new Error('No character to escape');
|
||||||
|
}
|
||||||
|
result += `\\${this.globPattern[this.pos]}`;
|
||||||
|
this.pos++;
|
||||||
|
break;
|
||||||
|
case '.': case '+': case '^': case '$': case '(': case ')': case '|':
|
||||||
|
result += `\\${c}`; // escape regexp special characters
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(pattern: string, separators: string = '') {
|
||||||
|
const escapedSeparators = separators.replaceAll(/[\^\]\-\\]/g, '\\$&');
|
||||||
|
this.nonSeparatorChars = escapedSeparators ? `[^${escapedSeparators}]` : '.';
|
||||||
|
this.globPattern = pattern;
|
||||||
|
this.regexpPattern = `^${this.#compile()}$`;
|
||||||
|
this.regexp = new RegExp(`^${this.regexpPattern}$`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function globCompile(pattern: string, separators: string = ''): GlobCompiler {
|
||||||
|
return new GlobCompiler(pattern, separators);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function globMatch(str: string, pattern: string, separators: string = ''): boolean {
|
||||||
|
try {
|
||||||
|
return globCompile(pattern, separators).regexp.test(str);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user