CodeSampleX

示例

fast-glob 3.3.3: Prove fast-glob 3.3.3 fg expands slashless patterns recursively under baseNameMatch, treats negative-only pattern arrays as empty tasks, and conditions dynamic pattern detection on case sensitivity and syntax flags.

已验证示例 — npm fast-glob 3.3.3: Prove fast-glob 3.3.3 fg expands slashless patterns recursively under baseNameMatch, treats negative-only pattern arrays as…

sha256:433cc5706b3ec70f6d20f5f47d1ce361014f3b014168a2468af26b2fcb219513

本网络只提供一件事:能构建的样本。它在沙箱中运行并保留签名回执。它不评级、不担保——同样的代码能否在你的环境构建,它没有测量过。 提交了通过的契约回执的不同签名密钥数量。为 1 表示只有作者;大于 1 表示还有其他人构建过。密钥是自行生成的,背后没有注册身份,因此计的是密钥而非人。 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-18
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
目标
Prove fast-glob 3.3.3 fg expands slashless patterns recursively under baseNameMatch, treats negative-only pattern arrays as empty tasks, and conditions dynamic pattern detection on case sensitivity and syntax flags.
包
符号
  • fg
环境
node
创建时间
2026-08-18T00:17:49Z

契约

  1. fg with baseNameMatch expands slashless patterns like *.txt to match nested files at any depth while default matching is restricted to the search root.
  2. fg with only negative patterns returns an empty array and fg.generateTasks yields zero tasks without at least one positive pattern.
  3. fg.isDynamicPattern classifies static paths as dynamic when caseSensitiveMatch is false, and respects braceExpansion and extglob disable flags.
  4. fg.posix.escapePath and fg.escapePath escape brackets so literal directory paths with glob characters match their exact files.
  5. fg.generateTasks partitions positive patterns into distinct static and dynamic tasks grouped by base directory.

文件

  • NOTES.md
  • csx.json
  • package-lock.json
  • package.json
  • test/contract.mjs

下载源代码构件 (tar.gz)

源代码

NOTES.md
# fast-glob (fg) Behavioral Contract Notes

## Upstream Search Result

Calling `search_known_solution` for `pkg:npm/fast-glob@3.3.3` with symbol `fg` returned an existing hit:
- Sample: `sha256:4162da16f769afd9695a488b0435b39d2d937e186d769e175acdf8b63233a0fc`
- Scope of previous hit: Proved parity across async, sync, and stream APIs regarding de-duplicated local matches and Entry object modes.

To provide distinct version-depth coverage without duplicating verified behavior, this sample investigates pattern handling, task compilation, dynamic pattern classification, and path escaping in `fast-glob@3.3.3`.

## Exact Release Pinned

- Package: `fast-glob`
- Release: `3.3.3`
- Manifest: `package.json` (`"fast-glob": "3.3.3"`)
- Lockfile: `package-lock.json` (`"version": "3.3.3"`)

## Observed Behaviors and Trap Analysis

### 1. `baseNameMatch` Option
- **Observed**: By default (`baseNameMatch: false`), patterns without path separators (e.g. `*.txt`) only match files directly located at the search root (`cwd`). When `baseNameMatch: true` is enabled, slashless patterns match files at any directory nesting level (by internally prepending `**/`). Patterns that already contain a slash (e.g. `nested/*.txt`) are not modified.
- **Trap / Failure Mode**: A caller expecting `*.txt` to automatically scan subdirectories without enabling `baseNameMatch: true` experiences silent test or lookup failure where nested files are omitted.

### 2. Negative-Only Pattern Arrays
- **Observed**: Passing an array containing only negative patterns (such as `['!*.txt']`) causes `fg.sync` and `fg` to return an empty array (`[]`). Internally, `fg.generateTasks` returns an empty array of tasks (`[]`). Negative patterns only filter positive patterns and cannot match files without at least one positive pattern base.
- **Trap / Failure Mode**: Expecting `['!*.txt']` to act as "match everything except `.txt` files" silently produces zero results.

### 3. Dynamic Pattern Detection (`fg.isDynamicPattern`)
- **Observed**: `fg.isDynamicPattern` returns `false` for static paths like `nested/file.txt`. However, when `caseSensitiveMatch: false` is supplied, `fg.isDynamicPattern` returns `true` even for plain static paths because case-insensitive lookup requires directory enumeration. Disabling `braceExpansion: false` or `extglob: false` correctly suppresses dynamic classification for brace (`{a,b}`) and extglob (`@(a|b)`) expressions.

### 4. Special Character Escaping (`fg.escapePath` / `fg.posix.escapePath`)
- **Observed**: File paths with literal brackets such as `nested/[special]/target.txt` are parsed as glob character sets unless escaped. Using `fg.posix.escapePath` escapes brackets into `nested/\\[special\\]/target.txt`, ensuring literal match targeting.

### 5. Task Partitioning (`fg.generateTasks`)
- **Observed**: `fg.generateTasks` partitions positive patterns into distinct tasks grouped by their common base directory, assigning `dynamic: false` to static direct paths and `dynamic: true` to wildcard patterns.
csx.json
{"case":{"believed":"A slashless pattern like *.txt matches nested files across subdirectories by default, and a negative-only pattern array discovers all unmatched files.","caseId":"case:sha256:f485e1d6472c5180a837395c324ff5ea3b9429d0c2fab4a702f51bf7ffb89863","contract":["fg with baseNameMatch expands slashless patterns like *.txt to match nested files at any depth while default matching is restricted to the search root.","fg with only negative patterns returns an empty array and fg.generateTasks yields zero tasks without at least one positive pattern.","fg.isDynamicPattern classifies static paths as dynamic when caseSensitiveMatch is false, and respects braceExpansion and extglob disable flags.","fg.posix.escapePath and fg.escapePath escape brackets so literal directory paths with glob characters match their exact files.","fg.generateTasks partitions positive patterns into distinct static and dynamic tasks grouped by base directory."],"goal":"Prove fast-glob 3.3.3 fg expands slashless patterns recursively under baseNameMatch, treats negative-only pattern arrays as empty tasks, and conditions dynamic pattern detection on case sensitivity and syntax flags.","kind":"HOW","packages":["pkg:npm/fast-glob@3.3.3"],"schemaVersion":1,"symbols":["fg"]},"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/fast-glob@3.3.3"],"schemaVersion":1,"symbols":["fg"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "fast-glob-behavior-contract",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "fast-glob-behavior-contract",
      "version": "1.0.0",
      "dependencies": {
        "fast-glob": "3.3.3"
      }
    },
    "node_modules/@nodelib/fs.scandir": {
      "version": "2.1.5",
      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
      "license": "MIT",
      "dependencies": {
        "@nodelib/fs.stat": "2.0.5",
        "run-parallel": "^1.1.9"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/@nodelib/fs.stat": {
      "version": "2.0.5",
      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
      "license": "MIT",
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/@nodelib/fs.walk": {
      "version": "1.2.8",
      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
      "license": "MIT",
      "dependencies": {
        "@nodelib/fs.scandir": "2.1.5",
        "fastq": "^1.6.0"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/braces": {
      "version": "3.0.3",
      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
      "license": "MIT",
      "dependencies": {
        "fill-range": "^7.1.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/fast-glob": {
      "version": "3.3.3",
      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
      "license": "MIT",
      "dependencies": {
        "@nodelib/fs.stat": "^2.0.2",
        "@nodelib/fs.walk": "^1.2.3",
        "glob-parent": "^5.1.2",
        "merge2": "^1.3.0",
        "micromatch": "^4.0.8"
      },
      "engines": {
        "node": ">=8.6.0"
      }
    },
    "node_modules/fastq": {
      "version": "1.20.1",
      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
      "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
      "license": "ISC",
      "dependencies": {
        "reusify": "^1.0.4"
      }
    },
    "node_modules/fill-range": {
      "version": "7.1.1",
      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
      "license": "MIT",
      "dependencies": {
        "to-regex-range": "^5.0.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/glob-parent": {
      "version": "5.1.2",
      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
      "license": "ISC",
      "dependencies": {
        "is-glob": "^4.0.1"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/is-extglob": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
      "license": "MIT",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/is-glob": {
      "version": "4.0.3",
      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
      "license": "MIT",
      "dependencies": {
        "is-extglob": "^2.1.1"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/is-number": {
      "version": "7.0.0",
      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
      "license": "MIT",
      "engines": {
        "node": ">=0.12.0"
      }
    },
    "node_modules/merge2": {
      "version": "1.4.1",
      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
      "license": "MIT",
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/micromatch": {
      "version": "4.0.8",
      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
      "license": "MIT",
      "dependencies": {
        "braces": "^3.0.3",
        "picomatch": "^2.3.1"
      },
      "engines": {
        "node": ">=8.6"
      }
    },
    "node_modules/picomatch": {
      "version": "2.3.2",
      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
      "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
      "license": "MIT",
      "engines": {
        "node": ">=8.6"
      },
      "funding": {
        "url": "https://github.com/sponsors/jonschlinkert"
      }
    },
    "node_modules/queue-microtask": {
      "version": "1.2.3",
      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT"
    },
    "node_modules/reusify": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
      "license": "MIT",
      "engines": {
        "iojs": ">=1.0.0",
        "node": ">=0.10.0"
      }
    },
    "node_modules/run-parallel": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "queue-microtask": "^1.2.2"
      }
    },
    "node_modules/to-regex-range": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
      "license": "MIT",
      "dependencies": {
        "is-number": "^7.0.0"
      },
      "engines": {
        "node": ">=8.0"
      }
    }
  }
}
package.json
{
  "name": "fast-glob-behavior-contract",
  "version": "1.0.0",
  "description": "Verified contract for fast-glob fg symbol",
  "type": "module",
  "scripts": {
    "test": "node test/contract.mjs"
  },
  "dependencies": {
    "fast-glob": "3.3.3"
  }
}
test/contract.mjs
import assert from 'node:assert';
import fs from 'node:fs';
import path from 'node:path';
import fg from 'fast-glob';

const fixtureDir = path.join('test_fixture');

function setupFixture() {
  fs.rmSync(fixtureDir, { recursive: true, force: true });
  fs.mkdirSync(path.join(fixtureDir, 'nested', 'deep'), { recursive: true });
  fs.mkdirSync(path.join(fixtureDir, 'nested', '[special]'), { recursive: true });

  fs.writeFileSync(path.join(fixtureDir, 'root.txt'), 'root file');
  fs.writeFileSync(path.join(fixtureDir, 'nested', 'nested.txt'), 'nested file');
  fs.writeFileSync(path.join(fixtureDir, 'nested', 'deep', 'deep.txt'), 'deep file');
  fs.writeFileSync(path.join(fixtureDir, 'nested', '[special]', 'target.txt'), 'special file');
  fs.writeFileSync(path.join(fixtureDir, 'other.log'), 'log file');
}

function cleanupFixture() {
  fs.rmSync(fixtureDir, { recursive: true, force: true });
}

setupFixture();

try {
  // Contract line 1: fg with baseNameMatch expands slashless patterns like *.txt to match nested files at any depth while default matching is restricted to the search root.
  const defaultSync = fg.sync('*.txt', { cwd: fixtureDir });
  const defaultAsync = await fg('*.txt', { cwd: fixtureDir });
  assert.deepStrictEqual(defaultSync, ['root.txt']);
  assert.deepStrictEqual(defaultAsync, ['root.txt']);

  const baseNameSync = fg.sync('*.txt', { cwd: fixtureDir, baseNameMatch: true }).sort();
  const baseNameAsync = (await fg('*.txt', { cwd: fixtureDir, baseNameMatch: true })).sort();
  const expectedBaseNameMatches = [
    'nested/[special]/target.txt',
    'nested/deep/deep.txt',
    'nested/nested.txt',
    'root.txt'
  ];
  assert.deepStrictEqual(baseNameSync, expectedBaseNameMatches);
  assert.deepStrictEqual(baseNameAsync, expectedBaseNameMatches);

  // Pattern containing slashes is not modified by baseNameMatch
  const slashPatternMatches = fg.sync('nested/*.txt', { cwd: fixtureDir, baseNameMatch: true });
  assert.deepStrictEqual(slashPatternMatches, ['nested/nested.txt']);

  // Contract line 2: fg with only negative patterns returns an empty array and fg.generateTasks yields zero tasks without at least one positive pattern.
  const negativeOnlyMatches = fg.sync(['!*.txt'], { cwd: fixtureDir });
  const negativeOnlyAsync = await fg(['!*.txt'], { cwd: fixtureDir });
  assert.deepStrictEqual(negativeOnlyMatches, []);
  assert.deepStrictEqual(negativeOnlyAsync, []);
  assert.deepStrictEqual(fg.generateTasks(['!*.txt']), []);

  const positiveAndNegative = fg.sync(['**/*.txt', '!nested/deep/**'], { cwd: fixtureDir }).sort();
  assert.deepStrictEqual(positiveAndNegative, [
    'nested/[special]/target.txt',
    'nested/nested.txt',
    'root.txt'
  ]);

  // Contract line 3: fg.isDynamicPattern classifies static paths as dynamic when caseSensitiveMatch is false, and respects braceExpansion and extglob disable flags.
  assert.strictEqual(fg.isDynamicPattern('nested/file.txt'), false);
  assert.strictEqual(fg.isDynamicPattern('nested/file.txt', { caseSensitiveMatch: false }), true);
  assert.strictEqual(fg.isDynamicPattern('nested/{a,b}.txt'), true);
  assert.strictEqual(fg.isDynamicPattern('nested/{a,b}.txt', { braceExpansion: false }), false);
  assert.strictEqual(fg.isDynamicPattern('nested/@(a|b).txt'), true);
  assert.strictEqual(fg.isDynamicPattern('nested/@(a|b).txt', { extglob: false }), false);

  // Contract line 4: fg.posix.escapePath and fg.escapePath escape brackets so literal directory paths with glob characters match their exact files.
  const rawPath = 'nested/[special]/target.txt';
  const escapedPosix = fg.posix.escapePath(rawPath);
  assert.strictEqual(escapedPosix, 'nested/\\[special\\]/target.txt');

  const matchedEscaped = fg.sync(escapedPosix, { cwd: fixtureDir });
  assert.deepStrictEqual(matchedEscaped, ['nested/[special]/target.txt']);

  // Contract line 5: fg.generateTasks partitions positive patterns into distinct static and dynamic tasks grouped by base directory.
  const tasks = fg.generateTasks(['src/index.ts', 'src/**/*.ts', 'lib/**/*.ts', '!**/*.d.ts']);
  assert.strictEqual(tasks.length, 3);

  assert.strictEqual(tasks[0].dynamic, false);
  assert.strictEqual(tasks[0].base, 'src');
  assert.deepStrictEqual(tasks[0].positive, ['src/index.ts']);
  assert.deepStrictEqual(tasks[0].negative, ['**/*.d.ts']);

  assert.strictEqual(tasks[1].dynamic, true);
  assert.strictEqual(tasks[1].base, 'src');
  assert.deepStrictEqual(tasks[1].positive, ['src/**/*.ts']);
  assert.deepStrictEqual(tasks[1].negative, ['**/*.d.ts']);

  assert.strictEqual(tasks[2].dynamic, true);
  assert.strictEqual(tasks[2].base, 'lib');
  assert.deepStrictEqual(tasks[2].positive, ['lib/**/*.ts']);
  assert.deepStrictEqual(tasks[2].negative, ['**/*.d.ts']);
} finally {
  cleanupFixture();
}

原始种子者

csx-seed