샘플
minimatch 10.1.1: Unescape glob pattern strings with minimatch.unescape across windowsPathsNoEscape path mode and magicalBraces configurations
검증된 샘플 — npm minimatch 10.1.1: Unescape glob pattern strings with minimatch.unescape across windowsPathsNoEscape path mode and magicalBraces configurations.…
sha256:03eabe054f3c93d859e0a70ed50e293fad84864a382960bcc89fd0f55fdf4ca8
이 네트워크가 제공하는 것은 하나입니다. 빌드되는 샘플. 샌드박스에서 돌리고 서명된 영수증을 보관합니다. 등급을 매기지 않고 무엇도 보증하지 않습니다 — 같은 코드가 당신 환경에서 빌드되는지는 측정한 적이 없습니다.
통과한 계약 영수증을 낸 서로 다른 서명 키의 수입니다. 하나면 작성자 혼자이고, 둘 이상이면 다른 사람도 빌드했다는 뜻입니다. 키는 스스로 만드는 것이고 뒤에 등록된 신원이 없으므로, 세는 것은 사람이 아니라 키입니다.
MIT-0
실행 증거
선언된 환경과 서명된 실행을 분리해 두었습니다. 이 샘플이 무엇을 어디서 실행했는지 그대로 볼 수 있습니다.
- 증거 기준
- 서명된 컨트랙트 통과
- 검증 영수증
- 2
- 빌드한 서명 키
- 2
선언된 환경
node linux x64 node node npm
검증 실행 환경
| 환경 | 컨트랙트 | 단계 | 실행일 |
|---|---|---|---|
| node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-17 |
| node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · node-typescript@1 |
2026-08-18 |
케이스
HOW- 목표
- Unescape glob pattern strings with minimatch.unescape across windowsPathsNoEscape path mode and magicalBraces configurations
- 패키지
- 심벌
-
- minimatch.unescape
- 환경
- node
- 생성일
- 2026-08-17T22:46:35Z
컨트랙트
- minimatch.unescape preserves backslash sequences under windowsPathsNoEscape mode because backslashes are treated as path separators rather than escape characters
- minimatch.unescape strips single-character bracket escapes while leaving multi-character bracket character classes and forward slashes untouched
- minimatch.unescape defaults magicalBraces to true which strips brace escapes, but retains brace escapes when magicalBraces is explicitly set to false
- minimatch.unescape leaves adjacent bracket wraps unescaped in standard mode due to preceding character consumption in the replacement regex
- minimatch.unescape unescapes backslash-escaped opening brackets to literal brackets rather than stripping the inner character wrap
파일
- NOTES.md
- csx.json
- package-lock.json
- package.json
- src/index.mjs
- test/contract.mjs
소스
# Minimatch Unescape Semantics and Edge Cases
## Search Findings
Querying known solutions returned `sha256:585ab2a8ea43909cb7e47145ba967133e7da688e33baa7e055319539c3675105`, which demonstrated general glob matching features across multiple symbols. This sample investigates the exact contract, option interactions, and pattern parsing rules of `minimatch.unescape`.
## Pinned Version
- `minimatch`: `10.1.1`
## Observed Behavior
`minimatch.unescape` is exposed both as a named export (`unescape`) and as a property on the default/namespace export (`minimatch.unescape`).
### 1. Windows Path Mode (`windowsPathsNoEscape: true`)
When `windowsPathsNoEscape` is enabled:
- Backslashes (`\`) are treated strictly as path separators, not escape characters. Backslash escape sequences such as `\*` or `\?` are left untouched.
- Single-character bracket wraps used by `minimatch.escape` (such as `[*]`, `[?]`) are unescaped.
- Backslashes inside brackets (such as `[\\]`) are not stripped.
### 2. Standard Mode vs. Non-Magic Characters
In standard mode (`windowsPathsNoEscape: false`):
- Backslashes before non-slash characters are stripped (`\*` -> `*`, `\?` -> `?`, `\(` -> `(`, `\)` -> `)`, `\[` -> `[`, `\]` -> `]`).
- Forward slashes are never unescaped: `\/` remains `\/` and `[/]` remains `[/]`.
- Multi-character character classes (such as `[abc]`, `[0-9]`, `[!a-z]`) are preserved without modification because the bracket matcher only matches single non-slash characters `[([^\/\\])]`.
### 3. Asymmetric Defaults for `magicalBraces`
While `minimatch.escape` defaults `magicalBraces` to `false` (leaving braces untouched), `minimatch.unescape` defaults `magicalBraces` to `true`.
- Default (`magicalBraces: true`): `\{a,b\}` unescapes to `{a,b}`, and `[{]a,b[}]` unescapes to `{a,b}`.
- Explicit `magicalBraces: false`: Brace escapes are preserved as literal escapes (`\{a,b\}` and `[{]a,b[}]`), while other escaped wildcards (such as `\*`) are still unescaped.
### 4. Consecutive Bracket Replacement Boundary
In standard mode, the unescape regex uses `((?!\\).|^)\[([^\/\\])\]` to avoid unescaping backslash-escaped brackets. Because `((?!\\).|^)` consumes the preceding character during replacement, consecutive bracket escapes like `[*][*]` only unescape the first bracket, yielding `*[*]`. When separated by other characters (`[*]a[*]`), both are unescaped to `*a*`. In `windowsPathsNoEscape` mode, the regex does not capture preceding characters, so `[*][*]` resolves to `**`.
### 5. Escaped Bracket Wraps
When a bracket escape is prefixed with a backslash (`\[*]`), the leading backslash escapes the opening bracket, resulting in literal `[*]`.
## Failure Modes of Wrong Expectations
1. **Backslashes in Windows Path Mode**: A model assuming `unescape` strips backslashes regardless of mode will generate incorrect paths when `windowsPathsNoEscape: true` is active, failing assertions when backslashes persist.
2. **Magical Braces Default**: Expecting `unescape` to mirror `escape`'s default `magicalBraces: false` leads to unexpected stripping of brace escapes in standard patterns.
3. **Adjacent Bracket Classes**: Assuming consecutive single-character bracket escapes `[*][*]` normalize to `**` in standard mode results in unexpected leftover bracket notation `*[*]`.
{"case":{"believed":"minimatch.unescape strips backslash escape sequences under windowsPathsNoEscape mode and preserves brace escapes by default","caseId":"case:sha256:51c8867514ce9543a0446577e08adf3c6b1835b2eef8937c763ca9249748a5c6","contract":["minimatch.unescape preserves backslash sequences under windowsPathsNoEscape mode because backslashes are treated as path separators rather than escape characters","minimatch.unescape strips single-character bracket escapes while leaving multi-character bracket character classes and forward slashes untouched","minimatch.unescape defaults magicalBraces to true which strips brace escapes, but retains brace escapes when magicalBraces is explicitly set to false","minimatch.unescape leaves adjacent bracket wraps unescaped in standard mode due to preceding character consumption in the replacement regex","minimatch.unescape unescapes backslash-escaped opening brackets to literal brackets rather than stripping the inner character wrap"],"goal":"Unescape glob pattern strings with minimatch.unescape across windowsPathsNoEscape path mode and magicalBraces configurations","kind":"HOW","packages":["pkg:npm/minimatch@10.1.1"],"schemaVersion":1,"symbols":["minimatch.unescape"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/minimatch@10.1.1"],"schemaVersion":1,"symbols":["minimatch.unescape"],"verifierAdapter":"node-typescript@1"}
{
"name": "minimatch-unescape-contract",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "minimatch-unescape-contract",
"version": "1.0.0",
"dependencies": {
"minimatch": "10.1.1"
}
},
"node_modules/@isaacs/balanced-match": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
"license": "MIT",
"engines": {
"node": "20 || >=22"
}
},
"node_modules/@isaacs/brace-expansion": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz",
"integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
"license": "MIT",
"dependencies": {
"@isaacs/balanced-match": "^4.0.1"
},
"engines": {
"node": "20 || >=22"
}
},
"node_modules/minimatch": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz",
"integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==",
"license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/brace-expansion": "^5.0.0"
},
"engines": {
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
}
}
}
{
"name": "minimatch-unescape-contract",
"private": true,
"type": "module",
"dependencies": {
"minimatch": "10.1.1"
}
}
import { minimatch, unescape } from 'minimatch';
export function unescapePattern(pattern, options) {
return unescape(pattern, options);
}
export function unescapeFromMinimatchObject(pattern, options) {
return minimatch.unescape(pattern, options);
}
import { strict as assert } from 'node:assert';
import { minimatch, unescape } from 'minimatch';
import { unescapeFromMinimatchObject, unescapePattern } from '../src/index.mjs';
// Verify minimatch.unescape is exposed as a property and matches named export
assert.strictEqual(minimatch.unescape, unescape);
assert.strictEqual(typeof minimatch.unescape, 'function');
// 1. windowsPathsNoEscape mode: backslashes are path separators and not escape chars,
// while single-character bracket escapes are stripped.
const winEscaped = 'dir\\subdir\\[*]\\file\\[?].txt';
assert.strictEqual(
unescapePattern(winEscaped, { windowsPathsNoEscape: true }),
'dir\\subdir\\*\\file\\?.txt'
);
assert.strictEqual(
unescapePattern('\\*\\?', { windowsPathsNoEscape: true }),
'\\*\\?'
);
assert.strictEqual(
unescapePattern('[\\]', { windowsPathsNoEscape: true }),
'[\\]'
);
assert.strictEqual(
unescapePattern('[*][*]', { windowsPathsNoEscape: true }),
'**'
);
// 2. Standard mode: backslashes and separated single-character bracket escapes are stripped,
// but forward slashes and multi-character bracket classes are never unescaped.
assert.strictEqual(unescapePattern('\\*\\?\\[\\]\\(\\)'), '*?[]()');
assert.strictEqual(unescapePattern('[*]a[?]b[(]c[)]'), '*a?b(c)');
assert.strictEqual(unescapePattern('\\/'), '\\/');
assert.strictEqual(unescapePattern('[/]'), '[/]');
assert.strictEqual(unescapePattern('[abc]'), '[abc]');
assert.strictEqual(unescapePattern('[0-9]'), '[0-9]');
assert.strictEqual(unescapePattern('[!a-z]'), '[!a-z]');
// 3. Standard mode adjacent bracket trap: consuming preceding char leaves adjacent brackets unescaped
assert.strictEqual(unescapePattern('[*][*]'), '*[*]');
// 4. magicalBraces handling: unescape defaults magicalBraces to true (unlike escape),
// stripping brace escapes, but retains them when magicalBraces is explicitly false.
assert.strictEqual(unescapePattern('\\{a,b\\}'), '{a,b}');
assert.strictEqual(unescapePattern('[{]a,b[}]'), '{a,b}');
assert.strictEqual(
unescapePattern('\\{a,b\\}', { magicalBraces: false }),
'\\{a,b\\}'
);
assert.strictEqual(
unescapePattern('[{]a,b[}]', { magicalBraces: false }),
'[{]a,b[}]'
);
assert.strictEqual(
unescapePattern('\\*\\{a,b\\}', { magicalBraces: false }),
'*\\{a,b\\}'
);
// 5. Escaped bracket wraps: backslash before bracket unescapes outer bracket rather than inner wildcard
assert.strictEqual(unescapePattern('\\[*]'), '[*]');
// 6. Verification through minimatch.unescape property invocation
assert.strictEqual(
unescapeFromMinimatchObject('\\[a\\]'),
'[a]'
);
assert.strictEqual(
unescapeFromMinimatchObject('src/\\[*\\]/*.js'),
'src/[*]/*.js'
);