Skip to content

Commit

Permalink
feat(utils, js): deps and DepsOptions are introduced
Browse files Browse the repository at this point in the history
  • Loading branch information
jjangga0214 committed Jun 13, 2023
1 parent a45f7e9 commit 2c8956b
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .changeset/deps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@haetae/utils': patch
'@haetae/javascript': patch
---

`deps` and `DepsOptions` are introduced.
36 changes: 36 additions & 0 deletions packages/docs/pages/apis/haetae-javascript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,42 @@ it's not just for a specific language, but for *any* dependency graph.
- `rootDir?{:ts}` : A directory to use when `entrypoint` or `tsConfig` is given as relative paths.
<small>(default: [`core.getConfigDirname(){:ts}`](./haetae-core#getconfigdirname))</small>

### `DepsOptions`

An argument interface for [`deps`](#deps).

<TokenLinkCode tokens={{'.DepsGraph': './haetae-utils#depsgraph'}}>
```ts
interface DepsOptions {
entrypoint: string
tsConfig?: string
rootDir?: string
additionalGraph?: utils.DepsGraph
}
```
</TokenLinkCode>

### `deps`

A function to get all of the direct and transitive dependencies of a single entry point.<br/>
The searched result keeps the order by breath-first approach, without duplication of elements.

<TokenLinkCode tokens={['DepsOptions']}>
```ts
(options: DepsOptions) => Promise<string[]>
```
</TokenLinkCode>

**Options**

- `entrypoint{:ts}` : An entry point to get all of whose direct and transitive dependencies.
- `tsConfig?{:ts}` : A path to Typescript config file. <small>(e.g. tsconfig.json)</small>.
- `rootDir?{:ts}` : A directory to join with when `entrypoint` is given as a relative path.
<small>(default: [`core.getConfigDirname(){:ts}`](./haetae-core#getconfigdirname))</small>
- `additionalGraph?{:ts}` : A graph to manually specify explicit dependency relationships.
This is purely additional, not an override or replacement of the source code dependency graph.
<small>(default: <TokenLinkCode inline tokens={{'graph' : './haetae-utils#graph'}}>`await graph({ edges: [], rootDir }){:ts}`</TokenLinkCode>)</small>

### `DependsOnOptions`

An argument interface for [`dependsOn`](#dependson).
Expand Down
31 changes: 31 additions & 0 deletions packages/docs/pages/apis/haetae-utils.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,37 @@ A function to merge multiple dependency graphs into one single unified graph.
```
</TokenLinkCode>

### `DepsOptions`

An argument interface for [`deps`](#deps).

<TokenLinkCode tokens={['DepsGraph']}>
```ts
interface DepsOptions {
entrypoint: string
graph: DepsGraph
rootDir?: string
}
```
</TokenLinkCode>

### `deps`

A function to get all of the direct and transitive dependencies of a single entry point.<br/>
The searched result keeps the order by breath-first approach, without duplication of elements.

<TokenLinkCode tokens={['DepsOptions']}>
```ts
(options: DepsOptions) => string[]
```
</TokenLinkCode>

**Options**

- `entrypoint{:ts}` : An entry point to get all of whose direct and transitive dependencies.
- `graph{:ts}` : A dependency graph. Return value of [`graph`](#graph) is proper.
- `rootDir?{:ts}` : A directory to join with when `entrypoint` is given as a relative path.
<small>(default: [`core.getConfigDirname(){:ts}`](./haetae-core#getconfigdirname))</small>

### `DependsOnOptions`

Expand Down
30 changes: 29 additions & 1 deletion packages/js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,35 @@ export async function graph({
return result
}

export interface DepsOptions {
entrypoint: string
rootDir?: string
tsConfig?: string
additionalGraph?: utils.DepsGraph
}

export async function deps({
entrypoint,
tsConfig,
rootDir = core.getConfigDirname(),
additionalGraph,
}: DepsOptions): Promise<string[]> {
/* eslint-disable no-param-reassign */
entrypoint = upath.resolve(rootDir, entrypoint)
additionalGraph =
additionalGraph || (await utils.graph({ edges: [], rootDir }))
/* eslint-enable no-param-reassign */

const jsGraph = await graph({
entrypoint,
tsConfig,
rootDir,
})
const mergedGraph = utils.mergeGraphs([jsGraph, additionalGraph])

return utils.deps({ entrypoint, graph: mergedGraph, rootDir })
}

export interface DependsOnOptions {
dependent: string
dependencies: readonly string[]
Expand All @@ -85,7 +114,6 @@ export async function dependsOn({
rootDir,
tsConfig,
})

const mergedGraph = utils.mergeGraphs([jsGraph, additionalGraph])

return utils.dependsOn({
Expand Down
36 changes: 36 additions & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,42 @@ export interface ChangedFilesOptions {
glob?: boolean
}

export interface DepsOptions {
entrypoint: string
graph: DepsGraph
rootDir?: string
}

export function deps({
entrypoint,
graph,
rootDir = core.getConfigDirname(),
}: DepsOptions): string[] {
/* eslint-disable no-param-reassign */
rootDir = toAbsolutePath({ path: rootDir, rootDir: core.getConfigDirname })
entrypoint = upath.resolve(rootDir, entrypoint)
/* eslint-enable no-param-reassign */

const checkedDeps = new Set<string>() // To avoid infinite loop by circular dependencies.
// `depsQueue` stores dependencies of dependencies.. and so on.
const depsQueue = [entrypoint] // Preserving dependency order (breadth-first search)
for (const dependency of depsQueue) {
if (!checkedDeps.has(dependency)) {
checkedDeps.add(dependency)
depsQueue.push(...(graph[dependency] || []))
}
}
checkedDeps.clear()
// Remove duplicates while preserving order
return depsQueue.filter((dep) => {
if (checkedDeps.has(dep)) {
return false
}
checkedDeps.add(dep)
return true
})
}

// eslint-disable-next-line @typescript-eslint/naming-convention
const _hash = hash

Expand Down
45 changes: 44 additions & 1 deletion packages/utils/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import upath from 'upath'
import { dirname } from 'dirname-filename-esm'
import { glob, $, graph, dependsOn, mergeGraphs } from '../src/index.js'
import { glob, $, graph, dependsOn, mergeGraphs, deps } from '../src/index.js'

describe('glob', () => {
test('basic usage', async () => {
Expand Down Expand Up @@ -239,6 +239,49 @@ describe('mergeGraphs', () => {
})
})

describe('deps', () => {
// Promise
const depsGraph = graph({
rootDir: '/',
edges: [
{
dependents: ['x', 'y'],
dependencies: ['a', 'e'],
},
{
dependents: ['a'],
dependencies: ['b', 'c'],
},
{
dependents: ['b'],
dependencies: ['d'],
},
{
dependents: ['d', 'e'],
dependencies: ['f'],
},
{
dependents: ['c', 'g'],
dependencies: ['e', 'f'],
},
{
dependents: ['h'],
dependencies: ['i'],
},
],
glob: false,
})
test('basic usage', async () => {
expect(
deps({
entrypoint: 'a',
graph: await depsGraph,
rootDir: '/',
}),
).toStrictEqual(['/a', '/b', '/c', '/d', '/e', '/f'])
})
})

describe('dependsOn', () => {
// Promise
const depsGraph = graph({
Expand Down

0 comments on commit 2c8956b

Please sign in to comment.