Skip to content

Helpers to assist monorepo dependencies traversals

License

Notifications You must be signed in to change notification settings

semrel-extra/topo

Repository files navigation

@semrel-extra/topo

CI Maintainability Test Coverage

Helpers to assist monorepo dependencies traversals

Install

yarn add @semrel-extra/topo

Usage

import { topo } from '@semrel-extra/topo'

const graph = topo({
  workspaces: ['packages/*'],
  cwd: '/path/to/project/root'
})

{
  queue: ['pkg-a', 'pkg-b', 'pkg-z', 'pkg-y', 'pkg-x'],
  nodes: ['pkg-a', 'pkg-b', 'pkg-x', 'pkg-y', 'pkg-z'],
  edges: [
    ['pkg-a', 'pkg-b'],
    ['pkg-z', 'pkg-y'],
    ['pkg-y', 'pkg-x'],
  ],
  // packages entries map
  packages: {
    'pkg-a': {
      manifest: {
        name: 'pkg-a',
        dependencies: {}
      },
      manifestPath: '/path/to/project/root/packages/a/package.json',
      path: 'packages/a', // legacy
      relPath: 'packages/a',
      absPath: '/path/to/project/root/packages/a'
    },
    'pkg-b': {...},
    ...
  }
}

pkgFilter() / filter()

Filter option is a function: gets IPackageEntry as argument, returns boolean

const graph = topo({
  workspaces: ['packages/*'],
  cwd: '/path/to/project/root',
  filter: ({manifest}) => !manifest.private // to omit private packages from graph
})

depFilter()

Applies filter to any kind of pkg dependencies to omit them from the graph.

const gpaph = topo({
  workspaces: ['packages/*'],
  cwd: '/path/to/project/root',
  depFilter: ({version}) => version.startsWith('workspace:') // include only workspace deps
})

workspacesExtra

Injects extra pattern to the resolved workspaces value from package.json / pnpm-workspace.yaml

const gpaph = topo({
  workspacesExtra: ['!packages/foo'],
  cwd: '/path/to/project/root'
})

traverseDeps()

Iterates up to the pkg deps graph.

import {topo, traverseDeps} from '@semrel-extra/topo'

const {packages} = topo({
  workspaces: ['packages/*'],
  cwd: '/path/to/project/root'
})
const pkg = packages['pkg-a']
const cb = async ({name, pkg}: IDepEntry) => {
  await traverseDeps({pkg, packages, cb})
}

await traverseDeps({packages, pkg, cb})

traverseQueue()

Iterates over the queue of packages in the order of their dependencies.

import {topo, traverseQueue} from '@semrel-extra/topo'

const {queue, prev} = await topo({
  workspaces: ['packages/*'],
  cwd: '/path/to/project/root'
})
const cb = async (name: string) => {
  // some async action
}
await traverseQueue({ queue, prev, cb })

iterateDeps()

Walks through the package dependencies and applies the cb() for each.

const results: any[] = []
const manifest = {
  name: 'foo',
  version: '0.0.0',
  dependencies: {
    bar: '1.0.0'
  },
  devDependencies: {
    baz: '2.0.0'
  }
}

iterateDeps(manifest, ({ name, version, scope, deps }) => {
  results.push({ name, version, scope, deps })
})

License

MIT