Skip to content

Commit

Permalink
feat: findWorkspaceDir (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Sep 6, 2022
1 parent e0bae4a commit 8b53c08
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 3 deletions.
15 changes: 15 additions & 0 deletions README.md
Expand Up @@ -106,6 +106,21 @@ import { resolveLockFile } from 'pkg-types'
const lockfile = await resolveLockFile('.')
```

### `findWorkspaceDir`

Try to detect workspace dir by in order:

1. Nearest `.git` directory
2. Farthest lockfile
3. Farthest `package.json` file

If fails, throws an error.

```js
import { findWorkspaceDir } from 'pkg-types'
const workspaceDir = await findWorkspaceDir('.')
```

## Types

**Note:** In order to make types working, you need to install `typescript` as a devDependency.
Expand Down
28 changes: 27 additions & 1 deletion src/index.ts
@@ -1,7 +1,8 @@
import { promises as fsp } from 'fs'
import { dirname, resolve } from 'path'
import { ResolveOptions as _ResolveOptions, resolvePath } from 'mlly'
import { isAbsolute } from 'pathe'
import { FindFileOptions, findNearestFile } from './utils'
import { findFile, FindFileOptions, findNearestFile } from './utils'
import type { PackageJson, TSConfig } from './types'

export * from './types'
Expand Down Expand Up @@ -60,3 +61,28 @@ export async function resolveLockfile (id: string = process.cwd(), opts: Resolve
}
throw new Error('No lockfile found from ' + id)
}

export async function findWorkspaceDir (id: string = process.cwd(), opts: ResolveOptions = {}): Promise<string> {
const resolvedPath = isAbsolute(id) ? id : await resolvePath(id, opts)
const _opts = { startingFrom: resolvedPath, ...opts }

// Lookup for .git/config
try {
const r = await findNearestFile('.git/config', _opts)
return resolve(r, '../..')
} catch { }

// Lookdown for lockfile
try {
const r = await resolveLockfile(resolvedPath, { ..._opts, reverse: true })
return dirname(r)
} catch { }

// Lookdown for package.json
try {
const r = await findFile(resolvedPath, _opts)
return dirname(r)
} catch { }

throw new Error('Cannot detect workspace root from ' + id)
}
2 changes: 1 addition & 1 deletion src/utils.ts
Expand Up @@ -61,7 +61,7 @@ export async function findFile (filename: string, _options: FindFileOptions = {}
if (await options.test(filePath)) { return filePath }
}
} else {
for (let i = root + 1; i < segments.length; i++) {
for (let i = root + 1; i <= segments.length; i++) {
const filePath = join(...segments.slice(0, i), filename)
if (await options.test(filePath)) { return filePath }
}
Expand Down
12 changes: 11 additions & 1 deletion test/index.test.ts
Expand Up @@ -11,7 +11,8 @@ import {
writeTSConfig,
TSConfig,
ResolveOptions,
resolveLockfile
resolveLockfile,
findWorkspaceDir
} from '../src'

const fixtureDir = resolve(dirname(fileURLToPath(import.meta.url)), 'fixture')
Expand Down Expand Up @@ -97,3 +98,12 @@ describe('resolveLockfile', () => {
expect(await resolveLockfile(rFixture('.'))).to.equal(rFixture('../..', 'pnpm-lock.yaml'))
})
})

describe('findWorkspaceDir', () => {
it('works', async () => {
expect(await findWorkspaceDir(rFixture('./sub'))).to.equal(rFixture('../..'))
expect(await findWorkspaceDir(rFixture('.'))).to.equal(rFixture('../..'))
expect(await findWorkspaceDir(rFixture('..'))).to.equal(rFixture('../..'))
expect(await findWorkspaceDir(rFixture('../..'))).to.equal(rFixture('../..'))
})
})

0 comments on commit 8b53c08

Please sign in to comment.