or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-lilconfig

A zero-dependency alternative to cosmiconfig for loading configuration files

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/lilconfig@3.1.x

To install, run

npx @tessl/cli install tessl/npm-lilconfig@3.1.0

0

# Lilconfig

1

2

Lilconfig is a zero-dependency alternative to cosmiconfig that provides configuration file discovery and loading functionality. It offers both synchronous and asynchronous APIs for searching and loading configuration files from common locations, supporting JavaScript, JSON, and custom file formats through configurable loaders.

3

4

## Package Information

5

6

- **Package Name**: lilconfig

7

- **Package Type**: npm

8

- **Language**: JavaScript with TypeScript definitions

9

- **Installation**: `npm install lilconfig`

10

11

## Core Imports

12

13

```javascript

14

import { lilconfig, lilconfigSync, defaultLoaders, defaultLoadersSync } from 'lilconfig';

15

```

16

17

For CommonJS:

18

19

```javascript

20

const { lilconfig, lilconfigSync, defaultLoaders, defaultLoadersSync } = require('lilconfig');

21

```

22

23

## Basic Usage

24

25

```javascript

26

import { lilconfig, lilconfigSync } from 'lilconfig';

27

28

// Async usage

29

const explorer = lilconfig('myapp');

30

const result = await explorer.search();

31

32

if (result) {

33

console.log('Config found at:', result.filepath);

34

console.log('Config contents:', result.config);

35

}

36

37

// Sync usage

38

const explorerSync = lilconfigSync('myapp');

39

const resultSync = explorerSync.search();

40

41

if (resultSync) {

42

console.log('Config found at:', resultSync.filepath);

43

console.log('Config contents:', resultSync.config);

44

}

45

```

46

47

## Architecture

48

49

Lilconfig is built around several key components:

50

51

- **Search Strategy**: Systematic file discovery from current directory upward to stop directory

52

- **Loader System**: Pluggable file loading mechanism supporting different formats (.js, .json, .cjs, .mjs)

53

- **Caching Layer**: Optional caching for both search and load operations to improve performance

54

- **Transform Pipeline**: Optional transformation of loaded configuration data

55

- **Package.json Integration**: Special handling for configuration stored in package.json files

56

57

## Capabilities

58

59

### Configuration Searching

60

61

Creates a configuration explorer that can search for configuration files in standard locations.

62

63

```javascript { .api }

64

/**

65

* Creates an async configuration explorer

66

* @param name - The configuration name to search for (e.g., 'myapp')

67

* @param options - Optional configuration options

68

* @returns AsyncSearcher instance with search and load methods

69

*/

70

function lilconfig(name: string, options?: Partial<Options>): AsyncSearcher;

71

72

/**

73

* Creates a sync configuration explorer

74

* @param name - The configuration name to search for (e.g., 'myapp')

75

* @param options - Optional configuration options

76

* @returns SyncSearcher instance with search and load methods

77

*/

78

function lilconfigSync(name: string, options?: OptionsSync): SyncSearcher;

79

```

80

81

**Default Search Places:**

82

83

For a configuration named `myapp`, lilconfig searches for files in this order:

84

85

```javascript

86

// Async version (lilconfig) searches for:

87

[

88

'package.json', // Looks for myapp property

89

'.myapprc.json',

90

'.myapprc.js',

91

'.myapprc.cjs',

92

'.myapprc.mjs', // Only in async mode

93

'.config/myapprc',

94

'.config/myapprc.json',

95

'.config/myapprc.js',

96

'.config/myapprc.cjs',

97

'.config/myapprc.mjs', // Only in async mode

98

'myapp.config.js',

99

'myapp.config.cjs',

100

'myapp.config.mjs' // Only in async mode

101

]

102

103

// Sync version (lilconfigSync) excludes .mjs files due to module loading limitations

104

```

105

106

**Usage Examples:**

107

108

```javascript

109

import { lilconfig, lilconfigSync } from 'lilconfig';

110

111

// Search for 'myapp' configuration files

112

const explorer = lilconfig('myapp');

113

const result = await explorer.search('/some/start/path');

114

115

// Search with custom options

116

const explorerWithOptions = lilconfig('myapp', {

117

searchPlaces: ['package.json', '.myapprc.js', 'myapp.config.js'],

118

stopDir: '/home/user',

119

ignoreEmptySearchPlaces: false

120

});

121

122

const customResult = await explorerWithOptions.search();

123

```

124

125

### Async Searcher Interface

126

127

The object returned by `lilconfig()` providing async search and load capabilities.

128

129

```javascript { .api }

130

interface AsyncSearcher {

131

/**

132

* Search for configuration files starting from specified directory

133

* @param searchFrom - Directory to start searching from (defaults to process.cwd())

134

* @returns Promise resolving to LilconfigResult or null if not found

135

*/

136

search(searchFrom?: string): Promise<LilconfigResult>;

137

138

/**

139

* Load configuration from a specific file path

140

* @param filepath - Path to configuration file to load

141

* @returns Promise resolving to LilconfigResult

142

*/

143

load(filepath: string): Promise<LilconfigResult>;

144

145

/** Clear the load cache */

146

clearLoadCache(): void;

147

148

/** Clear the search cache */

149

clearSearchCache(): void;

150

151

/** Clear both load and search caches */

152

clearCaches(): void;

153

}

154

```

155

156

### Sync Searcher Interface

157

158

The object returned by `lilconfigSync()` providing synchronous search and load capabilities.

159

160

```javascript { .api }

161

interface SyncSearcher {

162

/**

163

* Search for configuration files starting from specified directory

164

* @param searchFrom - Directory to start searching from (defaults to process.cwd())

165

* @returns LilconfigResult or null if not found

166

*/

167

search(searchFrom?: string): LilconfigResult;

168

169

/**

170

* Load configuration from a specific file path

171

* @param filepath - Path to configuration file to load

172

* @returns LilconfigResult

173

*/

174

load(filepath: string): LilconfigResult;

175

176

/** Clear the load cache */

177

clearLoadCache(): void;

178

179

/** Clear the search cache */

180

clearSearchCache(): void;

181

182

/** Clear both load and search caches */

183

clearCaches(): void;

184

}

185

```

186

187

### Default Loaders

188

189

Pre-configured loaders for common file types.

190

191

```javascript { .api }

192

/** Default async loaders supporting .js, .mjs, .cjs, .json files and files with no extension */

193

const defaultLoaders: Loaders;

194

195

/** Default sync loaders supporting .js, .json, .cjs files and files with no extension (no .mjs support) */

196

const defaultLoadersSync: LoadersSync;

197

```

198

199

**Loader Resolution:**

200

- File extensions are mapped to loaders (e.g., `.js` → JavaScript loader, `.json` → JSON parser)

201

- Files without extensions use the special `noExt` loader key

202

- Default `noExt` loader treats files as JSON

203

- Custom loaders can override any extension or the `noExt` behavior

204

205

**Usage Example:**

206

207

```javascript

208

import { lilconfig, defaultLoaders } from 'lilconfig';

209

210

// Extend default loaders with custom loader

211

const explorer = lilconfig('myapp', {

212

loaders: {

213

...defaultLoaders,

214

'.yaml': (filepath, content) => require('yaml').parse(content)

215

}

216

});

217

```

218

219

### Custom Configuration Options

220

221

Configuration options for customizing search behavior and file processing.

222

223

```javascript { .api }

224

interface Options {

225

/** Custom loaders for different file extensions */

226

loaders?: Loaders;

227

/** Transform function to modify loaded configuration */

228

transform?: Transform;

229

/** Enable/disable caching (default: true) */

230

cache?: boolean;

231

/** Directory to stop searching at (default: os.homedir()) */

232

stopDir?: string;

233

/** Custom list of places to search for config files */

234

searchPlaces?: string[];

235

/** Whether to ignore empty config files (default: true) */

236

ignoreEmptySearchPlaces?: boolean;

237

/** Property name(s) to extract from package.json (default: [name]) */

238

packageProp?: string | string[];

239

}

240

241

interface OptionsSync {

242

/** Custom sync loaders for different file extensions */

243

loaders?: LoadersSync;

244

/** Sync transform function to modify loaded configuration */

245

transform?: TransformSync;

246

/** Enable/disable caching (default: true) */

247

cache?: boolean;

248

/** Directory to stop searching at (default: os.homedir()) */

249

stopDir?: string;

250

/** Custom list of places to search for config files */

251

searchPlaces?: string[];

252

/** Whether to ignore empty config files (default: true) */

253

ignoreEmptySearchPlaces?: boolean;

254

/** Property name(s) to extract from package.json (default: [name]) */

255

packageProp?: string | string[];

256

}

257

```

258

259

**Option Details:**

260

261

- **packageProp**: When searching `package.json`, extracts configuration from the specified property. Can be a string (`'myapp'`) or nested path (`['config', 'myapp']`). Defaults to the configuration name.

262

- **transform**: Function called on all results (including `null` when no config found). Useful for adding defaults or metadata to loaded configurations.

263

- **searchPlaces**: Overrides the default search places entirely. When not provided, uses the default search places based on the configuration name.

264

265

**Usage Example:**

266

267

```javascript

268

import { lilconfig } from 'lilconfig';

269

import os from 'os';

270

271

const explorer = lilconfig('myapp', {

272

stopDir: os.homedir(),

273

searchPlaces: [

274

'package.json',

275

'.myapprc.json',

276

'.myapprc.js',

277

'myapp.config.js'

278

],

279

ignoreEmptySearchPlaces: false,

280

packageProp: ['myapp', 'config'],

281

cache: true,

282

transform: (result) => {

283

if (result && result.config) {

284

// Add metadata to config

285

return {

286

...result,

287

config: {

288

...result.config,

289

_loadedFrom: result.filepath

290

}

291

};

292

}

293

return result;

294

}

295

});

296

```

297

298

## Types

299

300

```javascript { .api }

301

/** Result object returned by search and load operations */

302

type LilconfigResult = null | {

303

/** Path to the configuration file that was found/loaded */

304

filepath: string;

305

/** The loaded configuration data */

306

config: any;

307

/** Whether the configuration file was empty */

308

isEmpty?: boolean;

309

};

310

311

/** Sync loader function for processing file content */

312

type LoaderSync = (filepath: string, content: string) => any;

313

314

/** Async loader function for processing file content */

315

type Loader = LoaderSync | ((filepath: string, content: string) => Promise<any>);

316

317

/** Map of file extensions to sync loaders */

318

type LoadersSync = Record<string, LoaderSync>;

319

320

/** Map of file extensions to async loaders */

321

type Loaders = Record<string, Loader>;

322

323

/** Sync transform function for modifying loaded configuration */

324

type TransformSync = (result: LilconfigResult) => LilconfigResult;

325

326

/** Transform function for modifying loaded configuration */

327

type Transform = TransformSync | ((result: LilconfigResult) => Promise<LilconfigResult>);

328

```

329

330

## Advanced Usage

331

332

### Custom Loaders

333

334

```javascript

335

import { lilconfig } from 'lilconfig';

336

import yaml from 'yaml';

337

338

// YAML loader example

339

function yamlLoader(filepath, content) {

340

return yaml.parse(content);

341

}

342

343

const explorer = lilconfig('myapp', {

344

loaders: {

345

'.yaml': yamlLoader,

346

'.yml': yamlLoader,

347

// Override default behavior for files with no extension

348

noExt: yamlLoader

349

}

350

});

351

```

352

353

### Transform Configuration

354

355

```javascript

356

import { lilconfig } from 'lilconfig';

357

358

const explorer = lilconfig('myapp', {

359

transform: (result) => {

360

if (!result) return result;

361

362

// Add default values

363

return {

364

...result,

365

config: {

366

timeout: 5000,

367

retries: 3,

368

...result.config

369

}

370

};

371

}

372

});

373

```

374

375

### Package.json Configuration

376

377

```javascript

378

import { lilconfig } from 'lilconfig';

379

380

// Extract nested configuration from package.json

381

const explorer = lilconfig('myapp', {

382

packageProp: ['config', 'myapp'] // Looks for package.json.config.myapp

383

});

384

385

// Extract from array of possible properties

386

const explorerMulti = lilconfig('myapp', {

387

packageProp: ['myapp', 'myappConfig'] // Tries myapp first, then myappConfig

388

});

389

```

390

391

## Error Handling

392

393

lilconfig throws specific errors in the following cases:

394

395

- **Missing loader**: `Error('Missing loader for extension "<extension>"')` when no loader is configured for a file extension

396

- **Invalid loader**: `Error('Loader for extension "<extension>" is not a function: Received <type>.')` when a loader is not a function

397

- **Empty filepath**: `Error('load must pass a non-empty string')` when load() is called with empty filepath

398

- **Loader validation**: `Error('No loader specified for extension "<ext>"')` when trying to load a file without a configured loader

399

400

```javascript

401

import { lilconfig } from 'lilconfig';

402

403

try {

404

const explorer = lilconfig('myapp');

405

const result = await explorer.load('');

406

} catch (error) {

407

console.error('Error:', error.message); // "load must pass a non-empty string"

408

}

409

```