@hyperfrontend/project-scope/projectProject Module
The project module provides utilities for analyzing project structure, finding configuration files, reading package.json, discovering project roots, and traversing file trees.
Capabilities
Configuration Detection
Find and analyze configuration files in a project.
import { detectConfigs, findConfigFile } from '@hyperfrontend/project-scope'
// Detect all configuration files
const configs = detectConfigs('./my-project')
for (const config of configs) {
console.log(`${config.type}: ${config.path}`)
}
// Output:
// typescript: tsconfig.json
// eslint: eslint.config.js
// jest: jest.config.ts
// prettier: .prettierrc
// Detect specific config types
const tsConfigs = detectConfigs('./my-project', ['typescript', 'eslint'])
// Find specific config file
const eslintConfig = findConfigFile('./my-project', 'eslint')
// Returns: './my-project/eslint.config.js'
Supported Config Types
| Type | Example Files |
|---|---|
typescript | tsconfig.json, tsconfig.*.json |
eslint | .eslintrc, eslint.config.js, .eslintrc.json |
prettier | .prettierrc, prettier.config.js |
jest | jest.config.ts, jest.config.js |
vitest | vitest.config.ts |
babel | babel.config.js, .babelrc |
webpack | webpack.config.js |
vite | vite.config.ts |
rollup | rollup.config.js |
nx | nx.json, project.json |
docker | Dockerfile, docker-compose.yml |
env | .env, .env.* |
Package.json Utilities
Read and analyze package.json files.
import {
readPackageJson,
readPackageJsonIfExists,
findNearestPackageJson,
getDependencyVersion,
hasDependency,
} from '@hyperfrontend/project-scope'
// Read package.json
const pkg = readPackageJson('./my-project')
console.log(pkg.name, pkg.version)
console.log(pkg.dependencies)
console.log(pkg.scripts)
// Safe reading (returns null if not found)
const pkg2 = readPackageJsonIfExists('./maybe-project')
// Find nearest package.json from any path
const pkgPath = findNearestPackageJson('./src/utils/deep/file.ts')
// Returns: './src/package.json' or '../package.json'
// Check dependencies
if (hasDependency(pkg, 'react')) {
const version = getDependencyVersion(pkg, 'react')
console.log('React version:', version) // '^18.2.0'
}
Root Detection
Find project and workspace roots from any path.
import { findProjectRoot, findWorkspaceRoot } from '@hyperfrontend/project-scope'
// Find project root (nearest package.json with source files)
const projectRoot = findProjectRoot('./libs/my-lib/src/utils/helper.ts')
// Returns: './libs/my-lib'
// Find workspace/monorepo root
const workspaceRoot = findWorkspaceRoot('./libs/my-lib')
// Returns: './' (root with nx.json, turbo.json, etc.)
Root Markers
Project root markers:
package.json(withsrc/directory or entry files)project.json(NX project)
Workspace root markers:
nx.jsonturbo.jsonlerna.jsonpnpm-workspace.yamlrush.jsonpackage.jsonwithworkspacesfield
File Traversal
Search and walk through project files.
import { findFiles, walkDirectory, walkTree } from '@hyperfrontend/project-scope'
// Find files by glob pattern
const tsFiles = findFiles('./src', '**/*.ts')
const configFiles = findFiles('./', ['*.json', '*.yaml'])
// With options
const limited = findFiles('./src', '**/*.ts', {
maxResults: 10,
absolutePaths: true,
maxDepth: 5,
})
// Walk directory with callback
walkDirectory('./src', (entry) => {
if (entry.isFile && entry.name.endsWith('.ts')) {
console.log('Found:', entry.relativePath)
}
// Return 'skip' to skip directory, 'stop' to stop walking
})
// Walk virtual file system tree
walkTree(tree, tree.root, (entry) => {
console.log(entry.path, entry.isFile ? 'file' : 'directory')
})
Interfaces
PackageJson
interface PackageJson {
name?: string
version?: string
description?: string
main?: string
module?: string
browser?: string
types?: string
bin?: string | Record<string, string>
scripts?: Record<string, string>
dependencies?: Record<string, string>
devDependencies?: Record<string, string>
peerDependencies?: Record<string, string>
optionalDependencies?: Record<string, string>
workspaces?: string[] | { packages: string[] }
exports?: Record<string, unknown>
engines?: Record<string, string>
[key: string]: unknown
}
DetectedConfig
interface DetectedConfig {
/** Config type (e.g., 'typescript', 'eslint') */
type: ConfigType
/** File path relative to root */
path: string
/** Pattern that matched */
matchedPattern: string
/** Pattern info */
info: ConfigPatternInfo
}
DirectoryEntry
interface DirectoryEntry {
/** File/directory name */
name: string
/** Full path */
path: string
/** Relative path from start */
relativePath: string
/** Is a file */
isFile: boolean
/** Is a directory */
isDirectory: boolean
/** Traversal depth */
depth: number
}
Design Principles
- Caching: All detection functions cache results appropriately
- Safe operations:
*IfExistsvariants return null instead of throwing - Flexible patterns: Support for multiple glob patterns
- Depth control: Configurable traversal depth limits
- Cross-platform: Works on Windows, macOS, and Linux
API Reference
ƒ Functions
Useful for testing or when the project files have changed.
Example
Clearing the config detection cache
import { clearConfigDetectionCache } from '@hyperfrontend/project-scope'
// Reset cache after modifying config files
clearConfigDetectionCache()detectConfigs(rootPath: string, types?: ConfigType[], options?: DetectConfigOptions): DetectedConfig[]
Results are cached for 30 seconds per project path and options to avoid redundant file system operations on repeated calls.
Parameters
| Name | Type | Description |
|---|---|---|
§rootPath | string | Project root directory |
§types? | ConfigType[] | Optional array of config types to check (defaults to all) |
§options? | DetectConfigOptions | Detection options |
Returns
DetectedConfig[]Example
Detecting configuration files
import { detectConfigs } from '@hyperfrontend/project-scope'
// Detect all config files
const configs = detectConfigs('./my-project')
for (const config of configs) {
console.log(`${config.type}: ${config.path}`)
}
// Output:
// typescript: tsconfig.json
// eslint: eslint.config.js
// jest: jest.config.ts
// Detect specific config types only
const tsConfigs = detectConfigs('./my-project', ['typescript', 'eslint'])Parameters
| Name | Type | Description |
|---|---|---|
§rootPath | string | Project root directory |
§type | ConfigType | Config type to find |
Returns
stringExample
Finding a specific config file
import { findConfigFile } from '@hyperfrontend/project-scope'
const tsConfig = findConfigFile('/project', 'typescript')
// => '/project/tsconfig.json'
const eslint = findConfigFile('/project', 'eslint')
// => '/project/.eslintrc.js' or null if not foundfindDirectories(startPath: string, patterns: string | string[], options?: FindOptions): string[]
Parameters
| Name | Type | Description |
|---|---|---|
§startPath | string | Root directory to begin the search |
§patterns | string | string[] | Glob patterns to filter directories (supports wildcards) |
§options? | FindOptions | Configuration for search behavior |
Returns
string[]Example
Finding directories by pattern
import { findDirectories } from '@hyperfrontend/project-scope'
const componentDirs = findDirectories('./src', 'components')
// => ['features/auth/components', 'features/dashboard/components']Parameters
| Name | Type | Description |
|---|---|---|
§startPath | string | Root directory to begin the search |
§patterns | string | string[] | Glob patterns (e.g., '.ts', '/.json') to filter files |
§options? | FindOptions | Configuration for search behavior |
Returns
string[]Example
Finding files by pattern
import { findFiles } from '@hyperfrontend/project-scope'
// Find all TypeScript files
const tsFiles = findFiles('./src', '\*\*/*.ts')
// Find multiple file types
const configFiles = findFiles('./', ['\*.json', '\*.yaml', '\*.yml'])
// Limit results and get absolute paths
const first10 = findFiles('./src', '\*\*/*.ts', {
maxResults: 10,
absolutePaths: true
})Parameters
| Name | Type | Description |
|---|---|---|
§tree | Tree | In-memory virtual file system representation |
§patterns | string | string[] | Glob patterns (e.g., '.ts', '/.json') to filter files |
§options? | FindOptions | Configuration for search behavior |
Returns
string[]Example
Finding files in a virtual tree
import { createTree, findFilesInTree } from '@hyperfrontend/project-scope'
const tree = createTree('/workspace')
const tsFiles = findFilesInTree(tree, '**/*.ts', { maxDepth: 3 })
// => ['src/index.ts', 'src/utils/helpers.ts']Parameters
| Name | Type | Description |
|---|---|---|
§startPath | string | Starting path |
Returns
stringExample
Finding Git repository root
import { findGitRoot } from '@hyperfrontend/project-scope'
const gitRoot = findGitRoot('./src/deep/nested/file.ts')
// => '/path/to/repository'Parameters
| Name | Type | Description |
|---|---|---|
§startPath | string | Starting path |
Returns
stringExample
Finding nearest package.json
import { findNearestPackageJson } from '@hyperfrontend/project-scope'
const pkgDir = findNearestPackageJson('./src/deep/nested/file.ts')
// => '/path/to/project'Parameters
| Name | Type | Description |
|---|---|---|
§startPath | string | Starting path |
Returns
stringExample
Finding project root
import { findProjectRoot } from '@hyperfrontend/project-scope'
// Find project root from current directory
const root = findProjectRoot(process.cwd())
if (root) {
console.log('Project root:', root)
}
// Find root from a deeply nested file
const root2 = findProjectRoot('./libs/my-lib/src/utils/helper.ts')Parameters
Returns
stringExample
Finding root by marker files
import { findRootDirectory } from '@hyperfrontend/project-scope'
// Find monorepo root by looking for nx.json or lerna.json
const root = findRootDirectory('./libs/my-lib', ['nx.json', 'lerna.json'])
// => '/path/to/monorepo'Parameters
| Name | Type | Description |
|---|---|---|
§startPath | string | Starting path |
Returns
stringExample
Finding workspace root
import { findWorkspaceRoot } from '@hyperfrontend/project-scope'
const root = findWorkspaceRoot('./libs/my-lib')
if (root) {
console.log('Monorepo root:', root) // e.g., '/home/user/my-monorepo'
}Parameters
| Name | Type | Description |
|---|---|---|
§packageJson | PackageJson | Parsed package.json |
Returns
DependencyMapExample
Getting all merged dependencies
import { getAllDependencies } from '@hyperfrontend/project-scope'
const allDeps = getAllDependencies(packageJson)
if ('typescript' in allDeps) {
console.log('TypeScript version:', allDeps['typescript'])
}Parameters
| Name | Type | Description |
|---|---|---|
§types | ConfigType[] | Array of config types to get patterns for |
Returns
string[]Example
Retrieving config patterns by type
import { getConfigPatternsByType } from '@hyperfrontend/project-scope'
const patterns = getConfigPatternsByType(['typescript', 'eslint'])
// => ['tsconfig.json', 'tsconfig.*.json', '.eslintrc', '.eslintrc.js', ...]Parameters
| Name | Type | Description |
|---|---|---|
§packageJson | PackageJson | Parsed package.json |
Returns
AllDependenciesExample
Extracting all dependencies
import { getDependencies } from '@hyperfrontend/project-scope'
const deps = getDependencies(packageJson)
console.log('Runtime:', Object.keys(deps.dependencies))
console.log('Dev:', Object.keys(deps.devDependencies))Parameters
| Name | Type | Description |
|---|---|---|
§packageJson | PackageJson | Parsed package.json content |
§name | string | Name of the dependency to look up |
Returns
stringExample
Getting dependency version
import { getDependencyVersion } from '@hyperfrontend/project-scope'
const version = getDependencyVersion(packageJson, 'react')
// => '^18.2.0' or nullParameters
| Name | Type | Description |
|---|---|---|
§packageJson | PackageJson | Parsed package.json |
Returns
DependencyMapExample
Getting development dependencies
import { getDevDependencies } from '@hyperfrontend/project-scope'
const devDeps = getDevDependencies(packageJson)
// => { 'jest': '^29.0.0', 'typescript': '^5.0.0' }Parameters
| Name | Type | Description |
|---|---|---|
§packageJson | PackageJson | Parsed package.json |
Returns
DependencyMapExample
Getting peer dependencies
import { getPeerDependencies } from '@hyperfrontend/project-scope'
const peerDeps = getPeerDependencies(packageJson)
// => { 'react': '^18.0.0', 'react-dom': '^18.0.0' }Parameters
| Name | Type | Description |
|---|---|---|
§packageJson | PackageJson | Parsed package.json |
Returns
DependencyMapExample
Getting production dependencies
import { getProductionDependencies } from '@hyperfrontend/project-scope'
const prodDeps = getProductionDependencies(packageJson)
// => { 'express': '^4.18.0', 'lodash': '^4.17.21' }Parameters
| Name | Type | Description |
|---|---|---|
§packageJson | PackageJson | Parsed package.json |
Returns
string[]Example
Getting workspace patterns
import { getWorkspaces } from '@hyperfrontend/project-scope'
const patterns = getWorkspaces(packageJson)
// => ['packages/*', 'apps/*']hasDependency(packageJson: PackageJson, name: string, depTypes?: ("dependencies" | "devDependencies" | "peerDependencies" | "optionalDependencies")[]): boolean
Parameters
| Name | Type | Description |
|---|---|---|
§packageJson | PackageJson | Parsed package.json content |
§name | string | Name of the dependency to check |
§depTypes? | ("dependencies" | "devDependencies" | "peerDependencies" | "optionalDependencies")[] | Optional array of dependency types to check (defaults to all) |
Returns
booleanExample
Checking for a dependency
import { hasDependency } from '@hyperfrontend/project-scope'
// Check any dependency type
hasDependency(packageJson, 'lodash')
// Check only production dependencies
hasDependency(packageJson, 'lodash', ['dependencies'])Parameters
Returns
booleanExample
Checking installed packages
import { hasInstalledPackage } from '@hyperfrontend/project-scope'
if (hasInstalledPackage('/project', 'typescript')) {
console.log('TypeScript is installed')
}Parameters
| Name | Type | Description |
|---|---|---|
§packageJson | PackageJson | Parsed package.json |
Returns
booleanExample
Checking for workspaces
import { hasWorkspaces } from '@hyperfrontend/project-scope'
if (hasWorkspaces(packageJson)) {
console.log('This is a monorepo')
}Parameters
| Name | Type | Description |
|---|---|---|
§filePath | string | Path to config file |
§type? | ConfigType | Optional config type (auto-detected if not provided) |
Returns
ParsedConfigExample
Parsing a configuration file
import { parseConfig } from '@hyperfrontend/project-scope'
const tsConfig = parseConfig('/project/tsconfig.json')
const eslintConfig = parseConfig('/project/.eslintrc.yml', 'eslint')parseJsonConfig(filePath: string, content: string, type?: ConfigType, format: "json" | "jsonc"): ParsedConfig
Parameters
| Name | Type | Description |
|---|---|---|
§filePath | string | Path to the JSON configuration file |
§content | string | Raw file content to parse |
§type? | ConfigType | Category of configuration (e.g., typescript, eslint) |
§format | "json" | "jsonc" | Whether to strip comments (jsonc) or parse strictly (json) (default: 'json') |
Returns
ParsedConfigExample
Parsing JSON configuration
import { parseJsonConfig } from '@hyperfrontend/project-scope'
const config = parseJsonConfig(
'tsconfig.json',
'{ "extends": "./base.json", "compilerOptions": {} }',
'typescript'
)
// => { type: 'typescript', path: 'tsconfig.json', data: {...}, extends: ['./base.json'] }Parameters
| Name | Type | Description |
|---|---|---|
§filePath | string | Path to the YAML configuration file |
§content | string | Raw file content to parse |
§type? | ConfigType | Category of configuration (e.g., github-actions, docker-compose) |
Returns
ParsedConfigExample
Parsing YAML configuration
import { parseYamlConfig } from '@hyperfrontend/project-scope'
const config = parseYamlConfig('.github/workflows/ci.yml', yamlContent, 'github-actions')
// => { type: 'github-actions', path: '...', format: 'yaml', data: {...} }Parameters
| Name | Type | Description |
|---|---|---|
§projectPath | string | Project directory path or path to package.json |
Returns
PackageJsonExample
Reading package.json
import { readPackageJson } from '@hyperfrontend/project-scope'
const pkg = readPackageJson('/path/to/project')
console.log(pkg.name, pkg.version)Parameters
| Name | Type | Description |
|---|---|---|
§projectPath | string | Project directory path or path to package.json |
Returns
PackageJsonExample
Reading package.json if it exists
import { readPackageJsonIfExists } from '@hyperfrontend/project-scope'
const pkg = readPackageJsonIfExists('/path/to/project')
if (pkg) {
console.log('Found:', pkg.name)
}Parameters
| Name | Type | Description |
|---|---|---|
§startPath | string | Root directory to begin traversal |
§visitor | WalkVisitor | Callback function invoked for each file system entry |
§options? | WalkOptions | Configuration for traversal behavior |
Example
Walking a directory tree
import { walkDirectory } from '@hyperfrontend/project-scope'
const tsFiles: string[] = []
walkDirectory('./src', (entry) => {
if (entry.isFile && entry.name.endsWith('.ts')) {
tsFiles.push(entry.relativePath)
}
}, { maxDepth: 5, respectGitignore: true })Parameters
| Name | Type | Description |
|---|---|---|
§tree | Tree | In-memory virtual file system representation |
§startPath | string | Root path within the tree to begin traversal |
§visitor | WalkVisitor | Callback function invoked for each tree entry |
§options? | WalkOptions | Configuration for traversal behavior |
Example
Walking a virtual tree
import { createTree, walkTree } from '@hyperfrontend/project-scope'
const tree = createTree('/workspace')
walkTree(tree, 'src', (entry) => {
if (entry.isDirectory) {
console.log('Dir:', entry.relativePath)
return 'skip' // Don't recurse into this directory
}
})◈ Interfaces
Properties
Properties
format?:"json" | "yaml" | "js" | "ts" | "jsonc" | "ini" | "dotenv" | "text"Properties
Properties
Properties
Properties
Properties
Properties
◆ Types
type ConfigType = "package.json" | "package-lock.json" | "pnpm-lock.yaml" | "yarn.lock" | ".npmrc" | "tsconfig" | "nx" | "project.json" | "workspace.json" | "turbo" | "lerna" | "webpack" | "rollup" | "vite" | "esbuild" | "babel" | "swc" | "jest" | "vitest" | "cypress" | "playwright" | "next" | "angular" | "nuxt" | "svelte" | "astro" | "eslint" | "prettier" | "env" | ".gitignore" | ".gitattributes"type DependencyMap = Record<string, string>type WalkVisitor = (entry: WalkEntry) => WalkVisitorResulttype WalkVisitorResult = void | "skip" | "stop"