diff --git a/components/legacy/utils/zlib-deflate.ts b/components/legacy/utils/zlib-deflate.ts index 0368d0d4424f..b005822ee934 100644 --- a/components/legacy/utils/zlib-deflate.ts +++ b/components/legacy/utils/zlib-deflate.ts @@ -4,6 +4,7 @@ import zlib from 'zlib'; export default async function deflate(buffer: Buffer, filePath?: string): Promise { const deflateP = promisify(zlib.deflate); try { + // @ts-ignore should be fixed return await deflateP(buffer); } catch (err: any) { const filePathStr = filePath ? ` of "${filePath}"` : ''; diff --git a/components/legacy/utils/zlib-inflate.ts b/components/legacy/utils/zlib-inflate.ts index 36ea3d58a839..830b2cb5de88 100644 --- a/components/legacy/utils/zlib-inflate.ts +++ b/components/legacy/utils/zlib-inflate.ts @@ -4,6 +4,7 @@ import zlib from 'zlib'; export default async function inflate(buffer: Buffer, filePath?: string): Promise { const inflateP = promisify(zlib.inflate); try { + // @ts-ignore should be fixed return await inflateP(buffer); } catch (err: any) { const filePathStr = filePath ? ` of "${filePath}"` : ''; diff --git a/e2e/harmony/deps-graph.e2e.ts b/e2e/harmony/deps-graph.e2e.ts new file mode 100644 index 000000000000..ebd3ea7d7441 --- /dev/null +++ b/e2e/harmony/deps-graph.e2e.ts @@ -0,0 +1,418 @@ +import fs from 'fs'; +import { generateRandomStr } from '@teambit/toolbox.string.random'; +import { DEPS_GRAPH } from '@teambit/harmony.modules.feature-toggle'; +import { addDistTag } from '@pnpm/registry-mock'; +import { type LockfileFileV9 } from '@pnpm/lockfile.types'; +import path from 'path'; +import chai, { expect } from 'chai'; +import stripAnsi from 'strip-ansi'; +import yaml from 'js-yaml'; +import Helper from '../../src/e2e-helper/e2e-helper'; +import NpmCiRegistry, { supportNpmCiRegistryTesting } from '../npm-ci-registry'; + +chai.use(require('chai-fs')); + +(supportNpmCiRegistryTesting ? describe : describe.skip)('dependencies graph data', function () { + this.timeout(0); + let npmCiRegistry: NpmCiRegistry; + let helper: Helper; + before(() => { + helper = new Helper(); + helper.command.setFeatures(DEPS_GRAPH); + }); + after(() => { + helper.scopeHelper.destroy(); + helper.command.resetFeatures(); + }); + describe('single component', () => { + before(async () => { + helper.scopeHelper.setNewLocalAndRemoteScopes(); + npmCiRegistry = new NpmCiRegistry(helper); + npmCiRegistry.configureCiInPackageJsonHarmony(); + await npmCiRegistry.init(); + helper.command.setConfig('registry', npmCiRegistry.getRegistryUrl()); + helper.fixtures.populateComponents(1); + helper.fs.outputFile(`comp1/index.js`, `const React = require("react"); require('@pnpm.e2e/pkg-with-1-dep')`); + helper.fs.outputFile( + `comp1/index.spec.js`, + `const isOdd = require("is-odd"); test('test', () => { expect(1).toEqual(1); })` + ); + await addDistTag({ package: '@pnpm.e2e/pkg-with-1-dep', version: '100.0.0', distTag: 'latest' }); + await addDistTag({ package: '@pnpm.e2e/dep-of-pkg-with-1-dep', version: '100.0.0', distTag: 'latest' }); + helper.workspaceJsonc.addKeyValToDependencyResolver('policy', { + dependencies: { + '@pnpm.e2e/pkg-with-1-dep': '^100.0.0', + }, + }); + helper.command.install('react@18.3.1 is-odd@1.0.0'); + helper.command.snapAllComponentsWithoutBuild('--skip-tests'); + await addDistTag({ package: '@pnpm.e2e/pkg-with-1-dep', version: '100.1.0', distTag: 'latest' }); + await addDistTag({ package: '@pnpm.e2e/dep-of-pkg-with-1-dep', version: '100.1.0', distTag: 'latest' }); + }); + after(() => { + npmCiRegistry.destroy(); + helper.command.delConfig('registry'); + }); + it('should save dependencies graph to the model', () => { + const versionObj = helper.command.catComponent('comp1@latest'); + const depsGraph = JSON.parse(helper.command.catObject(versionObj.dependenciesGraphRef)); + const directDeps = depsGraph.edges.find((edge) => edge.id === '.')?.neighbours; + expect(directDeps).deep.include({ + name: 'react', + specifier: '18.3.1', + id: 'react@18.3.1', + lifecycle: 'runtime', + optional: false, + }); + expect(directDeps).deep.include({ + name: 'is-odd', + specifier: '1.0.0', + id: 'is-odd@1.0.0', + lifecycle: 'dev', + optional: false, + }); + }); + describe('sign component and use dependency graph to generate a lockfile', () => { + let signOutput: string; + let signRemote; + before(async () => { + helper.command.export(); + signRemote = helper.scopeHelper.getNewBareScope('-remote-sign'); + helper.scopeHelper.addRemoteScope(helper.scopes.remotePath, signRemote.scopePath); + const { head } = helper.command.catComponent(`${helper.scopes.remote}/comp1`); + signOutput = helper.command.sign( + [`${helper.scopes.remote}/comp1@${head}`], + '--push --log', + signRemote.scopePath + ); + }); + it('should sign successfully', () => { + expect(signOutput).to.include('the following 1 component(s) were signed with build-status "succeed"'); + }); + it('should save dependencies graph to the model', () => { + const versionObj = helper.command.catComponent('comp1@latest'); + const depsGraph = JSON.parse(helper.command.catObject(versionObj.dependenciesGraphRef)); + const directDeps = depsGraph.edges.find((edge) => edge.id === '.')?.neighbours; + expect(directDeps).deep.include({ + name: 'react', + specifier: '18.3.1', + id: 'react@18.3.1', + lifecycle: 'runtime', + optional: false, + }); + expect(directDeps).deep.include({ + name: 'is-odd', + specifier: '1.0.0', + id: 'is-odd@1.0.0', + lifecycle: 'dev', + optional: false, + }); + }); + }); + describe('imported component uses dependency graph to generate a lockfile', () => { + before(async () => { + helper.scopeHelper.reInitLocalScope(); + helper.scopeHelper.addRemoteScope(); + helper.command.import(`${helper.scopes.remote}/comp1@latest`); + }); + it('should generate a lockfile', () => { + expect(fs.readFileSync(path.join(helper.scopes.localPath, 'pnpm-lock.yaml'), 'utf8')).to.have.string( + 'restoredFromModel: true' + ); + }); + }); + }); + describe('single component and sign writes the dependency graph', () => { + before(async () => { + helper.scopeHelper.setNewLocalAndRemoteScopes(); + npmCiRegistry = new NpmCiRegistry(helper); + npmCiRegistry.configureCiInPackageJsonHarmony(); + await npmCiRegistry.init(); + helper.command.setConfig('registry', npmCiRegistry.getRegistryUrl()); + helper.fixtures.populateComponents(1); + helper.fs.outputFile(`comp1/index.js`, `const React = require("react"); require('@pnpm.e2e/pkg-with-1-dep')`); + helper.fs.outputFile( + `comp1/index.spec.js`, + `const isOdd = require("is-odd"); test('test', () => { expect(1).toEqual(1); })` + ); + await addDistTag({ package: '@pnpm.e2e/pkg-with-1-dep', version: '100.0.0', distTag: 'latest' }); + await addDistTag({ package: '@pnpm.e2e/dep-of-pkg-with-1-dep', version: '100.0.0', distTag: 'latest' }); + helper.workspaceJsonc.addKeyValToDependencyResolver('policy', { + dependencies: { + '@pnpm.e2e/pkg-with-1-dep': '^100.0.0', + }, + }); + helper.command.install('react@18.3.1 is-odd@1.0.0'); + fs.unlinkSync(path.join(helper.fixtures.scopes.localPath, 'pnpm-lock.yaml')); + helper.command.snapAllComponentsWithoutBuild('--skip-tests'); + await addDistTag({ package: '@pnpm.e2e/pkg-with-1-dep', version: '100.1.0', distTag: 'latest' }); + await addDistTag({ package: '@pnpm.e2e/dep-of-pkg-with-1-dep', version: '100.1.0', distTag: 'latest' }); + }); + after(() => { + npmCiRegistry.destroy(); + helper.command.delConfig('registry'); + }); + it('should not save dependencies graph to the model', () => { + const versionObj = helper.command.catComponent('comp1@latest'); + expect(versionObj.dependenciesGraphRef).to.be.undefined; + }); + describe('sign component and use dependency graph to generate a lockfile', () => { + let signOutput: string; + let lockfile: LockfileFileV9; + let signRemote; + before(async () => { + helper.command.export(); + signRemote = helper.scopeHelper.getNewBareScope('-remote-sign'); + helper.scopeHelper.addRemoteScope(helper.scopes.remotePath, signRemote.scopePath); + const { head } = helper.command.catComponent(`${helper.scopes.remote}/comp1`); + signOutput = helper.command.sign( + [`${helper.scopes.remote}/comp1@${head}`], + '--push --log', + signRemote.scopePath + ); + }); + it('should sign successfully', () => { + expect(signOutput).to.include('the following 1 component(s) were signed with build-status "succeed"'); + }); + it('should generate a lockfile', () => { + const capsulesDir = signOutput.match(/running installation in root dir (\/[^\s]+)/)?.[1]; + expect(capsulesDir).to.be.a('string'); + lockfile = yaml.load(fs.readFileSync(path.join(stripAnsi(capsulesDir!), 'pnpm-lock.yaml'), 'utf8')); + expect(lockfile['bit']).to.be.undefined; // eslint-disable-line + }); + }); + describe('imported component uses dependency graph to generate a lockfile', () => { + before(async () => { + helper.scopeHelper.reInitLocalScope(); + helper.scopeHelper.addRemoteScope(); + helper.command.import(`${helper.scopes.remote}/comp1@latest`); + }); + it('should generate a lockfile', () => { + expect(fs.readFileSync(path.join(helper.scopes.localPath, 'pnpm-lock.yaml'), 'utf8')).to.have.string( + 'restoredFromModel: true' + ); + }); + it('should save dependencies graph to the model', () => { + const versionObj = helper.command.catComponent('comp1@latest'); + const depsGraph = JSON.parse(helper.command.catObject(versionObj.dependenciesGraphRef)); + expect(depsGraph).to.not.be.undefined; + }); + }); + }); + describe('two components with different peer dependencies', function () { + const env1DefaultPeerVersion = '16.0.0'; + const env2DefaultPeerVersion = '17.0.0'; + let randomStr: string; + before(async () => { + randomStr = generateRandomStr(4); // to avoid publishing the same package every time the test is running + const name = `@ci/${randomStr}.{name}`; + helper.scopeHelper.setNewLocalAndRemoteScopes(); + npmCiRegistry = new NpmCiRegistry(helper); + npmCiRegistry.configureCustomNameInPackageJsonHarmony(name); + await npmCiRegistry.init(); + helper.command.setConfig('registry', npmCiRegistry.getRegistryUrl()); + + helper.env.setCustomNewEnv( + undefined, + undefined, + { + policy: { + peers: [ + { + name: 'react', + version: env1DefaultPeerVersion, + supportedRange: '^16.0.0', + }, + ], + }, + }, + false, + 'custom-react/env1', + 'custom-react/env1' + ); + helper.env.setCustomNewEnv( + undefined, + undefined, + { + policy: { + peers: [ + { + name: 'react', + version: env2DefaultPeerVersion, + supportedRange: '^17.0.0', + }, + ], + }, + }, + false, + 'custom-react/env2', + 'custom-react/env2' + ); + + helper.fixtures.populateComponents(2); + helper.extensions.workspaceJsonc.addKeyValToDependencyResolver('rootComponents', true); + await addDistTag({ package: '@pnpm.e2e/foo', version: '100.0.0', distTag: 'latest' }); + await addDistTag({ package: '@pnpm.e2e/bar', version: '100.0.0', distTag: 'latest' }); + helper.fs.outputFile( + `comp1/index.js`, + `const React = require("react"); require("@pnpm.e2e/foo"); // eslint-disable-line` + ); + helper.fs.outputFile( + `comp2/index.js`, + `const React = require("react");const comp1 = require("@ci/${randomStr}.comp1"); require("@pnpm.e2e/bar"); // eslint-disable-line` + ); + helper.extensions.addExtensionToVariant('comp1', `${helper.scopes.remote}/custom-react/env1`, {}); + helper.extensions.addExtensionToVariant('comp2', `${helper.scopes.remote}/custom-react/env2`, {}); + helper.extensions.addExtensionToVariant('custom-react', 'teambit.envs/env', {}); + helper.workspaceJsonc.addKeyValToDependencyResolver('policy', { + dependencies: { + '@pnpm.e2e/foo': '^100.0.0', + '@pnpm.e2e/bar': '^100.0.0', + }, + }); + helper.command.install('--add-missing-deps'); + helper.command.tagAllComponents('--skip-tests'); + helper.command.export(); + }); + after(() => { + npmCiRegistry.destroy(); + helper.command.delConfig('registry'); + helper.scopeHelper.destroy(); + }); + it('should save dependencies graph to the model of comp1', () => { + const versionObj = helper.command.catComponent('comp1@latest'); + const depsGraph = JSON.parse(helper.command.catObject(versionObj.dependenciesGraphRef)); + const directDependencies = depsGraph.edges.find((edge) => edge.id === '.').neighbours; + expect(directDependencies).deep.include({ + name: 'react', + specifier: '16.0.0', + id: 'react@16.0.0', + lifecycle: 'runtime', + optional: false, + }); + }); + let depsGraph2; + let depsGraph2DirectDeps; + let comp1Package; + it('should save dependencies graph to the model comp2', () => { + const versionObj = helper.command.catComponent('comp2@latest'); + depsGraph2 = JSON.parse(helper.command.catObject(versionObj.dependenciesGraphRef)); + depsGraph2DirectDeps = depsGraph2.edges.find((edge) => edge.id === '.').neighbours; + expect(depsGraph2DirectDeps).deep.include({ + name: 'react', + specifier: '17.0.0', + id: 'react@17.0.0', + lifecycle: 'runtime', + optional: false, + }); + }); + it('should replace pending version in direct dependency', () => { + expect(depsGraph2DirectDeps).deep.include({ + name: `@ci/${randomStr}.comp1`, + specifier: '*', + id: `@ci/${randomStr}.comp1@0.0.1(react@17.0.0)`, + lifecycle: 'runtime', + optional: false, + }); + }); + it('should update integrity of dependency component', () => { + comp1Package = depsGraph2.packages[`@ci/${randomStr}.comp1@0.0.1`]; + expect(comp1Package.resolution.integrity).to.match(/^sha512-/); + }); + it('should add component ID to the deps graph', () => { + expect(comp1Package.component).to.eql({ scope: helper.scopes.remote, name: 'comp1' }); + }); + describe('importing a component that depends on another component and was export together with that component', () => { + before(async () => { + helper.scopeHelper.reInitLocalScope(); + helper.scopeHelper.addRemoteScope(); + await addDistTag({ package: '@pnpm.e2e/foo', version: '100.1.0', distTag: 'latest' }); + await addDistTag({ package: '@pnpm.e2e/bar', version: '100.1.0', distTag: 'latest' }); + helper.command.import(`${helper.scopes.remote}/comp2@latest`); + }); + let lockfile: any; + it('should generate a lockfile', () => { + lockfile = yaml.load(fs.readFileSync(path.join(helper.scopes.localPath, 'pnpm-lock.yaml'), 'utf8')); + expect(lockfile.bit.restoredFromModel).to.eq(true); + }); + it('should import the component with its own resolved versions', () => { + expect(lockfile.packages).to.not.have.property('@pnpm.e2e/foo@100.1.0'); + expect(lockfile.packages).to.not.have.property('@pnpm.e2e/bar@100.1.0'); + expect(lockfile.packages).to.have.property('@pnpm.e2e/foo@100.0.0'); + expect(lockfile.packages).to.have.property('@pnpm.e2e/bar@100.0.0'); + }); + }); + }); + describe('two components exported with different peer dependencies using the same env', function () { + let randomStr: string; + before(async () => { + randomStr = generateRandomStr(4); // to avoid publishing the same package every time the test is running + const name = `@ci/${randomStr}.{name}`; + helper.scopeHelper.setNewLocalAndRemoteScopes(); + npmCiRegistry = new NpmCiRegistry(helper); + npmCiRegistry.configureCustomNameInPackageJsonHarmony(name); + await npmCiRegistry.init(); + helper.command.setConfig('registry', npmCiRegistry.getRegistryUrl()); + helper.env.setCustomNewEnv( + undefined, + undefined, + { + policy: { + peers: [ + { + name: '@pnpm.e2e/abc', + version: '*', + supportedRange: '*', + }, + ], + }, + }, + false, + 'custom-env/env', + 'custom-env/env' + ); + helper.fs.createFile('bar', 'bar.js', 'require("@pnpm.e2e/abc"); // eslint-disable-line'); + helper.command.addComponent('bar'); + helper.extensions.addExtensionToVariant('bar', `${helper.scopes.remote}/custom-env/env`, {}); + await addDistTag({ package: '@pnpm.e2e/abc', version: '1.0.0', distTag: 'latest' }); + await addDistTag({ package: '@pnpm.e2e/peer-a', version: '1.0.1', distTag: 'latest' }); + helper.command.install('--add-missing-deps'); + helper.command.tagAllComponents('--skip-tests'); + helper.command.export(); + + await addDistTag({ package: '@pnpm.e2e/abc', version: '2.0.0', distTag: 'latest' }); + await addDistTag({ package: '@pnpm.e2e/peer-a', version: '1.0.0', distTag: 'latest' }); + helper.scopeHelper.reInitLocalScope(); + helper.scopeHelper.addRemoteScope(); + helper.fs.createFile('foo', 'foo.js', `require("@pnpm.e2e/abc"); require("@ci/${randomStr}.bar");`); + helper.command.addComponent('foo'); + helper.extensions.addExtensionToVariant('foo', `${helper.scopes.remote}/custom-env/env@0.0.1`, {}); + helper.command.install('--add-missing-deps'); + helper.command.snapAllComponentsWithoutBuild('--skip-tests'); + helper.command.export(); + + helper.scopeHelper.reInitLocalScope(); + helper.scopeHelper.addRemoteScope(); + helper.command.import(`${helper.scopes.remote}/foo@latest ${helper.scopes.remote}/bar@latest`); + }); + let lockfile: any; + it('should generate a lockfile', () => { + lockfile = yaml.load(fs.readFileSync(path.join(helper.scopes.localPath, 'pnpm-lock.yaml'), 'utf8')); + expect(lockfile.bit.restoredFromModel).to.eq(true); + }); + it('should resolve to one version of the peer dependency, the highest one', () => { + expect(lockfile.packages).to.not.have.property('@pnpm.e2e/peer-a@1.0.0'); + expect(lockfile.packages).to.not.have.property('@pnpm.e2e/abc@1.0.0'); + expect(lockfile.packages).to.have.property('@pnpm.e2e/peer-a@1.0.1'); + expect(lockfile.packages).to.have.property('@pnpm.e2e/abc@2.0.0'); + }); + it('imported component is not installed as a dependency', () => { + expect(lockfile.packages).to.not.have.property(`@ci/${randomStr}.bar@0.0.1`); + }); + after(() => { + npmCiRegistry.destroy(); + helper.command.delConfig('registry'); + helper.scopeHelper.destroy(); + }); + }); +}); diff --git a/package.json b/package.json index 4a6d070ca2a7..5e51c40e676b 100644 --- a/package.json +++ b/package.json @@ -117,6 +117,8 @@ "memoizee": "0.4.15", "socks-proxy-agent": "5.0.0", "yaml": "1.10.2", + "@pnpm/dependency-path": "900.0.0", + "@pnpm/lockfile.types": "^900.0.0", "@pnpm/node-fetch": "^1.0.0", "@teambit/defender.fs.global-bit-temp-dir": "0.0.1", "@teambit/legacy.analytics": "~0.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed7ce2324c64..a82453441e44 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -130,6 +130,15 @@ importers: '@pnpm/lockfile-file': specifier: 9.1.3 version: 9.1.3(@pnpm/logger@900.0.0) + '@pnpm/lockfile.filtering': + specifier: ^900.0.0 + version: 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/lockfile.fs': + specifier: ^900.0.0 + version: 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/lockfile.types': + specifier: ^900.0.0 + version: 900.0.0 '@pnpm/logger': specifier: 900.0.0 version: 900.0.0 @@ -1699,6 +1708,9 @@ importers: jest-watcher: specifier: 29.7.0 version: 29.7.0 + js-yaml: + specifier: npm:@zkochan/js-yaml@0.0.7 + version: '@zkochan/js-yaml@0.0.7' json-formatter-js: specifier: 2.3.4 version: 2.3.4 @@ -1961,8 +1973,8 @@ importers: specifier: ^0.64.1 version: 0.64.4(@babel/core@7.19.6)(@babel/preset-env@7.23.2(@babel/core@7.19.6))(bufferutil@4.0.3)(encoding@0.1.13)(react@17.0.2)(utf-8-validate@5.0.5) react-native-web: - specifier: 0.14.13 - version: 0.14.13(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + specifier: '>=0.16.0 <0.17.0' + version: 0.16.5(encoding@0.1.13)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) react-refresh: specifier: 0.10.0 version: 0.10.0 @@ -26265,6 +26277,9 @@ importers: '@pnpm/default-reporter': specifier: 900.0.0 version: 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/dependency-path': + specifier: 900.0.0 + version: 900.0.0 '@pnpm/error': specifier: 900.0.0 version: 900.0.0 @@ -26274,6 +26289,15 @@ importers: '@pnpm/lockfile-file': specifier: 9.1.3 version: 9.1.3(@pnpm/logger@900.0.0) + '@pnpm/lockfile.filtering': + specifier: ^900.0.0 + version: 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/lockfile.fs': + specifier: ^900.0.0 + version: 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/lockfile.types': + specifier: ^900.0.0 + version: 900.0.0 '@pnpm/logger': specifier: 900.0.0 version: 900.0.0 @@ -26716,19 +26740,19 @@ importers: version: 17.0.25 '@typescript-eslint/eslint-plugin': specifier: 7.1.0 - version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3) + version: 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0)(typescript@5.5.4) '@typescript-eslint/parser': specifier: 7.1.0 - version: 7.1.0(eslint@8.56.0)(typescript@5.5.3) + version: 7.1.0(eslint@8.56.0)(typescript@5.5.4) eslint-mdx: specifier: 1.17.1 version: 1.17.1(eslint@8.56.0) eslint-plugin-import: specifier: 2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0) + version: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0) eslint-plugin-jest: specifier: 27.6.3 - version: 27.6.3(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(jest@29.3.1(@types/node@20.12.10))(typescript@5.5.3) + version: 27.6.3(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0)(jest@29.3.1(@types/node@20.12.10))(typescript@5.5.4) eslint-plugin-jsx-a11y: specifier: 6.8.0 version: 6.8.0(eslint@8.56.0) @@ -33767,9 +33791,15 @@ importers: '@types/react-dom': specifier: ^17.0.21 version: 17.0.25 + assert: + specifier: ^2.1.0 + version: 2.1.0 browserify-zlib: specifier: 0.2.0 version: 0.2.0 + buffer: + specifier: 6.0.3 + version: 6.0.3 camelcase: specifier: 6.2.0 version: 6.2.0 @@ -33788,6 +33818,9 @@ importers: enhanced-resolve: specifier: 4.5.0 version: 4.5.0 + events: + specifier: ^3.3.0 + version: 3.3.0 expose-loader: specifier: 3.1.0 version: 3.1.0(webpack@5.84.1(esbuild@0.14.29)) @@ -33824,6 +33857,9 @@ importers: process: specifier: 0.11.10 version: 0.11.10 + punycode: + specifier: ^2.3.1 + version: 2.3.1 querystring-es3: specifier: 0.2.1 version: 0.2.1 @@ -33845,12 +33881,21 @@ importers: stream-http: specifier: 3.2.0 version: 3.2.0 + string_decoder: + specifier: ^1.3.0 + version: 1.3.0 timers-browserify: specifier: 2.0.12 version: 2.0.12 tty-browserify: specifier: 0.0.1 version: 0.0.1 + url: + specifier: ^0.11.3 + version: 0.11.4 + util: + specifier: ^0.12.5 + version: 0.12.5 vm-browserify: specifier: 1.1.2 version: 1.1.2 @@ -37585,13 +37630,8 @@ packages: '@szhsin/react-menu@3.3.1': resolution: {integrity: sha512-e8vK+N1YWwTdYXElvRRf5GIImtcDecqTCzpAa0DkGAknKwfQwtQtUnBn+DECodwsWi5H5ONKTU+kn0qJ70hEYQ==} peerDependencies: - react: '*' - react-dom: '*' - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + react: '>=16.14.0' + react-dom: '>=16.14.0' '@szmarczak/http-timer@4.0.6': resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} @@ -38003,13 +38043,8 @@ packages: '@teambit/base-ui.elements.image@1.0.0': resolution: {integrity: sha512-33kB66RvIaSRipV7mwL/IMwwOEThFRF4myHPFBSaF8rXmmJLKInm6bN1dWZ77gKcRlOtwJWq/UJMStC/EWtksA==, tarball: https://registry.npmjs.org/@teambit/base-ui.elements.image/-/base-ui.elements.image-1.0.0.tgz} peerDependencies: - react: '*' - react-dom: '*' - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 '@teambit/base-ui.graph.tree.collapsable-tree-node@0.0.10': resolution: {integrity: sha512-vZxGHBu3JnUe7KepnTQSbhuXErcriTakAKNIihhq7DPxnGgrc4NtuxBiBpQNBEIMiXpXHd6Zh/+EV6eJl6oVDg==} @@ -38128,8 +38163,8 @@ packages: '@teambit/base-ui.layout.grid-component@1.0.2': resolution: {integrity: sha512-/G/WOO98NHdLuEBAlctrgIWQuBMi96zLSyd55waivNFHm1RKgTzfLup/gdsnGbqhG1mYTfqboPUQI7OF1XmUQg==} peerDependencies: - react: '*' - react-dom: '*' + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 '@teambit/base-ui.layout.page-frame@1.0.0': resolution: {integrity: sha512-X+lWlURlRu528ink+3e7eqQt866UMYGI3DdPC7FAJ3v1CW0p0+O95K+/mxNmYvQLtW4y2iJ+2rrv/el27d6/Xw==} @@ -38233,13 +38268,8 @@ packages: '@teambit/base-ui.surfaces.abs-container@1.0.1': resolution: {integrity: sha1-51b87xnd65dXa3utstNjz7HXmtM=, tarball: https://node-registry.bit.cloud/tarballs/teambit.base-ui/surfaces/abs-container@1.0.1.tgz} peerDependencies: - react: '*' - react-dom: '*' - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 '@teambit/base-ui.surfaces.background@1.0.1': resolution: {integrity: sha512-VHPPrzqkHUiYkbief6QtxCbTXUcCh69xMtkbrAsIJXZjrAAN1GhNX2PrErEEaCRIXW1joo06zekyth0+vT1HUg==} @@ -38274,13 +38304,8 @@ packages: '@teambit/base-ui.surfaces.drawer@1.1.3': resolution: {integrity: sha1-EmfvFFxPhsVm6B9oBq1W7S4wzLA=, tarball: https://node-registry.bit.cloud/tarballs/teambit.base-ui/surfaces/drawer@1.1.3.tgz} peerDependencies: - react: '*' - react-dom: '*' - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 '@teambit/base-ui.surfaces.split-pane.hover-splitter@1.0.0': resolution: {integrity: sha512-sbN1AgGvc3lzoeWg7KQrYD9lCa4V9s0EctfZSrPCwy/UcHGePgMipBOWJkcNwuq8GGhzSTzH8rP8McWCLUGdew==} @@ -38309,13 +38334,8 @@ packages: '@teambit/base-ui.surfaces.split-pane.splitter@1.0.0': resolution: {integrity: sha512-5/oGHEUOQQnQUi2911fLb/rdFLLDoMy1G4fQ4DNkqoHcahi1a26tCtKlV+7FAI1LsFdk0V+wRp6WY+kX+Qbsxw==, tarball: https://registry.npmjs.org/@teambit/base-ui.surfaces.split-pane.splitter/-/base-ui.surfaces.split-pane.splitter-1.0.0.tgz} peerDependencies: - react: '*' - react-dom: '*' - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 '@teambit/base-ui.text.heading@1.0.1': resolution: {integrity: sha512-P6N4Mx5YUuCnkVXwpG5UK2/5b56aXJCHq2LRiqambZM/lZbLX2qO+CNolRjYztRf2cXea6/ToUdjAn+BPcwXXA==, tarball: https://registry.npmjs.org/@teambit/base-ui.text.heading/-/base-ui.text.heading-1.0.1.tgz} @@ -55384,7 +55404,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.22.3 convert-source-map: 1.9.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 lodash: 4.17.21 @@ -55405,7 +55425,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.22.3 convert-source-map: 1.9.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 lodash: 4.17.21 @@ -55428,7 +55448,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.22.3 convert-source-map: 1.9.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -55448,7 +55468,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.22.3 convert-source-map: 1.9.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -55468,7 +55488,7 @@ snapshots: '@babel/traverse': 7.25.9 '@babel/types': 7.26.0 convert-source-map: 2.0.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -55591,7 +55611,7 @@ snapshots: '@babel/core': 7.12.9 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55602,7 +55622,7 @@ snapshots: '@babel/core': 7.19.6 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55613,7 +55633,7 @@ snapshots: '@babel/core': 7.20.2 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55624,7 +55644,7 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55635,7 +55655,7 @@ snapshots: '@babel/core': 7.12.9 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55646,7 +55666,7 @@ snapshots: '@babel/core': 7.19.6 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55657,7 +55677,7 @@ snapshots: '@babel/core': 7.20.2 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55668,7 +55688,7 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55679,7 +55699,7 @@ snapshots: '@babel/core': 7.12.9 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55690,7 +55710,7 @@ snapshots: '@babel/core': 7.19.6 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55701,7 +55721,7 @@ snapshots: '@babel/core': 7.20.2 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -55712,7 +55732,7 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-compilation-targets': 7.25.9 '@babel/helper-plugin-utils': 7.25.9 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash.debounce: 4.0.8 resolve: 1.20.0 transitivePeerDependencies: @@ -59587,7 +59607,7 @@ snapshots: '@babel/parser': 7.26.2 '@babel/template': 7.25.9 '@babel/types': 7.26.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -59917,7 +59937,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -60033,7 +60053,7 @@ snapshots: '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) minimatch: 3.0.5 transitivePeerDependencies: - supports-color @@ -63527,10 +63547,9 @@ snapshots: '@szhsin/react-menu@3.3.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: prop-types: 15.8.1 - react-transition-state: 1.1.5(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - optionalDependencies: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) + react-transition-state: 1.1.5(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@szmarczak/http-timer@4.0.6': dependencies: @@ -65364,7 +65383,6 @@ snapshots: dependencies: classnames: 2.2.6 core-js: 3.13.0 - optionalDependencies: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) @@ -65719,9 +65737,8 @@ snapshots: dependencies: classnames: 2.2.6 core-js: 3.13.0 - react-create-ref: 1.0.1(react@17.0.2) - optionalDependencies: react: 17.0.2 + react-create-ref: 1.0.1(react@17.0.2) react-dom: 17.0.2(react@17.0.2) '@teambit/base-ui.surfaces.background@1.0.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': @@ -65788,9 +65805,8 @@ snapshots: '@teambit/base-ui.surfaces.abs-container': 1.0.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2) classnames: 2.2.6 core-js: 3.13.0 - react-create-ref: 1.0.1(react@17.0.2) - optionalDependencies: react: 17.0.2 + react-create-ref: 1.0.1(react@17.0.2) react-dom: 17.0.2(react@17.0.2) '@teambit/base-ui.surfaces.split-pane.hover-splitter@1.0.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': @@ -65861,7 +65877,6 @@ snapshots: dependencies: classnames: 2.2.6 core-js: 3.13.0 - optionalDependencies: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) @@ -65869,7 +65884,6 @@ snapshots: dependencies: classnames: 2.2.6 core-js: 3.13.0 - optionalDependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -71616,7 +71630,7 @@ snapshots: archy: 1.0.0 chalk: 2.4.2 cli-table: 0.3.6 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) detective-amd: 3.0.1 detective-stylus: 1.0.0 fs-extra: 10.0.0 @@ -71679,7 +71693,7 @@ snapshots: archy: 1.0.0 chalk: 2.4.2 cli-table: 0.3.6 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) detective-amd: 3.0.1 detective-stylus: 1.0.0 fs-extra: 10.0.0 @@ -71719,6 +71733,7 @@ snapshots: '@teambit/component.sources': file:scopes/component/sources '@teambit/dependencies.aspect-docs.dependency-resolver': file:scopes/dependencies/aspect-docs/dependency-resolver(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@teambit/harmony': 0.4.6 + '@teambit/harmony.modules.feature-toggle': file:scopes/harmony/modules/feature-toggle '@teambit/harmony.modules.requireable-component': file:scopes/harmony/modules/requireable-component '@teambit/legacy-bit-id': 1.1.1 '@teambit/mdx.ui.mdx-scope-context': 1.0.7(@types/react@17.0.83)(react@17.0.2) @@ -71779,6 +71794,7 @@ snapshots: '@teambit/component.sources': file:scopes/component/sources '@teambit/dependencies.aspect-docs.dependency-resolver': file:scopes/dependencies/aspect-docs/dependency-resolver(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@teambit/harmony': 0.4.6 + '@teambit/harmony.modules.feature-toggle': file:scopes/harmony/modules/feature-toggle '@teambit/harmony.modules.requireable-component': file:scopes/harmony/modules/requireable-component '@teambit/legacy-bit-id': 1.1.1 '@teambit/mdx.ui.mdx-scope-context': 1.0.7(@types/react@17.0.83)(react@17.0.2) @@ -71839,6 +71855,7 @@ snapshots: '@teambit/component.sources': file:scopes/component/sources '@teambit/dependencies.aspect-docs.dependency-resolver': file:scopes/dependencies/aspect-docs/dependency-resolver(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@teambit/harmony': 0.4.6 + '@teambit/harmony.modules.feature-toggle': file:scopes/harmony/modules/feature-toggle '@teambit/harmony.modules.requireable-component': file:scopes/harmony/modules/requireable-component '@teambit/legacy-bit-id': 1.1.1 '@teambit/mdx.ui.mdx-scope-context': 1.0.7(@types/react@17.0.83)(react@17.0.2) @@ -76320,7 +76337,7 @@ snapshots: '@types/react': 17.0.83 '@types/react-dom': 17.0.25 chalk: 2.4.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) execa: 2.1.0 filenamify: 4.2.0 fs-extra: 10.0.0 @@ -78977,9 +78994,13 @@ snapshots: '@pnpm/config': 900.0.0(@pnpm/logger@900.0.0) '@pnpm/core': 900.0.1(@pnpm/logger@900.0.0)(@pnpm/worker@900.0.0(@pnpm/logger@900.0.0)(@types/node@20.12.10))(@types/node@20.12.10)(@yarnpkg/core@3.5.2(typanion@3.14.0))(typanion@3.14.0) '@pnpm/default-reporter': 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/dependency-path': 900.0.0 '@pnpm/error': 900.0.0 '@pnpm/list': 900.0.0(@pnpm/logger@900.0.0) '@pnpm/lockfile-file': 9.1.3(@pnpm/logger@900.0.0) + '@pnpm/lockfile.filtering': 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/lockfile.fs': 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/lockfile.types': 900.0.0 '@pnpm/logger': 900.0.0 '@pnpm/modules-yaml': 900.0.0 '@pnpm/package-store': 900.0.0(@pnpm/logger@900.0.0)(@pnpm/worker@900.0.0(@pnpm/logger@900.0.0)(@types/node@20.12.10)) @@ -78995,6 +79016,7 @@ snapshots: '@teambit/dependencies.aspect-docs.pnpm': file:scopes/dependencies/aspect-docs/pnpm(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@teambit/dependencies.pnpm.dep-path': 0.0.2 '@teambit/harmony': 0.4.6 + '@teambit/harmony.modules.feature-toggle': file:scopes/harmony/modules/feature-toggle '@teambit/mdx.ui.mdx-scope-context': 1.0.7(@types/react@17.0.83)(react@17.0.2) '@teambit/toolbox.string.strip-trailing-char': file:scopes/toolbox/string/strip-trailing-char '@teambit/ui-foundation.ui.use-box.menu': 1.0.15(@testing-library/react@12.1.5(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(@types/react@17.0.83)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) @@ -79031,9 +79053,13 @@ snapshots: '@pnpm/config': 900.0.0(@pnpm/logger@900.0.0) '@pnpm/core': 900.0.1(@pnpm/logger@900.0.0)(@pnpm/worker@900.0.0(@pnpm/logger@900.0.0)(@types/node@20.12.10))(@types/node@20.12.10)(@yarnpkg/core@4.1.6(typanion@3.14.0))(typanion@3.14.0) '@pnpm/default-reporter': 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/dependency-path': 900.0.0 '@pnpm/error': 900.0.0 '@pnpm/list': 900.0.0(@pnpm/logger@900.0.0) '@pnpm/lockfile-file': 9.1.3(@pnpm/logger@900.0.0) + '@pnpm/lockfile.filtering': 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/lockfile.fs': 900.0.0(@pnpm/logger@900.0.0) + '@pnpm/lockfile.types': 900.0.0 '@pnpm/logger': 900.0.0 '@pnpm/modules-yaml': 900.0.0 '@pnpm/package-store': 900.0.0(@pnpm/logger@900.0.0)(@pnpm/worker@900.0.0(@pnpm/logger@900.0.0)(@types/node@20.12.10)) @@ -79049,6 +79075,7 @@ snapshots: '@teambit/dependencies.aspect-docs.pnpm': file:scopes/dependencies/aspect-docs/pnpm(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@teambit/dependencies.pnpm.dep-path': 0.0.2 '@teambit/harmony': 0.4.6 + '@teambit/harmony.modules.feature-toggle': file:scopes/harmony/modules/feature-toggle '@teambit/mdx.ui.mdx-scope-context': 1.0.7(@types/react@17.0.83)(react@17.0.2) '@teambit/toolbox.string.strip-trailing-char': file:scopes/toolbox/string/strip-trailing-char '@teambit/ui-foundation.ui.use-box.menu': 1.0.15(@testing-library/react@12.1.5(react-dom@17.0.2(react@17.0.2))(react@17.0.2))(@types/react@17.0.83)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) @@ -81303,12 +81330,12 @@ snapshots: - supports-color - typescript - '@teambit/react.eslint-config-bit-react@1.0.224(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0)(typescript@5.5.3)': + '@teambit/react.eslint-config-bit-react@1.0.224(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0)(typescript@5.5.3)': dependencies: '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/parser': 7.1.0(eslint@8.56.0)(typescript@5.5.3) eslint: 8.56.0 - eslint-config-airbnb-typescript: 12.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0)(typescript@5.5.3) + eslint-config-airbnb-typescript: 12.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0)(typescript@5.5.3) eslint-config-prettier: 8.5.0(eslint@8.56.0) eslint-plugin-mdx: 1.17.1(eslint@8.56.0) transitivePeerDependencies: @@ -82023,7 +82050,7 @@ snapshots: '@teambit/mdx.ui.mdx-scope-context': 1.0.7(@types/react@17.0.83)(react@18.3.1) '@teambit/preview.react-preview': 1.0.66(@babel/core@7.12.9)(@parcel/css@1.14.0)(@swc/css@0.0.20)(@testing-library/react@13.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react-dom@17.0.25)(@types/react@17.0.83)(@types/webpack@5.28.1(esbuild@0.14.29))(bufferutil@4.0.3)(debug@4.3.4)(encoding@0.1.13)(esbuild@0.14.29)(eslint@8.56.0)(graphql@15.8.0)(less@4.2.1)(lightningcss@1.28.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@0.21.3)(typescript@5.5.3)(utf-8-validate@5.0.5) '@teambit/react.apps.react-app-types': 2.0.6(@babel/core@7.12.9)(@parcel/css@1.14.0)(@swc/css@0.0.20)(@testing-library/react@13.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@17.0.83)(@types/webpack@5.28.1(esbuild@0.14.29))(bufferutil@4.0.3)(debug@4.3.4)(esbuild@0.14.29)(eslint@8.56.0)(less@4.2.1)(lightningcss@1.28.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@0.21.3)(typescript@5.5.3)(utf-8-validate@5.0.5)(webpack-dev-server@4.15.0(bufferutil@4.0.3)(debug@4.3.4)(utf-8-validate@5.0.5)(webpack@5.84.1(esbuild@0.14.29))) - '@teambit/react.eslint-config-bit-react': 1.0.224(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0)(typescript@5.5.3) + '@teambit/react.eslint-config-bit-react': 1.0.224(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0)(typescript@5.5.3) '@teambit/react.generator.react-starters': 1.0.8 '@teambit/react.generator.react-templates': 1.0.12 '@teambit/react.jest.react-jest': 1.0.34(@babel/core@7.12.9)(@babel/traverse@7.25.9)(bufferutil@4.0.3)(jest@29.3.1(@types/node@20.12.10))(utf-8-validate@5.0.5) @@ -89758,13 +89785,16 @@ snapshots: '@types/node': 20.12.10 '@types/react': 17.0.83 '@types/react-dom': 17.0.25 + assert: 2.1.0 browserify-zlib: 0.2.0 + buffer: 6.0.3 camelcase: 6.2.0 compression-webpack-plugin: 11.0.0(webpack@5.84.1(esbuild@0.14.29)) constants-browserify: 1.0.0 crypto-browserify: 3.12.0 domain-browser: 4.19.0 enhanced-resolve: 4.5.0 + events: 3.3.0 expose-loader: 3.1.0(webpack@5.84.1(esbuild@0.14.29)) find-root: 1.1.0 graphql: 15.8.0 @@ -89777,6 +89807,7 @@ snapshots: p-map-series: 2.1.0 path-browserify: 1.0.1 process: 0.11.10 + punycode: 2.3.1 querystring-es3: 0.2.1 react: 17.0.2 react-dev-utils: 11.0.4(eslint@8.56.0)(typescript@5.3.3)(webpack@5.84.1(esbuild@0.14.29)) @@ -89784,8 +89815,11 @@ snapshots: react-router-dom: 6.28.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2) stream-browserify: 3.0.0 stream-http: 3.2.0 + string_decoder: 1.3.0 timers-browserify: 2.0.12 tty-browserify: 0.0.1 + url: 0.11.4 + util: 0.12.5 vm-browserify: 1.1.2 webpack: 5.84.1(esbuild@0.14.29) webpack-assets-manifest: 5.1.0(webpack@5.84.1(esbuild@0.14.29)) @@ -89825,13 +89859,16 @@ snapshots: '@types/node': 20.12.10 '@types/react': 17.0.83 '@types/react-dom': 17.0.25 + assert: 2.1.0 browserify-zlib: 0.2.0 + buffer: 6.0.3 camelcase: 6.2.0 compression-webpack-plugin: 11.0.0(webpack@5.84.1(esbuild@0.14.29)) constants-browserify: 1.0.0 crypto-browserify: 3.12.0 domain-browser: 4.19.0 enhanced-resolve: 4.5.0 + events: 3.3.0 expose-loader: 3.1.0(webpack@5.84.1(esbuild@0.14.29)) find-root: 1.1.0 graphql: 15.8.0 @@ -89844,6 +89881,7 @@ snapshots: p-map-series: 2.1.0 path-browserify: 1.0.1 process: 0.11.10 + punycode: 2.3.1 querystring-es3: 0.2.1 react: 17.0.2 react-dev-utils: 11.0.4(eslint@8.56.0)(typescript@5.5.4)(webpack@5.84.1(esbuild@0.14.29)) @@ -89851,8 +89889,11 @@ snapshots: react-router-dom: 6.28.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2) stream-browserify: 3.0.0 stream-http: 3.2.0 + string_decoder: 1.3.0 timers-browserify: 2.0.12 tty-browserify: 0.0.1 + url: 0.11.4 + util: 0.12.5 vm-browserify: 1.1.2 webpack: 5.84.1(esbuild@0.14.29) webpack-assets-manifest: 5.1.0(webpack@5.84.1(esbuild@0.14.29)) @@ -91318,7 +91359,7 @@ snapshots: '@typescript-eslint/type-utils': 6.19.1(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/utils': 6.19.1(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -91338,7 +91379,7 @@ snapshots: '@typescript-eslint/type-utils': 6.19.1(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/utils': 6.19.1(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -91358,7 +91399,7 @@ snapshots: '@typescript-eslint/type-utils': 6.19.1(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/utils': 6.19.1(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -91378,7 +91419,7 @@ snapshots: '@typescript-eslint/type-utils': 6.19.1(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/utils': 6.19.1(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -91398,7 +91439,7 @@ snapshots: '@typescript-eslint/type-utils': 6.19.1(eslint@8.56.0)(typescript@5.5.4) '@typescript-eslint/utils': 6.19.1(eslint@8.56.0)(typescript@5.5.4) '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -91418,7 +91459,7 @@ snapshots: '@typescript-eslint/type-utils': 7.1.0(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/utils': 7.1.0(eslint@8.56.0)(typescript@5.3.3) '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -91438,7 +91479,7 @@ snapshots: '@typescript-eslint/type-utils': 7.1.0(eslint@8.56.0)(typescript@5.5.4) '@typescript-eslint/utils': 7.1.0(eslint@8.56.0)(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -91458,7 +91499,7 @@ snapshots: '@typescript-eslint/type-utils': 7.1.0(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/utils': 7.1.0(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -91478,7 +91519,7 @@ snapshots: '@typescript-eslint/type-utils': 7.1.0(eslint@8.56.0)(typescript@5.5.4) '@typescript-eslint/utils': 7.1.0(eslint@8.56.0)(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -91495,7 +91536,7 @@ snapshots: '@typescript-eslint/scope-manager': 4.4.1 '@typescript-eslint/types': 4.4.1 '@typescript-eslint/typescript-estree': 4.4.1(typescript@5.3.3) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 optionalDependencies: typescript: 5.3.3 @@ -91507,7 +91548,7 @@ snapshots: '@typescript-eslint/scope-manager': 4.4.1 '@typescript-eslint/types': 4.4.1 '@typescript-eslint/typescript-estree': 4.4.1(typescript@5.5.3) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 optionalDependencies: typescript: 5.5.3 @@ -91519,7 +91560,7 @@ snapshots: '@typescript-eslint/scope-manager': 4.4.1 '@typescript-eslint/types': 4.4.1 '@typescript-eslint/typescript-estree': 4.4.1(typescript@5.5.4) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 optionalDependencies: typescript: 5.5.4 @@ -91532,7 +91573,7 @@ snapshots: '@typescript-eslint/types': 6.19.1 '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 optionalDependencies: typescript: 5.3.3 @@ -91545,7 +91586,7 @@ snapshots: '@typescript-eslint/types': 6.19.1 '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.5.3) '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 optionalDependencies: typescript: 5.5.3 @@ -91558,7 +91599,7 @@ snapshots: '@typescript-eslint/types': 6.19.1 '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.5.4) '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 optionalDependencies: typescript: 5.5.4 @@ -91571,7 +91612,7 @@ snapshots: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 optionalDependencies: typescript: 5.3.3 @@ -91584,7 +91625,7 @@ snapshots: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.5.3) '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 optionalDependencies: typescript: 5.5.3 @@ -91597,7 +91638,7 @@ snapshots: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 optionalDependencies: typescript: 5.5.4 @@ -91628,7 +91669,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.3.3) '@typescript-eslint/utils': 6.19.1(eslint@8.56.0)(typescript@5.3.3) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 ts-api-utils: 1.4.3(typescript@5.3.3) optionalDependencies: @@ -91640,7 +91681,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.5.3) '@typescript-eslint/utils': 6.19.1(eslint@8.56.0)(typescript@5.5.3) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 ts-api-utils: 1.4.3(typescript@5.5.3) optionalDependencies: @@ -91652,7 +91693,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.5.4) '@typescript-eslint/utils': 6.19.1(eslint@8.56.0)(typescript@5.5.4) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 ts-api-utils: 1.4.3(typescript@5.5.4) optionalDependencies: @@ -91664,7 +91705,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3) '@typescript-eslint/utils': 7.1.0(eslint@8.56.0)(typescript@5.3.3) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 ts-api-utils: 1.4.3(typescript@5.3.3) optionalDependencies: @@ -91676,7 +91717,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.5.3) '@typescript-eslint/utils': 7.1.0(eslint@8.56.0)(typescript@5.5.3) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 ts-api-utils: 1.4.3(typescript@5.5.3) optionalDependencies: @@ -91688,7 +91729,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.1.0(typescript@5.5.4) '@typescript-eslint/utils': 7.1.0(eslint@8.56.0)(typescript@5.5.4) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 ts-api-utils: 1.4.3(typescript@5.5.4) optionalDependencies: @@ -91710,7 +91751,7 @@ snapshots: dependencies: '@typescript-eslint/types': 4.4.1 '@typescript-eslint/visitor-keys': 4.4.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.0.1 is-glob: 4.0.1 lodash: 4.17.21 @@ -91725,7 +91766,7 @@ snapshots: dependencies: '@typescript-eslint/types': 4.4.1 '@typescript-eslint/visitor-keys': 4.4.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.0.1 is-glob: 4.0.1 lodash: 4.17.21 @@ -91740,7 +91781,7 @@ snapshots: dependencies: '@typescript-eslint/types': 4.4.1 '@typescript-eslint/visitor-keys': 4.4.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.0.1 is-glob: 4.0.1 lodash: 4.17.21 @@ -91755,7 +91796,7 @@ snapshots: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.2 @@ -91769,7 +91810,7 @@ snapshots: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.2 @@ -91783,7 +91824,7 @@ snapshots: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.2 @@ -91797,7 +91838,7 @@ snapshots: dependencies: '@typescript-eslint/types': 6.19.1 '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -91812,7 +91853,7 @@ snapshots: dependencies: '@typescript-eslint/types': 6.19.1 '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -91827,7 +91868,7 @@ snapshots: dependencies: '@typescript-eslint/types': 6.19.1 '@typescript-eslint/visitor-keys': 6.19.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -91842,7 +91883,7 @@ snapshots: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -91857,7 +91898,7 @@ snapshots: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -91872,7 +91913,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -91887,7 +91928,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -91902,7 +91943,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.1.0 '@typescript-eslint/visitor-keys': 7.1.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -92132,7 +92173,7 @@ snapshots: '@verdaccio/file-locking': 10.3.1 '@verdaccio/streams': 10.2.1 async: 3.2.4 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash: 4.17.21 lowdb: 1.0.0 mkdirp: 1.0.4 @@ -93145,19 +93186,19 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color agent-base@7.1.1: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color agentkeepalive@4.1.4: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) depd: 1.1.2 humanize-ms: 1.2.1 transitivePeerDependencies: @@ -93165,7 +93206,7 @@ snapshots: agentkeepalive@4.2.1: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) depd: 1.1.2 humanize-ms: 1.2.1 transitivePeerDependencies: @@ -95832,10 +95873,6 @@ snapshots: optionalDependencies: supports-color: 8.1.1 - debug@4.3.4: - dependencies: - ms: 2.1.2 - debug@4.3.4(supports-color@8.1.1): dependencies: ms: 2.1.2 @@ -96560,14 +96597,6 @@ snapshots: object.assign: 4.1.5 object.entries: 1.1.8 - eslint-config-airbnb-base@14.2.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0))(eslint@8.56.0): - dependencies: - confusing-browser-globals: 1.0.11 - eslint: 8.56.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0) - object.assign: 4.1.5 - object.entries: 1.1.8 - eslint-config-airbnb-base@14.2.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0))(eslint@8.56.0): dependencies: confusing-browser-globals: 1.0.11 @@ -96660,12 +96689,12 @@ snapshots: - supports-color - typescript - eslint-config-airbnb-typescript@12.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0)(typescript@5.5.3): + eslint-config-airbnb-typescript@12.0.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0)(typescript@5.5.3): dependencies: '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3) '@typescript-eslint/parser': 4.4.1(eslint@8.56.0)(typescript@5.5.3) - eslint-config-airbnb: 18.2.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0) - eslint-config-airbnb-base: 14.2.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0))(eslint@8.56.0) + eslint-config-airbnb: 18.2.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0) + eslint-config-airbnb-base: 14.2.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0))(eslint@8.56.0) transitivePeerDependencies: - eslint - eslint-plugin-import @@ -96746,17 +96775,6 @@ snapshots: object.assign: 4.1.5 object.entries: 1.1.8 - eslint-config-airbnb@18.2.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0): - dependencies: - eslint: 8.56.0 - eslint-config-airbnb-base: 14.2.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0))(eslint@8.56.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0) - eslint-plugin-jsx-a11y: 6.8.0(eslint@8.56.0) - eslint-plugin-react: 7.33.2(eslint@8.56.0) - eslint-plugin-react-hooks: 4.6.2(eslint@8.56.0) - object.assign: 4.1.5 - object.entries: 1.1.8 - eslint-config-airbnb@18.2.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.56.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.56.0))(eslint-plugin-react@7.33.2(eslint@8.56.0))(eslint@8.56.0): dependencies: eslint: 8.56.0 @@ -96860,16 +96878,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@8.56.0): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 7.1.0(eslint@8.56.0)(typescript@5.5.3) - eslint: 8.56.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.56.0): dependencies: debug: 3.2.7 @@ -96988,33 +96996,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0): - dependencies: - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.56.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint@8.56.0) - hasown: 2.0.2 - is-core-module: 2.15.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.0 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 7.1.0(eslint@8.56.0)(typescript@5.5.3) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0): dependencies: array-includes: 3.1.8 @@ -97196,12 +97177,12 @@ snapshots: - supports-color - typescript - eslint-plugin-jest@27.6.3(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(jest@29.3.1(@types/node@20.12.10))(typescript@5.5.3): + eslint-plugin-jest@27.6.3(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0)(jest@29.3.1(@types/node@20.12.10))(typescript@5.5.4): dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.5.3) + '@typescript-eslint/utils': 5.62.0(eslint@8.56.0)(typescript@5.5.4) eslint: 8.56.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.3))(eslint@8.56.0)(typescript@5.5.3) + '@typescript-eslint/eslint-plugin': 7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.56.0)(typescript@5.5.4))(eslint@8.56.0)(typescript@5.5.4) jest: 29.3.1(@types/node@20.12.10) transitivePeerDependencies: - supports-color @@ -97336,7 +97317,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -97740,7 +97721,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -97991,7 +97972,7 @@ snapshots: follow-redirects@1.15.9(debug@4.3.4): optionalDependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) follow-redirects@1.15.9(debug@4.3.7): optionalDependencies: @@ -98912,7 +98893,7 @@ snapshots: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -98920,14 +98901,14 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -99006,21 +98987,21 @@ snapshots: https-proxy-agent@5.0.0: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -99133,7 +99114,7 @@ snapshots: inject-body-webpack-plugin@1.3.0(html-webpack-plugin@5.3.2(webpack@5.84.1(esbuild@0.14.29))): dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) html-webpack-plugin: 5.3.2(webpack@5.84.1(esbuild@0.14.29)) insert-string-after: 1.0.0 insert-string-before: 1.0.0 @@ -99552,7 +99533,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -101643,7 +101624,7 @@ snapshots: micromark@2.11.4: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) parse-entities: 2.0.0 transitivePeerDependencies: - supports-color @@ -101651,7 +101632,7 @@ snapshots: micromark@4.0.1: dependencies: '@types/debug': 4.1.12 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.2 @@ -101864,7 +101845,7 @@ snapshots: mocha-junit-reporter@2.2.1(mocha@9.2.2): dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) md5: 2.3.0 mkdirp: 3.0.1 mocha: 9.2.2 @@ -101875,7 +101856,7 @@ snapshots: mocha-multi-reporters@1.5.1(mocha@9.2.2): dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) lodash: 4.17.21 mocha: 9.2.2 transitivePeerDependencies: @@ -104003,7 +103984,7 @@ snapshots: puppeteer@13.7.0(bufferutil@4.0.3)(encoding@0.1.13)(utf-8-validate@5.0.5): dependencies: cross-fetch: 3.1.5(encoding@0.1.13) - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) devtools-protocol: 0.0.981744 extract-zip: 2.0.1 https-proxy-agent: 5.0.1 @@ -105691,7 +105672,7 @@ snapshots: socks-proxy-agent@5.0.0: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -105699,7 +105680,7 @@ snapshots: socks-proxy-agent@6.1.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -105707,7 +105688,7 @@ snapshots: socks-proxy-agent@8.0.4: dependencies: agent-base: 7.1.1 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -105809,7 +105790,7 @@ snapshots: spdy-transport@3.0.0: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -105820,7 +105801,7 @@ snapshots: spdy@4.0.2: dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -106168,7 +106149,7 @@ snapshots: stylus-lookup@3.0.2: dependencies: commander: 2.20.3 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -106793,7 +106774,7 @@ snapshots: '@types/node': 22.10.1 '@types/unist': 3.0.3 concat-stream: 2.0.0 - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) extend: 3.0.2 glob: 10.4.5 ignore: 6.0.2 @@ -107366,7 +107347,7 @@ snapshots: vue-eslint-parser@9.4.3(eslint@8.56.0): dependencies: - debug: 4.3.4 + debug: 4.3.4(supports-color@9.4.0) eslint: 8.56.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 diff --git a/scopes/component/apply/apply.main.runtime.ts b/scopes/component/apply/apply.main.runtime.ts index 4ea940fd74ec..1d7619a5bc44 100644 --- a/scopes/component/apply/apply.main.runtime.ts +++ b/scopes/component/apply/apply.main.runtime.ts @@ -150,6 +150,7 @@ export class ApplyMain { const shouldTag = Boolean(params.tag); const results = await tagModelComponent({ ...params, + components, consumerComponents, tagDataPerComp: snapDataPerComp.map((s) => ({ componentId: s.componentId, @@ -342,6 +343,7 @@ export class ApplyMain { const shouldTag = Boolean(params.tag); const results = await tagModelComponent({ ...params, + components, consumerComponents, tagDataPerComp: snapDataPerComp.map((s) => ({ componentId: s.componentId, diff --git a/scopes/component/component-writer/component-writer.main.runtime.ts b/scopes/component/component-writer/component-writer.main.runtime.ts index 7accaeea9f69..c714b54984aa 100644 --- a/scopes/component/component-writer/component-writer.main.runtime.ts +++ b/scopes/component/component-writer/component-writer.main.runtime.ts @@ -1,4 +1,5 @@ import { MainRuntime } from '@teambit/cli'; +import { ComponentID } from '@teambit/component-id'; import { CompilerAspect, CompilerMain } from '@teambit/compiler'; import { InstallAspect, InstallMain } from '@teambit/install'; import { Logger, LoggerAspect, LoggerMain } from '@teambit/logger'; @@ -79,7 +80,10 @@ export class ComponentWriterMain { ); } if (!opts.skipDependencyInstallation) { - installationError = await this.installPackagesGracefully(opts.skipWriteConfigFiles); + installationError = await this.installPackagesGracefully( + opts.components.map(({ id }) => id), + opts.skipWriteConfigFiles + ); // no point to compile if the installation is not running. the environment is not ready. compilationError = await this.compileGracefully(); } @@ -87,7 +91,10 @@ export class ComponentWriterMain { return { installationError, compilationError, workspaceConfigUpdateResult }; } - private async installPackagesGracefully(skipWriteConfigFiles = false): Promise { + private async installPackagesGracefully( + componentIds: ComponentID[], + skipWriteConfigFiles = false + ): Promise { this.logger.debug('installPackagesGracefully, start installing packages'); try { const installOpts = { @@ -95,6 +102,7 @@ export class ComponentWriterMain { updateExisting: false, import: false, writeConfigFiles: !skipWriteConfigFiles, + dependenciesGraph: await this.workspace.scope.getDependenciesGraphByComponentIds(componentIds), }; await this.installer.install(undefined, installOpts); this.logger.debug('installPackagesGracefully, completed installing packages successfully'); diff --git a/scopes/component/forking/forking.main.runtime.ts b/scopes/component/forking/forking.main.runtime.ts index 39a7fd2e3dd4..c90ca8b6c4ee 100644 --- a/scopes/component/forking/forking.main.runtime.ts +++ b/scopes/component/forking/forking.main.runtime.ts @@ -393,7 +393,7 @@ the reason is that the refactor changes the components using ${sourceId.toString GraphqlMain, RefactoringMain, PkgMain, - InstallMain + InstallMain, ]) { const forkingMain = new ForkingMain( workspace, diff --git a/scopes/component/isolator/capsule-list.ts b/scopes/component/isolator/capsule-list.ts index 7a259a5f3f4e..70b8af4d62cb 100644 --- a/scopes/component/isolator/capsule-list.ts +++ b/scopes/component/isolator/capsule-list.ts @@ -26,6 +26,9 @@ export default class CapsuleList extends Array { getAllComponents(): Component[] { return this.map((c) => c.component); } + getAllComponentIDs(): ComponentID[] { + return this.map((c) => c.component.id); + } getGraphIds(): Graph { const components = this.getAllComponents(); const graph = new Graph(); diff --git a/scopes/component/isolator/isolator.main.runtime.ts b/scopes/component/isolator/isolator.main.runtime.ts index 63cfedd7f873..e48ba7e1c952 100644 --- a/scopes/component/isolator/isolator.main.runtime.ts +++ b/scopes/component/isolator/isolator.main.runtime.ts @@ -50,6 +50,7 @@ import { pathNormalizeToLinux, PathOsBasedAbsolute } from '@teambit/legacy.utils import { concurrentComponentsLimit } from '@teambit/harmony.modules.concurrency'; import { componentIdToPackageName } from '@teambit/pkg.modules.component-package-name'; import { Scope } from '@teambit/legacy/dist/scope'; +import { type DependenciesGraph } from '@teambit/legacy/dist/scope/models/dependencies-graph'; import fs, { copyFile } from 'fs-extra'; import hash from 'object-hash'; import path, { basename } from 'path'; @@ -593,6 +594,7 @@ export class IsolatorMain { * @param opts * @param legacyScope */ + /* eslint-disable complexity */ private async createCapsules( components: Component[], capsulesDir: string, @@ -700,13 +702,22 @@ export class IsolatorMain { }) ); } else { + const dependenciesGraph = await legacyScope?.getDependenciesGraphByComponentIds( + capsuleList.getAllComponentIDs() + ); const linkedDependencies = await this.linkInCapsules(capsuleList, capsulesWithPackagesData); linkedDependencies[capsulesDir] = rootLinks; await this.installInCapsules(capsulesDir, capsuleList, installOptions, { cachePackagesOnCapsulesRoot, linkedDependencies, packageManager: opts.packageManager, + dependenciesGraph, }); + if (dependenciesGraph == null) { + // If the graph was not present in the model, we use the just created lockfile inside the capsules + // to populate the graph. + await this.addDependenciesGraphToComponents(capsuleList, components, capsulesDir); + } } if (installLongProcessLogger) { installLongProcessLogger.end('success'); @@ -737,6 +748,24 @@ export class IsolatorMain { return allCapsuleList; } + /* eslint-enable complexity */ + + private async addDependenciesGraphToComponents( + capsuleList: CapsuleList, + components: Component[], + capsulesDir: string + ): Promise { + const componentIdByPkgName = this.dependencyResolver.createComponentIdByPkgNameMap(components); + const opts = { + componentIdByPkgName, + rootDir: capsulesDir, + }; + await Promise.all( + capsuleList.map((capsule) => + this.dependencyResolver.addDependenciesGraph(capsule.component, path.relative(capsulesDir, capsule.path), opts) + ) + ); + } private async markCapsulesAsReady(capsuleList: CapsuleList): Promise { await Promise.all( @@ -778,6 +807,7 @@ export class IsolatorMain { linkedDependencies?: Record>; packageManager?: string; nodeLinker?: NodeLinker; + dependenciesGraph?: DependenciesGraph; } ) { const installer = this.dependencyResolver.getInstaller({ @@ -799,6 +829,7 @@ export class IsolatorMain { forceTeambitHarmonyLink: !this.dependencyResolver.hasHarmonyInRootPolicy(), excludeExtensionsDependencies: true, dedupeInjectedDeps: true, + dependenciesGraph: opts.dependenciesGraph, }; const packageManagerInstallOptions: PackageManagerInstallOptions = { diff --git a/scopes/component/merging/merging.main.runtime.ts b/scopes/component/merging/merging.main.runtime.ts index 4d3aa164de1e..2ddb6e04f234 100644 --- a/scopes/component/merging/merging.main.runtime.ts +++ b/scopes/component/merging/merging.main.runtime.ts @@ -269,9 +269,8 @@ export class MergingMain { let workspaceConfigConflictWriteError: Error | undefined; if (workspaceDepsConflicts) { - workspaceConfigConflictWriteError = await this.configMerger.writeWorkspaceJsoncWithConflictsGracefully( - workspaceDepsConflicts - ); + workspaceConfigConflictWriteError = + await this.configMerger.writeWorkspaceJsoncWithConflictsGracefully(workspaceDepsConflicts); } if (this.workspace) await this.configMerger.generateConfigMergeConflictFileForAll(allConfigMerge); @@ -721,7 +720,7 @@ export class MergingMain { RemoveMain, GlobalConfigMain, ConfigMergerMain, - DependencyResolverMain + DependencyResolverMain, ]) { const logger = loggerMain.createLogger(MergingAspect.id); const merging = new MergingMain( diff --git a/scopes/component/snapping/snapping.main.runtime.ts b/scopes/component/snapping/snapping.main.runtime.ts index e1dbbc668c33..0e7dbd7e87a9 100644 --- a/scopes/component/snapping/snapping.main.runtime.ts +++ b/scopes/component/snapping/snapping.main.runtime.ts @@ -64,6 +64,8 @@ import { LaneNotFound } from '@teambit/legacy.scope-api'; import { createLaneInScope } from '@teambit/lanes.modules.create-lane'; import { RemoveAspect, RemoveMain } from '@teambit/remove'; +export type PackageIntegritiesByPublishedPackages = Map; + export type TagDataPerComp = { componentId: ComponentID; dependencies: ComponentID[]; @@ -212,6 +214,7 @@ export class SnappingMain { const { taggedComponents, autoTaggedResults, publishedPackages, stagedConfig, removedComponents } = await tagModelComponent({ snapping: this, + components, consumerComponents, ids: compIds, message, @@ -336,6 +339,7 @@ if you're willing to lose the history from the head to the specified version, us }); const results = await tagModelComponent({ ...params, + components, consumerComponents, tagDataPerComp, populateArtifactsFrom: shouldUsePopulateArtifactsFrom ? components.map((c) => c.id) : undefined, @@ -500,6 +504,7 @@ if you're willing to lose the history from the head to the specified version, us const shouldTag = Boolean(params.tag); const results = await tagModelComponent({ ...params, + components, consumerComponents, tagDataPerComp: snapDataPerComp.map((s) => ({ componentId: s.componentId, @@ -588,6 +593,7 @@ if you're willing to lose the history from the head to the specified version, us const { taggedComponents, autoTaggedResults, stagedConfig, removedComponents } = await tagModelComponent({ snapping: this, editor, + components, consumerComponents, ids, ignoreNewestVersion: false, @@ -748,6 +754,31 @@ in case you're unsure about the pattern syntax, use "bit pattern [--help]"`); this.logger.profile('snap._addFlattenedDependenciesToComponents'); } + async _addDependenciesGraphToComponents(components: Component[]): Promise { + if (this.workspace == null) { + return; + } + this.logger.profile('snap._addDependenciesGraphToComponents'); + const componentIdByPkgName = this.dependencyResolver.createComponentIdByPkgNameMap(components); + const options = { + rootDir: this.workspace.path, + rootComponentsPath: this.workspace.rootComponentsPath, + componentIdByPkgName, + }; + await Promise.all( + components.map(async (component) => { + if (component.state._consumer.componentMap?.rootDir) { + await this.dependencyResolver.addDependenciesGraph( + component, + component.state._consumer.componentMap.rootDir, + options + ); + } + }) + ); + this.logger.profile('snap._addDependenciesGraphToComponents'); + } + async throwForDepsFromAnotherLane(components: ConsumerComponent[]) { const lane = await this.scope.legacyScope.getCurrentLaneObject(); const allIds = ComponentIdList.fromArray(components.map((c) => c.id)); @@ -912,13 +943,16 @@ another option, in case this dependency is not in main yet is to remove all refe }); } - _getPublishedPackages(components: ConsumerComponent[]): string[] { - const publishedPackages = components.map((comp) => { + _getPublishedPackages(components: ConsumerComponent[]): PackageIntegritiesByPublishedPackages { + const publishedPackages: PackageIntegritiesByPublishedPackages = new Map(); + for (const comp of components) { const builderExt = comp.extensions.findCoreExtension(Extensions.builder); const pkgData = builderExt?.data?.aspectsData?.find((a) => a.aspectId === Extensions.pkg); - return pkgData?.data?.publishedPackage; - }); - return compact(publishedPackages); + if (pkgData?.data?.publishedPackage != null) { + publishedPackages.set(pkgData.data.publishedPackage, pkgData.data.integrity); + } + } + return publishedPackages; } async _addCompToObjects({ @@ -985,13 +1019,15 @@ another option, in case this dependency is not in main yet is to remove all refe const component = await this.scope.legacyScope.sources.findOrAddComponent(source as any); const artifactFiles = getArtifactsFiles(source.extensions); const artifacts = this.transformArtifactsFromVinylToSource(artifactFiles); - const { version, files, flattenedEdges } = await this.scope.legacyScope.sources.consumerComponentToVersion(source); + const { version, files, flattenedEdges, dependenciesGraph } = + await this.scope.legacyScope.sources.consumerComponentToVersion(source); version.origin = { id: { scope: source.scope || (source.defaultScope as string), name: source.name }, lane: lane ? { scope: lane.scope, name: lane.name, hash: lane.hash().toString() } : undefined, }; objectRepo.add(version); if (flattenedEdges) this.objectsRepo.add(flattenedEdges); + if (dependenciesGraph) this.objectsRepo.add(dependenciesGraph); if (!source.version) throw new Error(`addSource expects source.version to be set`); component.addVersion(version, source.version, lane, source.previouslyUsedVersion, updateDependentsOnLane); objectRepo.add(component); @@ -1018,7 +1054,12 @@ another option, in case this dependency is not in main yet is to remove all refe version.extensions = consumerComponent.extensions; version.buildStatus = consumerComponent.buildStatus; const artifactObjects = artifacts.map((file) => file.source); - return [version, ...artifactObjects]; + const dependenciesGraph = Version.dependenciesGraphToSource(consumerComponent.dependenciesGraph); + version.dependenciesGraphRef = dependenciesGraph ? dependenciesGraph.hash() : undefined; + + const result = [version, ...artifactObjects]; + if (dependenciesGraph) result.push(dependenciesGraph); + return result; } private transformArtifactsFromVinylToSource(artifactsFiles: ArtifactFiles[]): ArtifactSource[] { diff --git a/scopes/component/snapping/tag-model-component.ts b/scopes/component/snapping/tag-model-component.ts index 90e3a9e6eefa..8193d643315c 100644 --- a/scopes/component/snapping/tag-model-component.ts +++ b/scopes/component/snapping/tag-model-component.ts @@ -19,6 +19,7 @@ import { getBasicLog } from '@teambit/harmony.modules.get-basic-log'; import { sha1 } from '@teambit/toolbox.crypto.sha1'; import { AutoTagResult, getAutoTagInfo } from '@teambit/legacy/dist/scope/component-ops/auto-tag'; import { OnTagOpts } from '@teambit/builder'; +import { DependenciesGraph } from '@teambit/legacy/dist/scope/models/dependencies-graph'; import { Log } from '@teambit/legacy/dist/scope/models/version'; import { MessagePerComponent, @@ -29,7 +30,7 @@ import { DependencyResolverMain } from '@teambit/dependency-resolver'; import { ScopeMain, StagedConfig } from '@teambit/scope'; import { Workspace } from '@teambit/workspace'; import { pMapPool } from '@teambit/toolbox.promise.map-pool'; -import { SnappingMain, TagDataPerComp } from './snapping.main.runtime'; +import { PackageIntegritiesByPublishedPackages, SnappingMain, TagDataPerComp } from './snapping.main.runtime'; export type onTagIdTransformer = (id: ComponentID) => ComponentID | null; @@ -175,6 +176,7 @@ function getVersionByEnteredId( export async function tagModelComponent({ snapping, consumerComponents, + components, ids, tagDataPerComp, populateArtifactsFrom, @@ -202,6 +204,7 @@ export async function tagModelComponent({ updateDependentsOnLane = false, // on lane, adds it into updateDependents prop }: { snapping: SnappingMain; + components: Component[]; consumerComponents: ConsumerComponent[]; ids: ComponentIdList; tagDataPerComp?: TagDataPerComp[]; @@ -290,6 +293,7 @@ export async function tagModelComponent({ logger.debugAndAddBreadCrumb('tag-model-components', 'sequentially persist all components'); setCurrentSchema(allComponentsToTag); + // go through all components and find the future versions for them isSnap ? setHashes(allComponentsToTag) @@ -320,6 +324,7 @@ export async function tagModelComponent({ consumer.updateNextVersionOnBitmap(allComponentsToTag, preReleaseId); } else { await snapping._addFlattenedDependenciesToComponents(allComponentsToTag, rebuildDepsGraph); + await snapping._addDependenciesGraphToComponents(components); await snapping.throwForDepsFromAnotherLane(allComponentsToTag); if (!build) emptyBuilderData(allComponentsToTag); addBuildStatus(allComponentsToTag, BuildStatus.Pending); @@ -366,7 +371,10 @@ export async function tagModelComponent({ const buildResult = scope.builderDataMapToLegacyOnTagResults(builderDataMap); snapping._updateComponentsByTagResult(componentsToBuild, buildResult); - publishedPackages.push(...snapping._getPublishedPackages(componentsToBuild)); + const packageIntegritiesByPublishedPackages = snapping._getPublishedPackages(componentsToBuild); + publishedPackages.push(...Array.from(packageIntegritiesByPublishedPackages.keys())); + + addIntegritiesToConsumerComponentsGraphs(packageIntegritiesByPublishedPackages, allComponentsToTag); addBuildStatus(componentsToBuild, BuildStatus.Succeed); await mapSeries(componentsToBuild, (consumerComponent) => snapping._enrichComp(consumerComponent)); if (populateArtifactsFrom) await updateHiddenProp(scope, populateArtifactsFrom); @@ -403,6 +411,49 @@ export async function tagModelComponent({ }; } +function addIntegritiesToConsumerComponentsGraphs( + packageIntegritiesByPublishedPackages: PackageIntegritiesByPublishedPackages, + consumerComponents: ConsumerComponent[] +) { + const _addIntegritiesToDependenciesGraph = addIntegritiesToDependenciesGraph.bind( + null, + packageIntegritiesByPublishedPackages + ); + for (const consumerComponent of consumerComponents) { + if (consumerComponent.dependenciesGraph) { + consumerComponent.dependenciesGraph = _addIntegritiesToDependenciesGraph(consumerComponent.dependenciesGraph); + } + } +} + +/** + * Updates the dependencies graph by replacing all "pending" version numbers of component dependencies + * with the actual version numbers of the recently published packages. It also attaches the integrity + * checksums of these components to ensure data integrity for each resolved dependency. + * + * @param packageIntegritiesByPublishedPackages - A map of package names and versions to their integrity checksums. + * @param dependenciesGraph - The current dependencies graph, containing nodes with potentially "pending" versions. + * @returns A new DependenciesGraph with updated versions and integrity checksums for all previously pending dependencies. + */ +function addIntegritiesToDependenciesGraph( + packageIntegritiesByPublishedPackages: PackageIntegritiesByPublishedPackages, + dependenciesGraph: DependenciesGraph +): DependenciesGraph { + const resolvedVersions: Array<{ name: string; version: string }> = []; + for (const [selector, integrity] of packageIntegritiesByPublishedPackages.entries()) { + if (integrity == null) continue; + const index = selector.indexOf('@', 1); + const name = selector.substring(0, index); + const version = selector.substring(index + 1); + const pendingPkg = dependenciesGraph.packages.get(`${name}@pending:`); + if (pendingPkg) { + pendingPkg.resolution = { integrity }; + resolvedVersions.push({ name, version }); + } + } + return replacePendingVersions(dependenciesGraph, resolvedVersions) as DependenciesGraph; +} + async function removeDeletedComponentsFromBitmap( comps: ConsumerComponent[], workspace?: Workspace @@ -614,6 +665,22 @@ export async function updateComponentsVersions( return stagedConfig; } +function replacePendingVersions( + graph: DependenciesGraph, + resolvedVersions: Array<{ name: string; version: string }> +): DependenciesGraph { + let s = graph.serialize(); + for (const { name, version } of resolvedVersions) { + s = s.replaceAll(`${name}@pending:`, `${name}@${version}`); + } + const updatedDependenciesGraph = DependenciesGraph.deserialize(s); + // This should never happen as we know at this point that the schema version is supported + if (updatedDependenciesGraph == null) { + throw new BitError('Failed to deserialize dependencies graph in replacePendingVersions()'); + } + return updatedDependenciesGraph; +} + /** * relevant for "_tag" (tag-from-scope) command. * the new tag uses the same files/config/build-artifacts as the previous snap. diff --git a/scopes/component/stash/stash-data.ts b/scopes/component/stash/stash-data.ts index bd65bec726f0..b8835ff8020e 100644 --- a/scopes/component/stash/stash-data.ts +++ b/scopes/component/stash/stash-data.ts @@ -10,7 +10,10 @@ export type StashDataObj = { }; export class StashData { - constructor(readonly metadata: StashMetadata, readonly stashCompsData: StashCompData[]) {} + constructor( + readonly metadata: StashMetadata, + readonly stashCompsData: StashCompData[] + ) {} toObject(): StashDataObj { return { diff --git a/scopes/component/stash/stash.main.runtime.ts b/scopes/component/stash/stash.main.runtime.ts index 576b3721ded3..62a1ae853b00 100644 --- a/scopes/component/stash/stash.main.runtime.ts +++ b/scopes/component/stash/stash.main.runtime.ts @@ -138,9 +138,8 @@ export class StashMain { if (!consumerComponent.log) { consumerComponent.log = await getBasicLog(); } - const { version, files } = await this.workspace.scope.legacyScope.sources.consumerComponentToVersion( - consumerComponent - ); + const { version, files } = + await this.workspace.scope.legacyScope.sources.consumerComponentToVersion(consumerComponent); if (previousVersion) { // set the parent, we need it for the "stash-load" to function as the "base" version for the three-way-merge. const modelComponent = consumerComponent.modelComponent; @@ -163,7 +162,7 @@ export class StashMain { Workspace, CheckoutMain, SnappingMain, - RemoveMain + RemoveMain, ]) { const stashMain = new StashMain(workspace, checkout, snapping, remove); const stashCmd = new StashCmd(stashMain); diff --git a/scopes/dependencies/dependencies/dependencies.main.runtime.ts b/scopes/dependencies/dependencies/dependencies.main.runtime.ts index e693bfdd76aa..eeb789bfc055 100644 --- a/scopes/dependencies/dependencies/dependencies.main.runtime.ts +++ b/scopes/dependencies/dependencies/dependencies.main.runtime.ts @@ -414,7 +414,7 @@ export class DependenciesMain { AspectLoaderMain, ScopeMain, GraphMain, - LoggerMain + LoggerMain, ]) { const logger = loggerMain.createLogger(DependenciesAspect.id); const depsMain = new DependenciesMain(workspace, scope, depsResolver, devFiles, aspectLoader, graph, logger); diff --git a/scopes/dependencies/dependency-resolver/dependency-installer.ts b/scopes/dependencies/dependency-resolver/dependency-installer.ts index 85cb0f98d705..8974e49f88cc 100644 --- a/scopes/dependencies/dependency-resolver/dependency-installer.ts +++ b/scopes/dependencies/dependency-resolver/dependency-installer.ts @@ -3,6 +3,7 @@ import path from 'path'; import fs from 'fs-extra'; import { MainAspect, AspectLoaderMain } from '@teambit/aspect-loader'; import { ComponentMap } from '@teambit/component'; +import { type DependenciesGraph } from '@teambit/legacy/dist/scope/models/dependencies-graph'; import { Logger } from '@teambit/logger'; import { PathAbsolute } from '@teambit/toolbox.path.path'; import { PeerDependencyRules, ProjectManifest } from '@pnpm/types'; @@ -44,6 +45,7 @@ export type InstallOptions = { forceTeambitHarmonyLink?: boolean; excludeExtensionsDependencies?: boolean; dedupeInjectedDeps?: boolean; + dependenciesGraph?: DependenciesGraph; }; export type GetComponentManifestsOptions = { @@ -207,6 +209,7 @@ export class DependencyInstaller { neverBuiltDependencies: ['core-js', ...(this.neverBuiltDependencies ?? [])], preferOffline: this.preferOffline, dedupeInjectedDeps: options.dedupeInjectedDeps, + dependenciesGraph: options.dependenciesGraph, ...packageManagerOptions, }; if (options.installTeambitBit) { diff --git a/scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts b/scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts index ae351a04fe1b..ac51856fd79b 100644 --- a/scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts +++ b/scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts @@ -1,5 +1,6 @@ import multimatch from 'multimatch'; import mapSeries from 'p-map-series'; +import { DEPS_GRAPH, isFeatureEnabled } from '@teambit/harmony.modules.feature-toggle'; import { MainRuntime } from '@teambit/cli'; import { getAllCoreAspectsIds } from '@teambit/bit'; import { getRootComponentDir } from '@teambit/workspace.root-components'; @@ -494,6 +495,14 @@ export class DependencyResolverMain { return this.getDepResolverData(component)?.packageName ?? this.calcPackageName(component); } + createComponentIdByPkgNameMap(components: Component[]): Map { + const componentIdByPkgName = new Map(); + for (const component of components) { + componentIdByPkgName.set(this.getPackageName(component), component.id); + } + return componentIdByPkgName; + } + getDepResolverData(component: Component): DependencyResolverComponentData | undefined { return component.state.aspects.get(DependencyResolverAspect.id)?.data as DependencyResolverComponentData; } @@ -532,12 +541,23 @@ export class DependencyResolverMain { // in that case we return the dir from the root node_modules return this.getModulePath(component); } - const envId = this.envs.getEnvId(component); - const dirInEnvRoot = join(getRelativeRootComponentDir(envId), 'node_modules', pkgName); + const dirInEnvRoot = join(this.getComponentDirInBitRoots(component, options), 'node_modules', pkgName); if (fs.pathExistsSync(dirInEnvRoot)) return dirInEnvRoot; return this.getModulePath(component); } + getComponentDirInBitRoots( + component: Component, + options: { + workspacePath: string; + rootComponentsPath: string; + } + ) { + const envId = this.envs.getEnvId(component); + const rootComponentsRelativePath = relative(options.workspacePath, options.rootComponentsPath); + return getRootComponentDir(rootComponentsRelativePath ?? '', envId); + } + /** * returns the package path in the /node_modules/ folder * In case you call this in order to run the code from the path, please refer to the `getRuntimeModulePath` API @@ -548,6 +568,36 @@ export class DependencyResolverMain { return relativePath; } + async addDependenciesGraph( + component: Component, + componentRelativeDir: string, + options: { + rootDir: string; + rootComponentsPath?: string; + componentIdByPkgName: Map; + } + ): Promise { + try { + component.state._consumer.dependenciesGraph = await this.getPackageManager()?.calcDependenciesGraph?.({ + rootDir: options.rootDir, + componentRootDir: options.rootComponentsPath + ? this.getComponentDirInBitRoots(component, { + workspacePath: options.rootDir, + rootComponentsPath: options.rootComponentsPath, + }) + : undefined, + pkgName: this.getPackageName(component), + componentRelativeDir, + componentIdByPkgName: options.componentIdByPkgName, + }); + } catch (err) { + // If the dependencies graph feature is disabled, we ignore the error + if (isFeatureEnabled(DEPS_GRAPH)) { + throw err; + } + } + } + /** * get a component dependency installer. */ diff --git a/scopes/dependencies/dependency-resolver/index.ts b/scopes/dependencies/dependency-resolver/index.ts index 658b3be8cc55..08d0337d9402 100644 --- a/scopes/dependencies/dependency-resolver/index.ts +++ b/scopes/dependencies/dependency-resolver/index.ts @@ -12,6 +12,8 @@ export type { PackageManagerInstallOptions, PackageManagerResolveRemoteVersionOptions, ResolvedPackageVersion, + CalcDepsGraphOptions, + ComponentIdByPkgName, } from './package-manager'; export type { DependencyResolverWorkspaceConfig, NodeLinker } from './dependency-resolver-workspace-config'; export type { diff --git a/scopes/dependencies/dependency-resolver/package-manager.ts b/scopes/dependencies/dependency-resolver/package-manager.ts index 471f4b2b09d6..b84aecee52dd 100644 --- a/scopes/dependencies/dependency-resolver/package-manager.ts +++ b/scopes/dependencies/dependency-resolver/package-manager.ts @@ -1,6 +1,7 @@ import { PeerDependencyIssuesByProjects } from '@pnpm/core'; import { PeerDependencyRules, ProjectManifest } from '@pnpm/types'; -import { ComponentMap } from '@teambit/component'; +import { ComponentID, ComponentMap } from '@teambit/component'; +import { type DependenciesGraph } from '@teambit/legacy/dist/scope/models/dependencies-graph'; import { Registries } from './registry'; import { DepsFilterFn } from './manifest'; import { NetworkConfig, ProxyConfig } from './dependency-resolver.main.runtime'; @@ -131,6 +132,8 @@ export type PackageManagerInstallOptions = { * This is used by Ripple CI. */ returnListOfDepsRequiringBuild?: boolean; + + dependenciesGraph?: DependenciesGraph; }; export type PackageManagerGetPeerDependencyIssuesOptions = PackageManagerInstallOptions; @@ -206,4 +209,16 @@ export interface PackageManager { getWorkspaceDepsOfBitRoots(manifests: ProjectManifest[]): Record; findUsages?(depName: string, opts: { lockfileDir: string; depth?: number }): Promise; + + calcDependenciesGraph?(options: CalcDepsGraphOptions): Promise; +} + +export interface CalcDepsGraphOptions { + componentRelativeDir: string; + componentIdByPkgName: ComponentIdByPkgName; + rootDir: string; + componentRootDir?: string; + pkgName?: string; } + +export type ComponentIdByPkgName = Map; diff --git a/scopes/dependencies/pnpm/lockfile-deps-graph-converter.spec.ts b/scopes/dependencies/pnpm/lockfile-deps-graph-converter.spec.ts new file mode 100644 index 000000000000..ae49546b3e31 --- /dev/null +++ b/scopes/dependencies/pnpm/lockfile-deps-graph-converter.spec.ts @@ -0,0 +1,205 @@ +import path from 'path'; +import { DependenciesGraph } from '@teambit/legacy/dist/scope/models/dependencies-graph'; +import { type LockfileFileV9 } from '@pnpm/lockfile.types'; +import { convertLockfileToGraph, convertGraphToLockfile } from './lockfile-deps-graph-converter'; +import { expect } from 'chai'; + +describe('convertLockfileToGraph simple case', () => { + const lockfile: LockfileFileV9 = { + importers: { + '.': {}, + 'node_modules/.bit_roots/env': { + dependencies: { + comp1: { + version: 'file:comps/comp1', + specifier: '*', + }, + }, + }, + 'comps/comp1': { + dependencies: { + foo: { + version: '1.0.0(patch_hash=0000)', + specifier: '^1.0.0', + }, + }, + }, + }, + lockfileVersion: '9.0', + snapshots: { + 'foo@1.0.0(patch_hash=0000)': { + dependencies: { + bar: '1.0.0', + }, + }, + 'bar@1.0.0': {}, + 'comp1@file:comps/comp1': { + dependencies: { + foo: '1.0.0(patch_hash=0000)', + }, + }, + }, + packages: { + 'comp1@file:comps/comp1': { + resolution: { + directory: 'comps/comp1', + type: 'directory', + }, + }, + 'foo@1.0.0': { + engines: { + node: '>=8', + npm: '>=6', + }, + hasBin: true, + os: ['darwin'], + cpu: ['arm64'], + resolution: { + integrity: 'sha512-000', + }, + }, + 'bar@1.0.0': { + resolution: { + integrity: 'sha512-111', + }, + }, + }, + }; + const graph = convertLockfileToGraph(lockfile, { + pkgName: 'comp1', + componentRelativeDir: 'comps/comp1', + componentRootDir: 'node_modules/.bit_roots/env', + componentIdByPkgName: new Map(), + }); + const expected = { + schemaVersion: '1.0', + edges: [ + { + id: 'foo@1.0.0(patch_hash=0000)', + neighbours: [{ id: 'bar@1.0.0', optional: false }], + attr: { + pkgId: 'foo@1.0.0', + }, + }, + { + id: 'comp1@pending:', + neighbours: [ + { + id: 'foo@1.0.0(patch_hash=0000)', + optional: false, + }, + ], + }, + { + id: '.', + neighbours: [ + { + id: 'foo@1.0.0(patch_hash=0000)', + name: 'foo', + specifier: '^1.0.0', + lifecycle: 'runtime', + optional: false, + }, + ], + }, + ], + packages: { + 'foo@1.0.0': { + engines: { + node: '>=8', + npm: '>=6', + }, + hasBin: true, + os: ['darwin'], + cpu: ['arm64'], + resolution: { + integrity: 'sha512-000', + }, + }, + 'bar@1.0.0': { + resolution: { + integrity: 'sha512-111', + }, + }, + 'comp1@pending:': { + resolution: { + directory: 'comps/comp1', + type: 'directory', + }, + }, + }, + }; + it('should convert the lockfile object to the graph object', () => { + expect({ + ...graph, + packages: Object.fromEntries(graph.packages.entries()), + }).to.eql(expected); + }); + it('should convert the graph object to the lockfile object', () => { + expect( + convertGraphToLockfile( + new DependenciesGraph(graph), + { + [path.resolve('comps/comp1')]: { + dependencies: { + foo: '^1.0.0', + }, + }, + }, + process.cwd() + ) + ).to.eql({ + importers: { + 'comps/comp1': { + dependencies: { + foo: { + version: '1.0.0(patch_hash=0000)', + specifier: '^1.0.0', + }, + }, + devDependencies: {}, + optionalDependencies: {}, + }, + }, + lockfileVersion: '9.0', + snapshots: { + 'foo@1.0.0(patch_hash=0000)': { + dependencies: { + bar: '1.0.0', + }, + }, + 'bar@1.0.0': {}, + 'comp1@pending:': { + dependencies: { + foo: '1.0.0(patch_hash=0000)', + }, + }, + }, + packages: { + 'comp1@pending:': { + resolution: { + directory: 'comps/comp1', + type: 'directory', + }, + }, + 'foo@1.0.0': { + engines: { + node: '>=8', + npm: '>=6', + }, + hasBin: true, + os: ['darwin'], + cpu: ['arm64'], + resolution: { + integrity: 'sha512-000', + }, + }, + 'bar@1.0.0': { + resolution: { + integrity: 'sha512-111', + }, + }, + }, + }); + }); +}); diff --git a/scopes/dependencies/pnpm/lockfile-deps-graph-converter.ts b/scopes/dependencies/pnpm/lockfile-deps-graph-converter.ts new file mode 100644 index 000000000000..6ef1ac0dbdc3 --- /dev/null +++ b/scopes/dependencies/pnpm/lockfile-deps-graph-converter.ts @@ -0,0 +1,273 @@ +import { type ProjectManifest } from '@pnpm/types'; +import { type LockfileFileV9, type InlineSpecifiersResolvedDependencies } from '@pnpm/lockfile.types'; +import * as dp from '@pnpm/dependency-path'; +import { pick, partition } from 'lodash'; +import { + DependenciesGraph, + type PackagesMap, + type PackageAttributes, + type DependencyEdge, + type DependencyNeighbour, +} from '@teambit/legacy/dist/scope/models/dependencies-graph'; +import { type CalcDepsGraphOptions, type ComponentIdByPkgName } from '@teambit/dependency-resolver'; +import { getLockfileImporterId } from '@pnpm/lockfile.fs'; + +function convertLockfileToGraphFromCapsule( + lockfile: LockfileFileV9, + { + componentRelativeDir, + componentIdByPkgName, + }: Pick +): DependenciesGraph { + const componentImporter = lockfile.importers![componentRelativeDir]; + const directDependencies: DependencyNeighbour[] = []; + for (const depType of ['dependencies' as const, 'optionalDependencies' as const, 'devDependencies' as const]) { + if (componentImporter[depType] != null) { + const lifecycle = depType === 'devDependencies' ? 'dev' : 'runtime'; + const optional = depType === 'optionalDependencies'; + directDependencies.push(...importerDepsToNeighbours(componentImporter[depType]!, lifecycle, optional)); + } + } + return _convertLockfileToGraph(lockfile, { componentIdByPkgName, directDependencies }); +} + +function importerDepsToNeighbours( + importerDependencies: InlineSpecifiersResolvedDependencies, + lifecycle: 'dev' | 'runtime', + optional: boolean +): DependencyNeighbour[] { + const neighbours: DependencyNeighbour[] = []; + for (const [name, { version, specifier }] of Object.entries(importerDependencies) as any) { + const id = dp.refToRelative(version, name)!; + neighbours.push({ name, specifier, id, lifecycle, optional }); + } + return neighbours; +} + +export function convertLockfileToGraph( + lockfile: LockfileFileV9, + { pkgName, componentRootDir, componentRelativeDir, componentIdByPkgName }: Omit +): DependenciesGraph { + if (componentRootDir == null || pkgName == null) { + return convertLockfileToGraphFromCapsule(lockfile, { componentRelativeDir, componentIdByPkgName }); + } + const componentDevImporter = lockfile.importers![componentRelativeDir]; + const directDependencies: DependencyNeighbour[] = []; + if (componentDevImporter.devDependencies != null) { + directDependencies.push(...importerDepsToNeighbours(componentDevImporter.devDependencies, 'dev', false)); + } + const lockedPkg = + lockfile.snapshots![`${pkgName}@${lockfile.importers![componentRootDir].dependencies![pkgName].version}`]; + for (const depType of ['dependencies' as const, 'optionalDependencies' as const]) { + const optional = depType === 'optionalDependencies'; + for (const [name, version] of Object.entries(lockedPkg[depType] ?? {})) { + const id = dp.refToRelative(version, name)!; + directDependencies.push({ + name, + specifier: componentDevImporter[depType]?.[name]?.specifier ?? '*', + id, + lifecycle: 'runtime', + optional, + }); + } + } + return _convertLockfileToGraph(lockfile, { componentIdByPkgName, directDependencies }); +} + +function _convertLockfileToGraph( + lockfile: LockfileFileV9, + { + componentIdByPkgName, + directDependencies, + }: { + componentIdByPkgName: ComponentIdByPkgName; + directDependencies: DependencyNeighbour[]; + } +): DependenciesGraph { + lockfile = replaceFileVersionsWithPendingVersions(lockfile); + return new DependenciesGraph({ + edges: buildEdges(lockfile, { directDependencies }), + packages: buildPackages(lockfile, { componentIdByPkgName }), + }); +} + +function buildEdges( + lockfile: LockfileFileV9, + { directDependencies }: { directDependencies: DependencyNeighbour[] } +): DependencyEdge[] { + const edges: DependencyEdge[] = []; + for (const [depPath, snapshot] of Object.entries(lockfile.snapshots ?? {})) { + const neighbours = extractDependenciesFromSnapshot(snapshot); + const edge: DependencyEdge = { + id: depPath, + neighbours, + }; + const pkgId = dp.removeSuffix(depPath); + if (pkgId !== depPath) { + edge.attr = { pkgId }; + } + if (snapshot.transitivePeerDependencies) { + edge.attr = { + ...edge.attr, + transitivePeerDependencies: snapshot.transitivePeerDependencies, + }; + } + if (edge.neighbours.length > 0 || edge.id !== pkgId) { + edges.push(edge); + } + } + edges.push({ + id: DependenciesGraph.ROOT_EDGE_ID, + neighbours: replaceFileVersionsWithPendingVersions(directDependencies), + }); + return edges; +} + +function extractDependenciesFromSnapshot(snapshot: any): DependencyNeighbour[] { + const dependencies: DependencyNeighbour[] = []; + + for (const { depTypeField, optional } of [ + { depTypeField: 'dependencies', optional: false }, + { depTypeField: 'optionalDependencies', optional: true }, + ]) { + for (const [name, ref] of Object.entries((snapshot[depTypeField] ?? {}) as Record)) { + const subDepPath = dp.refToRelative(ref, name); + if (subDepPath != null) { + dependencies.push({ id: subDepPath, optional }); + } + } + } + + return dependencies; +} + +function buildPackages( + lockfile: LockfileFileV9, + { componentIdByPkgName }: { componentIdByPkgName: ComponentIdByPkgName } +): PackagesMap { + const packages: PackagesMap = new Map(); + for (const [pkgId, pkg] of Object.entries(lockfile.packages ?? {})) { + const graphPkg = pick(pkg, [ + 'bundledDependencies', + 'cpu', + 'deprecated', + 'engines', + 'hasBin', + 'libc', + 'name', + 'os', + 'peerDependencies', + 'peerDependenciesMeta', + 'resolution', + 'version', + ]) as any; + if (pkgId.includes('@pending:')) { + const parsed = dp.parse(pkgId); + if (parsed.name && componentIdByPkgName.has(parsed.name)) { + const compId = componentIdByPkgName.get(parsed.name)!; + graphPkg.component = { + name: compId.fullName, + scope: compId.scope, + }; + } + } + packages.set(pkgId, graphPkg); + } + return packages; +} + +function replaceFileVersionsWithPendingVersions(obj: T): T { + return JSON.parse(JSON.stringify(obj).replaceAll(/file:[^'"(]+/g, 'pending:')); +} + +export function convertGraphToLockfile( + graph: DependenciesGraph, + manifests: Record, + rootDir: string +): LockfileFileV9 { + const packages = {}; + const snapshots = {}; + const allEdgeIds = new Set(graph.edges.map(({ id }) => id)); + + for (const edge of graph.edges) { + if (edge.id === DependenciesGraph.ROOT_EDGE_ID) continue; + const pkgId = edge.attr?.pkgId ?? edge.id; + snapshots[edge.id] = {}; + packages[pkgId] = {}; + const [optionalDeps, prodDeps] = partition(edge.neighbours, (dep) => dep.optional); + if (prodDeps.length) { + snapshots[edge.id].dependencies = convertToDeps(prodDeps); + } + if (optionalDeps.length) { + snapshots[edge.id].optionalDependencies = convertToDeps(optionalDeps); + } + const graphPkg = graph.packages.get(pkgId); + if (graphPkg != null) { + Object.assign(packages[pkgId], convertGraphPackageToLockfilePackage(graphPkg)); + } + } + const lockfile = { + lockfileVersion: '9.0', + packages, + snapshots, + importers: {}, + }; + for (const [projectDir, manifest] of Object.entries(manifests)) { + const projectId = getLockfileImporterId(rootDir, projectDir); + lockfile.importers![projectId] = { + dependencies: {}, + devDependencies: {}, + optionalDependencies: {}, + }; + const rootEdge = graph.findRootEdge(); + if (rootEdge) { + for (const depType of ['dependencies', 'devDependencies', 'optionalDependencies']) { + for (const [name, specifier] of Object.entries(manifest[depType] ?? {})) { + const edgeId = rootEdge.neighbours.find( + (directDep) => directDep.name === name && directDep.specifier === specifier + )?.id; + if (edgeId) { + const parsed = dp.parse(edgeId); + const ref = depPathToRef(parsed); + lockfile.importers![projectId][depType][name] = { version: ref, specifier }; + } + } + } + } + } + return lockfile; + + function convertToDeps(neighbours: DependencyNeighbour[]) { + const deps = {}; + for (const { id } of neighbours) { + const parsed = dp.parse(id); + deps[parsed.name!] = depPathToRef(parsed); + if (!allEdgeIds.has(id)) { + snapshots[id] = {}; + packages[id] = convertGraphPackageToLockfilePackage(graph.packages.get(id)!); + } + } + return deps; + } +} + +function depPathToRef(depPath: dp.DependencyPath): string { + return `${depPath.version}${depPath.patchHash ?? ''}${depPath.peersSuffix ?? ''}`; +} + +function convertGraphPackageToLockfilePackage(pkgAttr: PackageAttributes) { + return pick(pkgAttr, [ + 'bundledDependencies', + 'cpu', + 'deprecated', + 'engines', + 'hasBin', + 'libc', + 'name', + 'os', + 'peerDependencies', + 'peerDependenciesMeta', + 'resolution', + 'version', + ]); +} diff --git a/scopes/dependencies/pnpm/pnpm.package-manager.ts b/scopes/dependencies/pnpm/pnpm.package-manager.ts index bf073b6521ef..a5b6dae8a4bc 100644 --- a/scopes/dependencies/pnpm/pnpm.package-manager.ts +++ b/scopes/dependencies/pnpm/pnpm.package-manager.ts @@ -12,13 +12,18 @@ import { BIT_CLOUD_REGISTRY, PackageManagerProxyConfig, PackageManagerNetworkConfig, + type CalcDepsGraphOptions, } from '@teambit/dependency-resolver'; import { VIRTUAL_STORE_DIR_MAX_LENGTH } from '@teambit/dependencies.pnpm.dep-path'; +import { DEPS_GRAPH, isFeatureEnabled } from '@teambit/harmony.modules.feature-toggle'; import { Logger } from '@teambit/logger'; +import { type LockfileFileV9 } from '@pnpm/lockfile.types'; import fs from 'fs'; import { memoize, omit } from 'lodash'; import { PeerDependencyIssuesByProjects } from '@pnpm/core'; +import { filterLockfileByImporters } from '@pnpm/lockfile.filtering'; import { Config } from '@pnpm/config'; +import { type ProjectId, type ProjectManifest, type DepPath } from '@pnpm/types'; import { readModulesManifest, Modules } from '@pnpm/modules-yaml'; import { buildDependenciesHierarchy, @@ -27,14 +32,16 @@ import { PackageNode, } from '@pnpm/reviewing.dependencies-hierarchy'; import { renderTree } from '@pnpm/list'; +import { writeLockfileFile, convertToLockfileFile as convertLockfileObjectToLockfileFile } from '@pnpm/lockfile.fs'; import { readWantedLockfile } from '@pnpm/lockfile-file'; -import { type ProjectManifest, type DepPath } from '@pnpm/types'; import { BIT_ROOTS_DIR } from '@teambit/legacy/dist/constants'; import { ServerSendOutStream } from '@teambit/legacy/dist/logger/pino-logger'; import { join } from 'path'; +import { convertLockfileToGraph, convertGraphToLockfile } from './lockfile-deps-graph-converter'; import { readConfig } from './read-config'; import { pnpmPruneModules } from './pnpm-prune-modules'; import type { RebuildFn } from './lynx'; +import { type DependenciesGraph } from '@teambit/legacy/dist/scope/models/dependencies-graph'; export type { RebuildFn }; @@ -70,6 +77,20 @@ export class PnpmPackageManager implements PackageManager { private cloud: CloudMain ) {} + async dependenciesGraphToLockfile( + dependenciesGraph: DependenciesGraph, + manifests: Record, + rootDir: string + ) { + const lockfile: LockfileFileV9 = convertGraphToLockfile(dependenciesGraph, manifests, rootDir); + Object.assign(lockfile, { + bit: { + restoredFromModel: true, + }, + }); + await writeLockfileFile(join(rootDir, 'pnpm-lock.yaml'), lockfile); + } + async install( { rootDir, manifests }: InstallationContext, installOptions: PackageManagerInstallOptions = {} @@ -78,6 +99,10 @@ export class PnpmPackageManager implements PackageManager { // eslint-disable-next-line global-require, import/no-dynamic-require const { install } = require('./lynx'); + if (installOptions.dependenciesGraph && isFeatureEnabled(DEPS_GRAPH)) { + await this.dependenciesGraphToLockfile(installOptions.dependenciesGraph, manifests, rootDir); + } + this.logger.debug(`running installation in root dir ${rootDir}`); this.logger.debug('components manifests for installation', manifests); if (!installOptions.hidePackageManagerOutput) { @@ -124,7 +149,7 @@ export class PnpmPackageManager implements PackageManager { includeOptionalDeps: installOptions.includeOptionalDeps, ignorePackageManifest: installOptions.ignorePackageManifest, dedupeInjectedDeps: installOptions.dedupeInjectedDeps ?? false, - dryRun: installOptions.dryRun, + dryRun: installOptions.dependenciesGraph == null && installOptions.dryRun, overrides: installOptions.overrides, hoistPattern: installOptions.hoistPatterns ?? config.hoistPattern, publicHoistPattern: config.shamefullyHoist @@ -352,6 +377,38 @@ export class PnpmPackageManager implements PackageManager { showExtraneous: false, }); } + + /** + * Calculating the dependencies graph of a given component using the lockfile. + */ + async calcDependenciesGraph(opts: CalcDepsGraphOptions): Promise { + const lockfile = await readWantedLockfile(opts.rootDir, { ignoreIncompatible: false }); + if (!lockfile) { + return undefined; + } + if (opts.componentRootDir && !lockfile.importers[opts.componentRootDir] && opts.componentRootDir.includes('@')) { + opts.componentRootDir = opts.componentRootDir.split('@')[0]; + } + const filterByImporterIds = [opts.componentRelativeDir as ProjectId]; + if (opts.componentRootDir != null) { + filterByImporterIds.push(opts.componentRootDir as ProjectId); + } + // Filters the lockfile so that it only includes packages related to the given component. + const partialLockfile = convertLockfileObjectToLockfileFile( + filterLockfileByImporters(lockfile, filterByImporterIds, { + include: { + dependencies: true, + devDependencies: true, + optionalDependencies: true, + }, + failOnMissingDependencies: false, + skipped: new Set(), + }), + { forceSharedFormat: true } + ); + const graph = convertLockfileToGraph(partialLockfile, opts); + return graph; + } } type GetPkgLocation = (pkgNode: PackageNode) => string; diff --git a/scopes/harmony/aspect-loader/aspect-loader.main.runtime.ts b/scopes/harmony/aspect-loader/aspect-loader.main.runtime.ts index 300bd0b5f997..40a909f581f7 100644 --- a/scopes/harmony/aspect-loader/aspect-loader.main.runtime.ts +++ b/scopes/harmony/aspect-loader/aspect-loader.main.runtime.ts @@ -884,7 +884,7 @@ export class AspectLoaderMain { [onAspectLoadErrorSlot, onLoadRequireableExtensionSlot, pluginSlot]: [ OnAspectLoadErrorSlot, OnLoadRequireableExtensionSlot, - PluginDefinitionSlot + PluginDefinitionSlot, ], harmony: Harmony ) { diff --git a/scopes/harmony/modules/feature-toggle/feature-toggle.ts b/scopes/harmony/modules/feature-toggle/feature-toggle.ts index 894a094f6983..e528668d7d8e 100644 --- a/scopes/harmony/modules/feature-toggle/feature-toggle.ts +++ b/scopes/harmony/modules/feature-toggle/feature-toggle.ts @@ -70,3 +70,5 @@ export const CLOUD_IMPORTER = 'cloud-importer'; export const CLOUD_IMPORTER_V2 = 'cloud-importer-v2'; export const ALLOW_SAME_NAME = 'allow-same-name'; // not in use anymore + +export const DEPS_GRAPH = 'deps-graph'; diff --git a/scopes/preview/preview/strategies/env-strategy.ts b/scopes/preview/preview/strategies/env-strategy.ts index 8e6c5765ee83..1285afb32d34 100644 --- a/scopes/preview/preview/strategies/env-strategy.ts +++ b/scopes/preview/preview/strategies/env-strategy.ts @@ -22,7 +22,11 @@ export const ENV_STRATEGY_ARTIFACT_NAME = 'preview'; export class EnvBundlingStrategy implements BundlingStrategy { name = 'env'; - constructor(private preview: PreviewMain, private pkg: PkgMain, private dependencyResolver: DependencyResolverMain) {} + constructor( + private preview: PreviewMain, + private pkg: PkgMain, + private dependencyResolver: DependencyResolverMain + ) {} async computeTargets(context: ComputeTargetsContext, previewDefs: PreviewDefinition[]) { const outputPath = this.getOutputPath(context); diff --git a/scopes/scope/scope/scope.main.runtime.ts b/scopes/scope/scope/scope.main.runtime.ts index d49117529df6..8e7085103836 100644 --- a/scopes/scope/scope/scope.main.runtime.ts +++ b/scopes/scope/scope/scope.main.runtime.ts @@ -47,6 +47,7 @@ import { BitId } from '@teambit/legacy-bit-id'; import { ExtensionDataEntry, ExtensionDataList } from '@teambit/legacy/dist/consumer/config'; import { EnvsAspect, EnvsMain } from '@teambit/envs'; import { compact, slice, difference, partition } from 'lodash'; +import { DependenciesGraph } from '@teambit/legacy/dist/scope/models/dependencies-graph'; import { DepEdge } from '@teambit/legacy/dist/scope/models/version'; import { getGlobalConfigPath } from '@teambit/legacy/dist/global-config/config'; import { invalidateCache } from '@teambit/legacy/dist/api/consumer/lib/global-config'; @@ -1338,6 +1339,10 @@ export class ScopeMain implements ComponentFactory { return scope; } + + public getDependenciesGraphByComponentIds(componentIds: ComponentID[]): Promise { + return this.legacyScope.getDependenciesGraphByComponentIds(componentIds); + } } ScopeAspect.addRuntime(ScopeMain); diff --git a/scopes/scope/sign/sign.main.runtime.ts b/scopes/scope/sign/sign.main.runtime.ts index 2ff453c61403..14a38b3ebef8 100644 --- a/scopes/scope/sign/sign.main.runtime.ts +++ b/scopes/scope/sign/sign.main.runtime.ts @@ -110,6 +110,9 @@ ${componentsToSkip.map((c) => c.toString()).join('\n')}\n`); this.logger.clearStatusLine(); // it's enough to check the first component whether it's a snap or tag, because it can't be a mix of both const shouldRunSnapPipeline = isSnap(components[0].id.version); + await Promise.all( + components.map((component) => this.scope.legacyScope.loadDependenciesGraphForComponent(component.state._consumer)) + ); const { builderDataMap, pipeResults } = await this.builder.tagListener( components, { throwOnError: false, isSnap: shouldRunSnapPipeline }, @@ -126,7 +129,7 @@ ${componentsToSkip.map((c) => c.toString()).join('\n')}\n`); const legacyBuildResults = this.scope.builderDataMapToLegacyOnTagResults(builderDataMap); const legacyComponents = components.map((c) => c.state._consumer); this.snapping._updateComponentsByTagResult(legacyComponents, legacyBuildResults); - const publishedPackages = this.snapping._getPublishedPackages(legacyComponents); + const publishedPackages = Array.from(this.snapping._getPublishedPackages(legacyComponents).keys()); const pipeWithError = pipeResults.find((pipe) => pipe.hasErrors()); const buildStatus = pipeWithError ? BuildStatus.Failed : BuildStatus.Succeed; if (push) { diff --git a/scopes/scope/update-dependencies/update-dependencies.main.runtime.ts b/scopes/scope/update-dependencies/update-dependencies.main.runtime.ts index 7b488fe12107..635f154ed5e4 100644 --- a/scopes/scope/update-dependencies/update-dependencies.main.runtime.ts +++ b/scopes/scope/update-dependencies/update-dependencies.main.runtime.ts @@ -96,6 +96,9 @@ export class UpdateDependenciesMain { // an error saying "the extension ${extensionId.toString()} is missing from the flattenedDependencies" // if (!updateDepsOptions.simulation) { await this.snapping._addFlattenedDependenciesToComponents(this.legacyComponents); + await Promise.all( + this.legacyComponents.map((component) => this.scope.legacyScope.loadDependenciesGraphForComponent(component)) + ); // } this.addBuildStatus(); await this.addComponentsToScope(); @@ -108,7 +111,7 @@ export class UpdateDependenciesMain { ); const legacyBuildResults = this.scope.builderDataMapToLegacyOnTagResults(builderDataMap); this.snapping._updateComponentsByTagResult(this.legacyComponents, legacyBuildResults); - const publishedPackages = this.snapping._getPublishedPackages(this.legacyComponents); + const publishedPackages = Array.from(this.snapping._getPublishedPackages(this.legacyComponents).keys()); const pipeWithError = pipeResults.find((pipe) => pipe.hasErrors()); const buildStatus = pipeWithError ? BuildStatus.Failed : BuildStatus.Succeed; await this.saveDataIntoLocalScope(buildStatus); diff --git a/scopes/workspace/install/install.main.runtime.ts b/scopes/workspace/install/install.main.runtime.ts index c9e34ba53e01..5b3b9ed7ef99 100644 --- a/scopes/workspace/install/install.main.runtime.ts +++ b/scopes/workspace/install/install.main.runtime.ts @@ -16,6 +16,7 @@ import { Component, ComponentID, ComponentMap } from '@teambit/component'; import { createLinks } from '@teambit/dependencies.fs.linked-dependencies'; import pMapSeries from 'p-map-series'; import { Harmony, Slot, SlotRegistry } from '@teambit/harmony'; +import { type DependenciesGraph } from '@teambit/legacy/dist/scope/models/dependencies-graph'; import { CodemodResult, linkToNodeModulesWithCodemod, @@ -85,6 +86,7 @@ export type WorkspaceInstallOptions = { lockfileOnly?: boolean; writeConfigFiles?: boolean; skipPrune?: boolean; + dependenciesGraph?: DependenciesGraph; }; export type ModulesInstallOptions = Omit; @@ -326,6 +328,7 @@ export class InstallMain { const pmInstallOptions: PackageManagerInstallOptions = { ...calcManifestsOpts, autoInstallPeers: this.dependencyResolver.config.autoInstallPeers, + dependenciesGraph: options?.dependenciesGraph, includeOptionalDeps: options?.includeOptionalDeps, neverBuiltDependencies: this.dependencyResolver.config.neverBuiltDependencies, overrides: this.dependencyResolver.config.overrides, diff --git a/src/consumer/component/consumer-component.ts b/src/consumer/component/consumer-component.ts index 1a6f3f9ac62e..35119a4f77ea 100644 --- a/src/consumer/component/consumer-component.ts +++ b/src/consumer/component/consumer-component.ts @@ -10,6 +10,7 @@ import { getCloudDomain, BIT_WORKSPACE_TMP_DIRNAME, BuildStatus, DEFAULT_LANGUAG import { Doclet, parser as docsParser } from '@teambit/semantics.doc-parser'; import logger from '../../logger/logger'; import { ScopeListItem } from '../../scope/models/model-component'; +import { type DependenciesGraph } from '../../scope/models/dependencies-graph'; import Version, { DepEdge, Log } from '../../scope/models/version'; import { pathNormalizeToLinux, PathLinux, PathOsBased, PathOsBasedRelative } from '@teambit/toolbox.path.path'; import { sha1 } from '@teambit/toolbox.crypto.sha1'; @@ -99,6 +100,7 @@ export default class Component { // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! devDependencies: Dependencies; peerDependencies: Dependencies; + dependenciesGraph?: DependenciesGraph; flattenedDependencies: ComponentIdList; flattenedEdges: DepEdge[]; packageDependencies: Record; diff --git a/src/scope/models/dependencies-graph.ts b/src/scope/models/dependencies-graph.ts new file mode 100644 index 000000000000..52c55ee4a8c3 --- /dev/null +++ b/src/scope/models/dependencies-graph.ts @@ -0,0 +1,119 @@ +import semver from 'semver'; +import { PackageInfo } from '@pnpm/lockfile.types'; +import * as dp from '@pnpm/dependency-path'; + +export type PackagesMap = Map; + +export type PackageAttributes = PackageInfo & { + component?: { + scope: string; + name: string; + }; +}; + +export type DependencyEdge = { + id: string; + neighbours: DependencyNeighbour[]; + attr?: { + pkgId?: string; + transitivePeerDependencies?: string[]; + }; +}; + +export type DependencyNeighbour = { + id: string; + /** + * This is true when the dependency is from optionalDependencies. + */ + optional?: boolean; + name?: string; + specifier?: string; + lifecycle?: 'runtime' | 'dev'; +}; + +const DEPENDENCIES_GRAPH_SCHEMA_VERSION = '1.0'; + +export class DependenciesGraph { + static ROOT_EDGE_ID = '.'; + + schemaVersion: string; + packages: PackagesMap; + edges: DependencyEdge[]; + + constructor({ + packages, + edges, + schemaVersion, + }: { + packages: PackagesMap; + edges: DependencyEdge[]; + schemaVersion?: string; + }) { + this.packages = packages; + this.edges = edges; + this.schemaVersion = schemaVersion ?? DEPENDENCIES_GRAPH_SCHEMA_VERSION; + } + + serialize(): string { + return JSON.stringify({ + schemaVersion: this.schemaVersion, + packages: Object.fromEntries(this.packages.entries()), + edges: this.edges, + }); + } + + static deserialize(data: string): DependenciesGraph | undefined { + const parsed = JSON.parse(data); + // If the schema version is not supported, then we just ignore the data + if (parsed.schemaVersion !== DEPENDENCIES_GRAPH_SCHEMA_VERSION) { + return undefined; + } + return new DependenciesGraph({ + schemaVersion: parsed.schemaVersion, + edges: parsed.edges, + packages: new Map(Object.entries(parsed.packages)), + }); + } + + merge(graph: DependenciesGraph): void { + const directDependencies = graph.findRootEdge()?.neighbours; + if (directDependencies) { + for (const directDep of directDependencies) { + const existingDirectDeps = this.findRootEdge()?.neighbours; + if (existingDirectDeps) { + const existingDirectDep = existingDirectDeps.find( + ({ name, specifier }) => name === directDep.name && specifier === directDep.specifier + ); + if (existingDirectDep == null) { + existingDirectDeps.push(directDep); + } else if (existingDirectDep.id !== directDep.id && nodeIdLessThan(existingDirectDep.id, directDep.id)) { + existingDirectDep.id = directDep.id; + } + } + } + } + for (const [newPkgId, newPkgAttr] of graph.packages.entries()) { + this.packages.set(newPkgId, newPkgAttr); + } + this.edges.push(...graph.edges); + } + + isEmpty(): boolean { + return this.packages.size === 0 && this.edges.length === 0; + } + + /** + * Returns the edge related to the root component + */ + findRootEdge(): DependencyEdge | undefined { + return this.edges.find(({ id }) => id === DependenciesGraph.ROOT_EDGE_ID); + } +} + +function nodeIdLessThan(nodeId1: string, nodeId2: string): boolean { + const parsed1 = dp.parse(nodeId1); + if (!parsed1?.version) return false; + const parsed2 = dp.parse(nodeId2); + if (!parsed2?.version) return false; + return semver.lt(parsed1.version, parsed2.version); +} diff --git a/src/scope/models/version.ts b/src/scope/models/version.ts index 30da63ee4328..7645a5d73a2e 100644 --- a/src/scope/models/version.ts +++ b/src/scope/models/version.ts @@ -22,6 +22,7 @@ import Repository from '../objects/repository'; import validateVersionInstance from '../version-validator'; import Source from './source'; import { BitIdCompIdError } from '../exceptions/bit-id-comp-id-err'; +import { DependenciesGraph } from './dependencies-graph'; import { getBitVersion } from '@teambit/bit.get-bit-version'; export type SourceFileModel = { @@ -64,6 +65,7 @@ export type VersionProps = { _flattenedEdges?: DepEdge[]; flattenedEdges?: DepEdge[]; flattenedEdgesRef?: Ref; + dependenciesGraphRef?: Ref; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! packageDependencies?: { [key: string]: string }; // @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX! @@ -99,6 +101,8 @@ export default class Version extends BitObject { devDependencies: Dependencies; peerDependencies: Dependencies; flattenedDependencies: ComponentIdList; + dependenciesGraphRef?: Ref; + _dependenciesGraph?: DependenciesGraph; // caching for the dependencies graph flattenedEdgesRef?: Ref; // ref to a BitObject Source file, which is a JSON object containing the flattened edge _flattenedEdges?: DepEdge[]; // caching for the flattenedEdges /** @@ -147,6 +151,7 @@ export default class Version extends BitObject { this.flattenedDependencies = props.flattenedDependencies || new ComponentIdList(); this.flattenedEdges = props.flattenedEdges || []; this.flattenedEdgesRef = props.flattenedEdgesRef; + this.dependenciesGraphRef = props.dependenciesGraphRef; this.packageDependencies = props.packageDependencies || {}; this.devPackageDependencies = props.devPackageDependencies || {}; this.peerPackageDependencies = props.peerPackageDependencies || {}; @@ -198,6 +203,22 @@ export default class Version extends BitObject { return this._flattenedEdges; } + async loadDependenciesGraph(repo: Repository): Promise { + if (!this._dependenciesGraph) { + if (this.dependenciesGraphRef) { + // it's possible that there is a ref but the file is not there. + // it can happen if the remote-scope uses an older version that doesn't know to collect this ref. + // in which case, the client will get the Version object with the ref prop, but not the Source object. + const throws = false; + const dependenciesGraphSource = (await repo.load(this.dependenciesGraphRef, throws)) as Source | undefined; + if (dependenciesGraphSource) { + this._dependenciesGraph = DependenciesGraph.deserialize(dependenciesGraphSource.contents.toString()); + } + } + } + return this._dependenciesGraph; + } + validateVersion() { const nonEmptyFields = ['mainFile', 'files']; nonEmptyFields.forEach((field) => { @@ -359,6 +380,7 @@ export default class Version extends BitObject { allRefs.push(...artifacts); } if (this.flattenedEdgesRef) allRefs.push(this.flattenedEdgesRef); + if (this.dependenciesGraphRef) allRefs.push(this.dependenciesGraphRef); return allRefs; } @@ -410,6 +432,11 @@ export default class Version extends BitObject { const flattenedEdgesBuffer = Buffer.from(JSON.stringify(flattenedEdgesObj)); return Source.from(flattenedEdgesBuffer); } + static dependenciesGraphToSource(dependenciesGraph?: DependenciesGraph): Source | undefined { + if (!dependenciesGraph) return undefined; + const dependenciesGraphBuffer = Buffer.from(dependenciesGraph.serialize()); + return Source.from(dependenciesGraphBuffer); + } toObject() { const _convertFileToObject = (file) => { @@ -439,6 +466,7 @@ export default class Version extends BitObject { flattenedDependencies: this.flattenedDependencies.map((dep) => dep.toObject()), flattenedEdges: this.flattenedEdgesRef ? undefined : this.flattenedEdges.map((f) => Version.depEdgeToObject(f)), flattenedEdgesRef: this.flattenedEdgesRef?.toString(), + dependenciesGraphRef: this.dependenciesGraphRef?.toString(), extensions: this.extensions.toModelObjects(), packageDependencies: this.packageDependencies, devPackageDependencies: this.devPackageDependencies, @@ -495,6 +523,7 @@ export default class Version extends BitObject { flattenedDependencies, flattenedEdges, flattenedEdgesRef, + dependenciesGraphRef, flattenedDevDependencies, devPackageDependencies, peerPackageDependencies, @@ -602,6 +631,7 @@ export default class Version extends BitObject { // backward compatibility. before introducing `flattenedEdgesRef`, we only had `flattenedEdges`. see getFlattenedEdges() for more info. flattenedEdges: flattenedEdgesRef ? [] : flattenedEdges?.map((f) => Version.depEdgeFromObject(f)) || [], flattenedEdgesRef: flattenedEdgesRef ? Ref.from(flattenedEdgesRef) : undefined, + dependenciesGraphRef: dependenciesGraphRef ? Ref.from(dependenciesGraphRef) : undefined, devPackageDependencies, peerPackageDependencies, packageDependencies, @@ -637,10 +667,12 @@ export default class Version extends BitObject { component, files, flattenedEdges, + dependenciesGraph, }: { component: ConsumerComponent; files: Array; flattenedEdges?: Source; + dependenciesGraph?: Source; }) { const parseFile = (file) => { return { @@ -664,6 +696,7 @@ export default class Version extends BitObject { packageDependencies: component.packageDependencies, devPackageDependencies: component.devPackageDependencies, peerPackageDependencies: component.peerPackageDependencies, + dependenciesGraphRef: dependenciesGraph?.hash(), flattenedDependencies: component.flattenedDependencies, // it's safe to remove this line once the version.flattenedEdges prop is deleted flattenedEdges: component.flattenedEdges, diff --git a/src/scope/repositories/sources.ts b/src/scope/repositories/sources.ts index 75e27a7f4e00..41ca21bfff2b 100644 --- a/src/scope/repositories/sources.ts +++ b/src/scope/repositories/sources.ts @@ -282,6 +282,7 @@ to quickly fix the issue, please delete the object at "${this.objects().objectPa version: Version; files: any; flattenedEdges?: Source; + dependenciesGraph?: Source; }> { const clonedComponent: ConsumerComponent = consumerComponent.clone(); const files = consumerComponent.files.map((file) => { @@ -294,16 +295,18 @@ to quickly fix the issue, please delete the object at "${this.objects().objectPa }); const flattenedEdges = Version.flattenedEdgeToSource(consumerComponent.flattenedEdges); + const dependenciesGraph = Version.dependenciesGraphToSource(consumerComponent.dependenciesGraph); const version: Version = Version.fromComponent({ component: clonedComponent, files: files as any, flattenedEdges, + dependenciesGraph, }); // $FlowFixMe it's ok to override the pendingVersion attribute consumerComponent.pendingVersion = version as any; // helps to validate the version against the consumer-component - return { version, files, flattenedEdges }; + return { version, files, flattenedEdges, dependenciesGraph }; } put({ component, objects }: ComponentTree): ModelComponent { diff --git a/src/scope/scope.ts b/src/scope/scope.ts index 944b84dab755..80ade10c6ab2 100644 --- a/src/scope/scope.ts +++ b/src/scope/scope.ts @@ -1,6 +1,7 @@ import fs from 'fs-extra'; import * as pathLib from 'path'; import { ComponentID, ComponentIdList } from '@teambit/component-id'; +import { DEPS_GRAPH, isFeatureEnabled } from '@teambit/harmony.modules.feature-toggle'; import R from 'ramda'; import { BitId, BitIdStr } from '@teambit/legacy-bit-id'; import { LaneId } from '@teambit/lane-id'; @@ -49,6 +50,7 @@ import { UnexpectedPackageName } from '../consumer/exceptions/unexpected-package import { getDivergeData } from './component-ops/get-diverge-data'; import { StagedSnaps } from './staged-snaps'; import { collectGarbage } from './garbage-collector'; +import { type DependenciesGraph } from './models/dependencies-graph'; const removeNils = R.reject(R.isNil); const pathHasScope = pathHasAll([OBJECTS_DIR, SCOPE_JSON]); @@ -797,6 +799,37 @@ once done, to continue working, please run "bit cc"` Scope.scopeCache[scopePath] = scope; return scope; } + + public async getDependenciesGraphByComponentIds(componentIds: ComponentID[]): Promise { + let allGraph: DependenciesGraph | undefined; + if (!isFeatureEnabled(DEPS_GRAPH)) return undefined; + await Promise.all( + componentIds.map(async (componentId) => { + const graph = await this.getDependenciesGraphByComponentId(componentId); + if (graph == null || graph.isEmpty()) return; + if (allGraph == null) { + allGraph = graph; + } else { + allGraph.merge(graph); + } + }) + ); + return allGraph; + } + + public async getDependenciesGraphByComponentId(id: ComponentID): Promise { + let versionObj: Version; + try { + versionObj = await this.getVersionInstance(id); + } catch (err) { + return undefined; + } + return versionObj.loadDependenciesGraph(this.objects); + } + + public async loadDependenciesGraphForComponent(component: Component): Promise { + component.dependenciesGraph = await this.getDependenciesGraphByComponentId(component.id); + } } function composePath(patternPath: string, patterns: string[]): string[] { diff --git a/workspace.jsonc b/workspace.jsonc index 114c7ca1dc7f..a28438cf2389 100644 --- a/workspace.jsonc +++ b/workspace.jsonc @@ -34,11 +34,12 @@ "@pnpm/config": "900.0.0", "@pnpm/core": "900.0.1", "@pnpm/default-reporter": "900.0.0", - "@pnpm/dependency-path": "900.0.0", "@pnpm/error": "900.0.0", "@pnpm/fetch": "900.0.0", "@pnpm/list": "^900.0.0", "@pnpm/lockfile-file": "9.1.3", + "@pnpm/lockfile.filtering": "^900.0.0", + "@pnpm/lockfile.fs": "^900.0.0", "@pnpm/logger": "900.0.0", "@pnpm/modules-yaml": "900.0.0", "@pnpm/network.ca-file": "3.0.0", @@ -428,6 +429,7 @@ "jest": "29.3.1", "jest-message-util": "29.3.1", "jest-watcher": "29.7.0", + "js-yaml": "npm:@zkochan/js-yaml@0.0.7", "json-formatter-js": "2.3.4", "junit-report-builder": "3.0.1", "less": "^4.1.1",