Skip to content

Commit 8352d40

Browse files
fix(core): optimize bun lockfile parser (#33623)
Key optimisations: 1. Pre-computed PackageIndex - Built once during lockfile parsing: - byName: Map from package name → array of versions (O(1) lookup) - workspaceNames: Set of workspace package names (O(1) lookup) - workspacePaths: Set of workspace paths (O(1) lookup) - packagesWithWorkspaceVariants: Set of packages with workspace-specific variants (O(1) lookup) - patchedPackages: Set of patched package names (O(1) lookup) 2. findResolvedVersion: Changed from O(n) scan through all packages to O(1) map lookup + O(k) where k = number of versions for that package (typically 1-3) 3. isWorkspacePackage: Changed from O(n) scan to O(1) set lookup 4. hasWorkspaceSpecificVariant: Changed from O(n) scan to O(1) set lookup 5. isNestedPackageKey: Now uses pre-computed workspace paths/names sets instead of computing them each call On my 40 project typescript monorepo my time goes from about 30 seconds to 4.5s, a speed-up of 6-7x. --------- Co-authored-by: Leosvel Pérez Espinosa <[email protected]>
1 parent 77692fe commit 8352d40

2 files changed

Lines changed: 371 additions & 381 deletions

File tree

packages/nx/src/plugins/js/lock-file/bun-parser.spec.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,6 +1564,64 @@ describe('Bun Parser', () => {
15641564
expect(result['npm:is-even/is-odd/is-number']).toBeUndefined();
15651565
expect(result['npm:@quz/pkg2/is-even/is-odd/is-number']).toBeUndefined();
15661566
});
1567+
1568+
it('should correctly handle scoped package aliases without incorrectly marking as workspace variants', () => {
1569+
// This tests two potential bugs:
1570+
// 1. In buildPackageIndex: a scoped alias like "@custom/lodash" aliasing "lodash"
1571+
// could incorrectly mark "lodash" as having workspace variants because the prefix "@custom"
1572+
// starts with "@" but doesn't contain "/" (missing check).
1573+
// 2. In isNestedPackageKey: scoped aliases could be incorrectly filtered as nested packages.
1574+
const lockFileContent = JSON.stringify({
1575+
lockfileVersion: 1,
1576+
workspaces: {
1577+
'': {
1578+
name: 'test-workspace',
1579+
dependencies: {
1580+
'@custom/lodash': 'npm:[email protected]',
1581+
lodash: '^4.17.21',
1582+
},
1583+
},
1584+
},
1585+
packages: {
1586+
// Scoped alias pointing to lodash - this is NOT a workspace-specific variant,
1587+
// it's a scoped package name used as an alias
1588+
'@custom/lodash': [
1589+
'lodash@npm:[email protected]',
1590+
'',
1591+
{},
1592+
'sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==',
1593+
],
1594+
// Regular lodash entry
1595+
lodash: [
1596+
'lodash@npm:[email protected]',
1597+
'',
1598+
{},
1599+
'sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==',
1600+
],
1601+
},
1602+
});
1603+
1604+
const result = getBunTextLockfileNodes(
1605+
lockFileContent,
1606+
'scoped-alias-test'
1607+
);
1608+
1609+
// The scoped alias should be created as an alias node
1610+
// The packageKey "@custom/lodash" differs from the resolved name "lodash",
1611+
// so this should be treated as an alias, not filtered out as a nested package
1612+
expect(result['npm:@custom/lodash']).toBeDefined();
1613+
expect(result['npm:@custom/lodash'].data.version).toBe(
1614+
1615+
);
1616+
1617+
// The target package should still exist
1618+
expect(result['npm:[email protected]']).toBeDefined();
1619+
1620+
// Lodash should still be hoisted since it has a direct entry in the packages section
1621+
// and appears in workspace dependencies - the scoped alias should NOT prevent hoisting
1622+
expect(result['npm:lodash']).toBeDefined();
1623+
expect(result['npm:lodash'].data.version).toBe('4.17.21');
1624+
});
15671625
});
15681626

15691627
describe('getBunLockfileDependencies', () => {
@@ -2036,6 +2094,16 @@ describe('Bun Parser', () => {
20362094

20372095
expect(result).toMatchInlineSnapshot(`
20382096
[
2097+
{
2098+
"source": "npm:@types/[email protected]",
2099+
"target": "npm:@types/[email protected]",
2100+
"type": "static",
2101+
},
2102+
{
2103+
"source": "npm:@types/[email protected]",
2104+
"target": "npm:[email protected]",
2105+
"type": "static",
2106+
},
20392107
{
20402108
"source": "npm:[email protected]",
20412109
"target": "npm:[email protected]",

0 commit comments

Comments
 (0)