mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 06:19:45 +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