@vzn/vx 0.0.554 → 0.0.555

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vzn/vx",
3
- "version": "0.0.554",
3
+ "version": "0.0.555",
4
4
  "description": "The fastest task runner and build cache for JavaScript monorepos.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -21,10 +21,10 @@
21
21
  "node": ">=18"
22
22
  },
23
23
  "optionalDependencies": {
24
- "@vzn/vx-linux-x64": "0.0.554",
25
- "@vzn/vx-linux-arm64": "0.0.554",
26
- "@vzn/vx-darwin-x64": "0.0.554",
27
- "@vzn/vx-darwin-arm64": "0.0.554"
24
+ "@vzn/vx-linux-x64": "0.0.555",
25
+ "@vzn/vx-linux-arm64": "0.0.555",
26
+ "@vzn/vx-darwin-x64": "0.0.555",
27
+ "@vzn/vx-darwin-arm64": "0.0.555"
28
28
  },
29
29
  "dependencies": {
30
30
  "@anthropic-ai/sandbox-runtime": "^0.0.76"
@@ -24,6 +24,9 @@ import {
24
24
  UserError,
25
25
  BUN_GLOB_WILDCARDS,
26
26
  EXTGLOB,
27
+ anyTaskGlob,
28
+ asTrees,
29
+ isLiteralPattern,
27
30
  } from '../util/index.js'
28
31
  import { nonJsonMessage, nonJsonPaths } from './json-data.js'
29
32
 
@@ -722,6 +725,7 @@ export function validateProjectConfig(config: ProjectConfig, configPath: string)
722
725
  // error for the same reason. Refusing costs nothing: such a config was
723
726
  // already silently broken, so no working key changes.
724
727
  assertNotNegationOnly((inputs as { files: string[] }).files, `${where}.cache.inputs.files`)
728
+ assertNoLiteralTakenBack((inputs as { files: string[] }).files, `${where}.cache.inputs.files`)
725
729
  // The only CacheInputs field that reached the run unvalidated: a
726
730
  // non-string entry crashes deep in `filterUpstreamHashes` /
727
731
  // `parseDependencySpec` with a raw TypeError naming neither the task
@@ -1338,6 +1342,28 @@ function assertNotNegationOnly(globs: readonly string[], where: string): void {
1338
1342
  )
1339
1343
  }
1340
1344
 
1345
+ /**
1346
+ * A `!` entry subtracts wherever it sits in the list, so a file named
1347
+ * outright after it (`['src/**', '!src/gen/**', 'src/gen/keep.ts']`) never
1348
+ * entered the key, and an edit to it replayed the old output. Refusing is
1349
+ * free: the literal already selected nothing.
1350
+ */
1351
+ function assertNoLiteralTakenBack(globs: readonly string[], where: string): void {
1352
+ const negative = globs.filter((g) => g.startsWith('!')).map((g) => g.slice(1))
1353
+ if (negative.length === 0) return
1354
+ const taken = anyTaskGlob(asTrees(negative))
1355
+ for (const g of globs) {
1356
+ if (g.startsWith('!')) continue
1357
+ const lit = normalizeGlob(g).replace(/\/+$/, '')
1358
+ if (!isLiteralPattern(lit) || !taken(lit)) continue
1359
+ const by = negative.find((n) => anyTaskGlob(asTrees([n]))(lit))
1360
+ throw new UserError(
1361
+ `${where}: "${g}" is taken back by "!${by}" — a \`!\` entry subtracts wherever it sits in ` +
1362
+ `the list, so the file never enters the key. Narrow the negation so it leaves "${g}".`,
1363
+ )
1364
+ }
1365
+ }
1366
+
1341
1367
  /**
1342
1368
  * `negation: false` for OUTPUT globs: a `!` entry takes a path back (A-44),
1343
1369
  * and a list of only negations selects nothing and is refused.
@@ -1370,8 +1396,10 @@ function validateWorkspaceGlobs(v: unknown, where: string, negation: boolean): v
1370
1396
  }
1371
1397
  assertNotDoubleNegated(g, where)
1372
1398
  }
1373
- if (negation) assertNotNegationOnly(v as string[], where)
1374
- else assertOutputsNotNegationOnly(v as string[], where)
1399
+ if (negation) {
1400
+ assertNotNegationOnly(v as string[], where)
1401
+ assertNoLiteralTakenBack(v as string[], where)
1402
+ } else assertOutputsNotNegationOnly(v as string[], where)
1375
1403
  }
1376
1404
 
1377
1405
  /**