or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Resolve.exports

1

2

Resolve.exports is a tiny (952b), correct, general-purpose, and configurable "exports" and "imports" resolver for Node.js package.json fields without file-system reliance. It provides spec-compliant resolution of module paths based on conditional exports, supporting both CommonJS and ES modules.

3

4

## Package Information

5

6

- **Package Name**: resolve.exports

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install resolve.exports`

10

11

## Core Imports

12

13

```typescript

14

import { resolve, exports, imports, legacy } from "resolve.exports";

15

```

16

17

For CommonJS:

18

19

```javascript

20

const { resolve, exports, imports, legacy } = require("resolve.exports");

21

```

22

23

## Basic Usage

24

25

```typescript

26

import { resolve, exports } from "resolve.exports";

27

28

// Example package.json-like object

29

const pkg = {

30

name: "my-package",

31

exports: {

32

".": {

33

"import": "./dist/index.mjs",

34

"require": "./dist/index.js"

35

},

36

"./utils": {

37

"import": "./dist/utils.mjs",

38

"require": "./dist/utils.js"

39

}

40

}

41

};

42

43

// Resolve main entry point for ES modules

44

const result = resolve(pkg, ".", { require: false });

45

console.log(result); // ["./dist/index.mjs"]

46

47

// Resolve specific export for CommonJS

48

const utilsResult = exports(pkg, "./utils", { require: true });

49

console.log(utilsResult); // ["./dist/utils.js"]

50

```

51

52

## Capabilities

53

54

### Main Resolution Function

55

56

The primary entry point that automatically routes to exports() or imports() based on the entry value.

57

58

```typescript { .api }

59

/**

60

* Convenience helper that automatically routes to exports() or imports() based on input value

61

* @param pkg - Package.json-like object containing exports/imports

62

* @param input - Target entry identifier (defaults to ".")

63

* @param options - Resolution options

64

* @returns Array of resolved paths or void if no match

65

*/

66

function resolve<T = Package>(

67

pkg: T,

68

input?: string,

69

options?: Options

70

): Imports.Output | Exports.Output | void;

71

```

72

73

### Exports Resolution

74

75

Resolves package.json "exports" field mappings according to Node.js specification.

76

77

```typescript { .api }

78

/**

79

* Resolves package.json "exports" field mappings

80

* @param pkg - Package.json-like object containing exports

81

* @param input - Export specifier to resolve (defaults to ".")

82

* @param options - Resolution options

83

* @returns Array of resolved paths or void if no match

84

* @throws Error if entry not found or no matching conditions

85

*/

86

function exports<T = Package>(

87

pkg: T,

88

input?: string,

89

options?: Options

90

): Exports.Output | void;

91

```

92

93

**Usage Example:**

94

95

```typescript

96

const pkg = {

97

name: "example",

98

exports: {

99

".": {

100

"node": "./dist/node.js",

101

"browser": "./dist/browser.js",

102

"default": "./dist/index.js"

103

},

104

"./feature": "./dist/feature.js"

105

}

106

};

107

108

// Resolve for browser environment

109

const browserPath = exports(pkg, ".", { browser: true });

110

console.log(browserPath); // ["./dist/browser.js"]

111

112

// Resolve specific feature

113

const featurePath = exports(pkg, "./feature");

114

console.log(featurePath); // ["./dist/feature.js"]

115

```

116

117

### Imports Resolution

118

119

Resolves package.json "imports" field mappings for internal package imports starting with "#".

120

121

```typescript { .api }

122

/**

123

* Resolves package.json "imports" field mappings

124

* @param pkg - Package.json-like object containing imports

125

* @param input - Import specifier (must start with "#")

126

* @param options - Resolution options

127

* @returns Array of resolved paths or void if no match

128

* @throws Error if target not found or no matching conditions

129

*/

130

function imports<T = Package>(

131

pkg: T,

132

input: string,

133

options?: Options

134

): Imports.Output | void;

135

```

136

137

**Usage Example:**

138

139

```typescript

140

const pkg = {

141

name: "example",

142

imports: {

143

"#utils": {

144

"node": "./src/utils-node.js",

145

"browser": "./src/utils-browser.js"

146

},

147

"#config/*": "./config/*.json"

148

}

149

};

150

151

// Resolve internal import

152

const utilsPath = imports(pkg, "#utils", { browser: true });

153

console.log(utilsPath); // ["./src/utils-browser.js"]

154

155

// Resolve wildcard import

156

const configPath = imports(pkg, "#config/database");

157

console.log(configPath); // ["./config/database.json"]

158

```

159

160

### Legacy Resolution

161

162

Resolves legacy package.json fields ("main", "module", "browser") as fallback when exports are not available.

163

164

```typescript { .api }

165

/**

166

* Resolves legacy package.json fields (main, module, browser) as fallback

167

*/

168

function legacy<T = Package>(

169

pkg: T,

170

options: { browser: true; fields?: readonly string[] }

171

): Browser | void;

172

173

function legacy<T = Package>(

174

pkg: T,

175

options: { browser: string; fields?: readonly string[] }

176

): string | false | void;

177

178

function legacy<T = Package>(

179

pkg: T,

180

options: { browser: false; fields?: readonly string[] }

181

): string | void;

182

183

function legacy<T = Package>(

184

pkg: T,

185

options?: {

186

browser?: boolean | string;

187

fields?: readonly string[];

188

}

189

): Browser | string;

190

```

191

192

**Usage Example:**

193

194

```typescript

195

const pkg = {

196

name: "legacy-package",

197

main: "./lib/index.js",

198

module: "./lib/index.mjs",

199

browser: "./lib/browser.js"

200

};

201

202

// Get main entry for Node.js

203

const nodeEntry = legacy(pkg, { browser: false });

204

console.log(nodeEntry); // "./lib/index.js"

205

206

// Get browser entry

207

const browserEntry = legacy(pkg, { browser: true });

208

console.log(browserEntry); // "./lib/browser.js"

209

210

// Custom field priority

211

const customEntry = legacy(pkg, {

212

browser: false,

213

fields: ["module", "main"]

214

});

215

console.log(customEntry); // "./lib/index.mjs"

216

```

217

218

## Types

219

220

### Options Interface

221

222

Configuration options for resolution behavior.

223

224

```typescript { .api }

225

interface Options {

226

/**

227

* When true, adds the "browser" conditions.

228

* Otherwise the "node" condition is enabled.

229

* @default false

230

*/

231

browser?: boolean;

232

233

/**

234

* Any custom conditions to match.

235

* @note Array order does not matter. Priority is determined by the key-order of conditions defined within a package's imports/exports mapping.

236

* @default []

237

*/

238

conditions?: readonly string[];

239

240

/**

241

* When true, adds the "require" condition.

242

* Otherwise the "import" condition is enabled.

243

* @default false

244

*/

245

require?: boolean;

246

247

/**

248

* Prevents "require", "import", "browser", and/or "node" conditions from being added automatically.

249

* When enabled, only `options.conditions` are added alongside the "default" condition.

250

* @important Enabling this deviates from Node.js default behavior.

251

* @default false

252

*/

253

unsafe?: boolean;

254

}

255

```

256

257

### Package Interface

258

259

Represents a package.json structure for resolution.

260

261

```typescript { .api }

262

interface Package {

263

name: string;

264

version?: string;

265

module?: string;

266

main?: string;

267

imports?: Imports;

268

exports?: Exports;

269

browser?: Browser;

270

[key: string]: any;

271

}

272

```

273

274

### Exports Types

275

276

Export mapping type definitions.

277

278

```typescript { .api }

279

type Exports = Path | {

280

[path: Exports.Entry]: Exports.Value;

281

[cond: Condition]: Exports.Value;

282

};

283

284

namespace Exports {

285

/** Allows "." and "./{name}" */

286

type Entry = `.${string}`;

287

288

/** strings must be internal paths */

289

type Value = Path | null | {

290

[c: Condition]: Value;

291

} | Value[];

292

293

type Output = Path[];

294

}

295

```

296

297

### Imports Types

298

299

Import mapping type definitions.

300

301

```typescript { .api }

302

type Imports = {

303

[entry: Imports.Entry]: Imports.Value;

304

};

305

306

namespace Imports {

307

type Entry = `#${string}`;

308

309

/** External dependency name (not an internal path) */

310

type External = string;

311

312

/** strings are dependency names OR internal paths */

313

type Value = External | Path | null | {

314

[c: Condition]: Value;

315

} | Value[];

316

317

type Output = Array<External | Path>;

318

}

319

```

320

321

### Common Types

322

323

Basic type definitions used throughout the API.

324

325

```typescript { .api }

326

/**

327

* A resolve condition

328

* @example "node", "default", "production"

329

*/

330

type Condition = string;

331

332

/** An internal file path */

333

type Path = `./${string}`;

334

335

type Browser = string[] | string | {

336

[file: Path | string]: string | false;

337

};

338

```

339

340

## Error Handling

341

342

The package throws `Error` instances with specific message formats for resolution failures:

343

344

- `Missing "{entry}" specifier in "{name}" package` - when the requested entry/target is not found in the package's exports/imports

345

- `No known conditions for "{entry}" specifier in "{name}" package` - when no matching conditions are found for the entry

346

347

```typescript

348

try {

349

const result = exports(pkg, "./nonexistent");

350

} catch (error) {

351

console.error(error.message); // Missing "./nonexistent" specifier in "my-package" package

352

}

353

```

354

355

## Advanced Usage

356

357

### Custom Conditions

358

359

```typescript

360

const pkg = {

361

name: "my-package",

362

exports: {

363

".": {

364

"development": "./src/index.js",

365

"production": "./dist/index.js",

366

"default": "./lib/index.js"

367

}

368

}

369

};

370

371

// Resolve with custom condition

372

const devPath = resolve(pkg, ".", {

373

conditions: ["development"],

374

unsafe: true // Only use custom conditions

375

});

376

console.log(devPath); // ["./src/index.js"]

377

```

378

379

### Complex Conditional Exports

380

381

```typescript

382

const pkg = {

383

name: "universal-package",

384

exports: {

385

".": {

386

"import": {

387

"browser": "./dist/browser.mjs",

388

"node": "./dist/node.mjs"

389

},

390

"require": {

391

"browser": "./dist/browser.js",

392

"node": "./dist/node.js"

393

}

394

}

395

}

396

};

397

398

// Browser + ES modules

399

const browserESM = resolve(pkg, ".", { browser: true, require: false });

400

console.log(browserESM); // ["./dist/browser.mjs"]

401

402

// Node.js + CommonJS

403

const nodeCJS = resolve(pkg, ".", { browser: false, require: true });

404

console.log(nodeCJS); // ["./dist/node.js"]

405

```