Skip to content

Commit 8452bc2

Browse files
nelsondudearcanis
andauthored
fix(fslib): handle float timestamps in convertToBigIntStats (#6988)
## Summary Fixes RangeError when converting floating-point timestamps to BigInt in the `convertToBigIntStats` function. ## Problem The `convertToBigIntStats()` function fails when file stats contain non-integer timestamps (e.g., `1763746784088.47`), throwing: ``` RangeError: The number 1763746784088.47 cannot be converted to a BigInt because it is not an integer ``` This occurs when ZIP file entries have timestamps with floating-point precision, particularly observed in Yarn 6.0.0-rc.5 when building with Storybook. ## Solution Use `Math.floor()` to ensure integer values before BigInt conversion on line 194 of `packages/yarnpkg-fslib/sources/statUtils.ts`. ## Changes - Changed `BigInt(element)` to `BigInt(Math.floor(element))` ## Testing - Tested with Yarn 6.0.0-rc.5 + Storybook build - Verified the RangeError no longer occurs with floating-point timestamps ## Related This issue was discovered while running `yarn storybook build` with Yarn 6.0.0-rc.5. --------- Co-authored-by: Maël Nison <[email protected]>
1 parent a0a55cb commit 8452bc2

File tree

7 files changed

+63
-11
lines changed

7 files changed

+63
-11
lines changed

.pnp.cjs

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.yarn/versions/78344001.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
releases:
2+
"@yarnpkg/fslib": patch
3+
4+
declined:
5+
- "@yarnpkg/plugin-catalog"
6+
- "@yarnpkg/plugin-compat"
7+
- "@yarnpkg/plugin-constraints"
8+
- "@yarnpkg/plugin-dlx"
9+
- "@yarnpkg/plugin-essentials"
10+
- "@yarnpkg/plugin-exec"
11+
- "@yarnpkg/plugin-file"
12+
- "@yarnpkg/plugin-git"
13+
- "@yarnpkg/plugin-github"
14+
- "@yarnpkg/plugin-init"
15+
- "@yarnpkg/plugin-jsr"
16+
- "@yarnpkg/plugin-link"
17+
- "@yarnpkg/plugin-nm"
18+
- "@yarnpkg/plugin-npm"
19+
- "@yarnpkg/plugin-npm-cli"
20+
- "@yarnpkg/plugin-pack"
21+
- "@yarnpkg/plugin-patch"
22+
- "@yarnpkg/plugin-pnp"
23+
- "@yarnpkg/plugin-pnpm"
24+
- "@yarnpkg/plugin-stage"
25+
- "@yarnpkg/plugin-typescript"
26+
- "@yarnpkg/plugin-version"
27+
- "@yarnpkg/plugin-workspace-tools"
28+
- vscode-zipfs
29+
- "@yarnpkg/builder"
30+
- "@yarnpkg/cli"
31+
- "@yarnpkg/core"
32+
- "@yarnpkg/doctor"
33+
- "@yarnpkg/libzip"
34+
- "@yarnpkg/nm"
35+
- "@yarnpkg/pnp"
36+
- "@yarnpkg/pnpify"
37+
- "@yarnpkg/sdks"
38+
- "@yarnpkg/shell"

packages/yarnpkg-fslib/sources/statUtils.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,18 +191,18 @@ export function convertToBigIntStats(stats: Stats): BigIntStats {
191191
const element = stats[key as keyof typeof stats];
192192
if (typeof element === `number`) {
193193
// @ts-expect-error Typescript isn't able to tell this is valid
194-
bigintStats[key as keyof typeof bigintStats] = BigInt(element);
194+
bigintStats[key as keyof typeof bigintStats] = BigInt(Math.floor(element));
195195
} else if (nodeUtils.types.isDate(element)) {
196196
// @ts-expect-error Typescript isn't able to tell this is valid
197197
bigintStats[key as keyof typeof bigintStats] = new Date(element);
198198
}
199199
}
200200
}
201201

202-
bigintStats.atimeNs = bigintStats.atimeMs * BigInt(1e6);
203-
bigintStats.mtimeNs = bigintStats.mtimeMs * BigInt(1e6);
204-
bigintStats.ctimeNs = bigintStats.ctimeMs * BigInt(1e6);
205-
bigintStats.birthtimeNs = bigintStats.birthtimeMs * BigInt(1e6);
202+
bigintStats.atimeNs = bigintStats.atimeMs * BigInt(1e6) + BigInt(Math.floor((stats.atimeMs % 1) * 1e3)) * BigInt(1e3);
203+
bigintStats.mtimeNs = bigintStats.mtimeMs * BigInt(1e6) + BigInt(Math.floor((stats.mtimeMs % 1) * 1e3)) * BigInt(1e3);
204+
bigintStats.ctimeNs = bigintStats.ctimeMs * BigInt(1e6) + BigInt(Math.floor((stats.ctimeMs % 1) * 1e3)) * BigInt(1e3);
205+
bigintStats.birthtimeNs = bigintStats.birthtimeMs * BigInt(1e6) + BigInt(Math.floor((stats.birthtimeMs % 1) * 1e3)) * BigInt(1e3);
206206

207207
return bigintStats as unknown as BigIntStats;
208208
}
583 Bytes
Binary file not shown.

packages/yarnpkg-libzip/tests/ZipOpenFS.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ export const ZIP_DIR4 = ppath.join(
1717
npath.toPortablePath(__dirname),
1818
`fixtures/symlink.zip` as Filename,
1919
);
20+
export const ZIP_DIR5 = ppath.join(
21+
npath.toPortablePath(__dirname),
22+
`fixtures/implicit-folders.zip` as Filename,
23+
);
2024

2125
export const ZIP_FILE1 = ppath.join(ZIP_DIR1, `foo.txt`);
2226
export const ZIP_FILE2 = ppath.join(ZIP_DIR2, `foo.txt`);
2327
export const ZIP_FILE3 = ppath.join(ZIP_DIR3, `foo.txt`);
2428
export const ZIP_FILE4 = ppath.join(ZIP_DIR4, `foo.txt`);
29+
export const ZIP_FILE5 = ppath.join(ZIP_DIR5, `foo.txt`);
2530

2631
afterEach(() => {
2732
jest.useRealTimers();
@@ -86,6 +91,15 @@ describe(`ZipOpenFS`, () => {
8691
fs.discardAndClose();
8792
});
8893

94+
it(`can read stats from a zip file with implicit folders`, () => {
95+
const fs = new ZipOpenFS();
96+
97+
expect(fs.statSync(ppath.join(ZIP_DIR5, `node_modules`)).isDirectory()).toBe(true);
98+
expect(fs.statSync(ppath.join(ZIP_DIR5, `node_modules`), {bigint: true}).isDirectory()).toBe(true);
99+
100+
fs.discardAndClose();
101+
});
102+
89103
it(`can read from a zip file that's a symlink`, () => {
90104
const fs = new ZipOpenFS();
91105

583 Bytes
Binary file not shown.

packages/yarnpkg-pnp/sources/hook.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)