or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# @traf/core

1

2

@traf/core is a TypeScript library that intelligently identifies truly affected projects in monorepos by analyzing code changes at the line and semantic level, rather than using traditional file-level dependency analysis. It uses the TypeScript compiler API to find changed code elements (functions, classes, constants) and recursively tracks their references across the monorepo to determine which projects are actually impacted by changes.

3

4

## Package Information

5

6

- **Package Name**: @traf/core

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install @traf/core`

10

11

## Core Imports

12

13

```typescript

14

import { trueAffected, DEFAULT_INCLUDE_TEST_FILES } from '@traf/core';

15

import type { TrueAffected, TrueAffectedProject, TrueAffectedLogging } from '@traf/core';

16

import type { CompilerOptions } from 'ts-morph';

17

```

18

19

This package is ESM-only (`"type": "module"` in package.json). Note that `CompilerOptions` is not exported from `@traf/core` and must be imported from `ts-morph` if you need to type the `compilerOptions` parameter.

20

21

## Basic Usage

22

23

```typescript

24

import { trueAffected } from '@traf/core';

25

26

const affectedProjects = await trueAffected({

27

cwd: process.cwd(),

28

rootTsConfig: 'tsconfig.base.json',

29

base: 'origin/main',

30

projects: [

31

{

32

name: 'my-app',

33

sourceRoot: 'apps/my-app/src',

34

tsConfig: 'apps/my-app/tsconfig.json',

35

},

36

{

37

name: 'shared-lib',

38

sourceRoot: 'libs/shared/src',

39

tsConfig: 'libs/shared/tsconfig.json',

40

},

41

],

42

});

43

44

console.log('Affected projects:', affectedProjects);

45

// Output: ['my-app', 'shared-lib']

46

```

47

48

## Architecture

49

50

@traf/core operates through the following key processes:

51

52

- **Git Diff Analysis**: Uses git to identify all changed lines in the current branch compared to a base branch

53

- **Semantic Code Analysis**: Uses ts-morph (TypeScript Compiler API wrapper) to parse changed lines and identify the specific code elements that changed (functions, classes, constants, etc.)

54

- **Reference Tracking**: Recursively finds all references to changed elements across the entire monorepo using TypeScript's language service

55

- **Project Mapping**: Maps source files to their containing projects and builds the list of affected projects

56

- **Non-Source File Handling**: Tracks changes to non-source files (assets, configs) by finding imports/requires of those files

57

- **Implicit Dependencies**: Includes projects that declare implicit dependencies on affected projects

58

- **Lockfile Analysis**: Experimental feature to detect dependency changes in package-lock files and find affected files

59

60

## Capabilities

61

62

### True Affected Analysis

63

64

Analyzes a monorepo to find projects that are truly affected by code changes in the current branch. Uses semantic-level change detection rather than file-level to reduce false positives.

65

66

```typescript { .api }

67

/**

68

* Finds projects that are truly affected by code changes based on line-level semantic analysis

69

* @param options - Configuration object

70

* @returns Promise resolving to array of affected project names

71

*/

72

function trueAffected(options: TrueAffected): Promise<string[]>;

73

74

interface TrueAffected extends TrueAffectedLogging {

75

/** Current working directory */

76

cwd: string;

77

78

/** Path to root tsconfig file with path mappings for all projects (optional but recommended) */

79

rootTsConfig?: string;

80

81

/** Base branch to compare against (default: 'origin/main') */

82

base?: string;

83

84

/** Array of projects to analyze */

85

projects: TrueAffectedProject[];

86

87

/** Patterns to include regardless of semantic analysis (e.g., test files). Default: test/spec files */

88

include?: (string | RegExp)[];

89

90

/** TypeScript compiler options from ts-morph */

91

compilerOptions?: CompilerOptions;

92

93

/** Paths to ignore during analysis (default: node_modules, dist, build, .git) */

94

ignoredPaths?: (string | RegExp)[];

95

96

/** Experimental feature to detect lockfile changes and find affected files */

97

__experimentalLockfileCheck?: boolean;

98

}

99

100

interface TrueAffectedProject {

101

/** Project name */

102

name: string;

103

104

/** Project source root directory path */

105

sourceRoot: string;

106

107

/** Path to project's tsconfig file (default: {sourceRoot}/tsconfig.json) */

108

tsConfig?: string;

109

110

/** Array of project names that implicitly depend on this project */

111

implicitDependencies?: string[];

112

113

/** Build targets for the project */

114

targets?: string[];

115

}

116

117

interface TrueAffectedLogging {

118

/** Console-compatible logger instance (default: console with debug controlled by DEBUG env var) */

119

logger?: Console;

120

}

121

```

122

123

**Usage Example:**

124

125

```typescript

126

import { trueAffected } from '@traf/core';

127

128

// Analyze monorepo with custom configuration

129

const affected = await trueAffected({

130

cwd: '/path/to/monorepo',

131

rootTsConfig: 'tsconfig.base.json',

132

base: 'origin/develop',

133

projects: [

134

{

135

name: 'api-service',

136

sourceRoot: 'apps/api/src',

137

tsConfig: 'apps/api/tsconfig.json',

138

implicitDependencies: ['database-migrations'],

139

},

140

{

141

name: 'web-app',

142

sourceRoot: 'apps/web/src',

143

tsConfig: 'apps/web/tsconfig.json',

144

},

145

{

146

name: 'shared-utils',

147

sourceRoot: 'libs/utils/src',

148

tsConfig: 'libs/utils/tsconfig.json',

149

},

150

{

151

name: 'database-migrations',

152

sourceRoot: 'libs/migrations',

153

},

154

],

155

include: [

156

/\.(spec|test)\.(ts|js)x?$/, // Include test files

157

/\.config\.(ts|js)$/, // Include config files

158

],

159

ignoredPaths: [

160

'./node_modules',

161

'./dist',

162

'./coverage',

163

],

164

logger: console,

165

});

166

167

console.log(`Found ${affected.length} affected projects:`, affected);

168

```

169

170

**Notes:**

171

172

- The `rootTsConfig` should include a `paths` property mapping all projects so ts-morph can resolve references across the monorepo

173

- Each project's `tsConfig` should only include files for that specific project

174

- If a project's `tsConfig` doesn't exist, the library will add all `.ts` and `.js` files from the `sourceRoot`

175

- The algorithm tracks changes recursively, so if function A is changed and function B references A, both projects containing A and B are marked as affected

176

- Setting `DEBUG=true` environment variable enables detailed debug logging

177

178

### Default Test File Pattern

179

180

Regular expression constant for the default test file inclusion pattern.

181

182

```typescript { .api }

183

const DEFAULT_INCLUDE_TEST_FILES: RegExp;

184

```

185

186

This constant equals `/\.(spec|test)\.(ts|js)x?/` and matches files like:

187

- `file.spec.ts`

188

- `file.test.js`

189

- `component.spec.tsx`

190

- `utils.test.jsx`

191

192

**Usage Example:**

193

194

```typescript

195

import { trueAffected, DEFAULT_INCLUDE_TEST_FILES } from '@traf/core';

196

197

const affected = await trueAffected({

198

cwd: process.cwd(),

199

rootTsConfig: 'tsconfig.base.json',

200

projects: [...],

201

include: [

202

DEFAULT_INCLUDE_TEST_FILES,

203

/\.e2e\.(ts|js)$/, // Also include e2e test files

204

],

205

});

206

```

207

208

## Types

209

210

### CompilerOptions

211

212

Type re-exported from ts-morph for TypeScript compiler configuration.

213

214

```typescript { .api }

215

import { CompilerOptions } from 'ts-morph';

216

```

217

218

This type is used in the `TrueAffected.compilerOptions` property to configure the TypeScript compiler behavior during analysis. Common options include:

219

220

```typescript

221

const affected = await trueAffected({

222

cwd: process.cwd(),

223

projects: [...],

224

compilerOptions: {

225

allowJs: true, // Allow JavaScript files (default: true)

226

strict: false, // Disable strict type checking for analysis

227

skipLibCheck: true, // Skip type checking of declaration files

228

},

229

});

230

```

231

232

## How It Works

233

234

The algorithm performs the following steps:

235

236

1. **Git Diff Extraction**: Runs `git diff` against the base branch to identify all changed files and the specific line numbers that changed in each file

237

238

2. **TypeScript Project Setup**: Creates a ts-morph Project instance and adds all source files from the specified projects using their tsconfig files

239

240

3. **Changed Line Analysis**: For each changed line in source files:

241

- Finds the AST node at that line number

242

- Identifies the root code element (function, class, const, etc.) containing that line

243

- Marks the containing project as affected

244

245

4. **Reference Tracking**: For each changed element:

246

- Uses ts-morph's `findReferencesAsNodes()` to find all references to that element

247

- Recursively processes each reference to find its references

248

- Marks all projects containing references as affected

249

- Maintains a visited set to avoid infinite loops

250

251

5. **Non-Source File Handling**: For changed non-source files (images, JSON, etc.):

252

- Searches the codebase for imports/requires of those files

253

- Treats those import statements as changed lines and applies the reference tracking algorithm

254

255

6. **Test File Inclusion**: Any changed files matching the `include` patterns cause their containing project to be marked as affected

256

257

7. **Implicit Dependencies**: Projects that declare implicit dependencies on affected projects are added to the affected set

258

259

8. **Lockfile Analysis** (experimental): If enabled and package-lock.json changed:

260

- Compares lockfile before and after to find changed dependencies

261

- Searches for imports of changed dependencies

262

- Marks projects importing changed dependencies as affected

263

264

## Error Handling

265

266

The library may throw errors in the following scenarios:

267

268

- **Git errors**: If the base branch doesn't exist or git commands fail, an error is thrown with message: `"Unable to get diff for base: \"{base}\". are you using the correct base?"`

269

- **File resolution errors**: If a file cannot be retrieved from a git revision, an error is thrown with message: `"Unable to get file \"{filePath}\" for base: \"{base}\". are you using the correct base?"`

270

271

## Integration with Monorepo Tools

272

273

@traf/core is designed as a reusable core library for integration with various monorepo tools. Companion packages provide tool-specific integrations:

274

275

- `@traf/nx` - Integration with Nx monorepo tool

276

- `@traf/turbo` - Integration with Turbo monorepo tool (future)

277

278

These packages handle tool-specific project configuration and provide convenient wrappers around the core functionality.

279