Add <%br= %> jqhtml syntax docs, class override detection, npm update

Document event handler placement and model fetch clarification

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2026-01-15 10:16:06 +00:00
parent 61f8f058f2
commit 1594502cb2
791 changed files with 7044 additions and 6089 deletions

View File

@@ -1,38 +0,0 @@
export declare type LilconfigResult = null | {
filepath: string;
config: any;
isEmpty?: boolean;
};
interface OptionsBase {
stopDir?: string;
searchPlaces?: string[];
ignoreEmptySearchPlaces?: boolean;
packageProp?: string | string[];
}
export declare type Transform = TransformSync | ((result: LilconfigResult) => Promise<LilconfigResult>);
export declare type TransformSync = (result: LilconfigResult) => LilconfigResult;
declare type LoaderResult = any;
export declare type LoaderSync = (filepath: string, content: string) => LoaderResult;
export declare type Loader = LoaderSync | ((filepath: string, content: string) => Promise<LoaderResult>);
export declare type Loaders = Record<string, Loader>;
export declare type LoadersSync = Record<string, LoaderSync>;
export interface Options extends OptionsBase {
loaders?: Loaders;
transform?: Transform;
}
export interface OptionsSync extends OptionsBase {
loaders?: LoadersSync;
transform?: TransformSync;
}
export declare const defaultLoaders: LoadersSync;
declare type AsyncSearcher = {
search(searchFrom?: string): Promise<LilconfigResult>;
load(filepath: string): Promise<LilconfigResult>;
};
export declare function lilconfig(name: string, options?: Partial<Options>): AsyncSearcher;
declare type SyncSearcher = {
search(searchFrom?: string): LilconfigResult;
load(filepath: string): LilconfigResult;
};
export declare function lilconfigSync(name: string, options?: OptionsSync): SyncSearcher;
export {};

251
node_modules/lilconfig/dist/index.js generated vendored
View File

@@ -1,251 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.lilconfigSync = exports.lilconfig = exports.defaultLoaders = void 0;
const path = require("path");
const fs = require("fs");
const os = require("os");
const fsReadFileAsync = fs.promises.readFile;
function getDefaultSearchPlaces(name) {
return [
'package.json',
`.${name}rc.json`,
`.${name}rc.js`,
`.${name}rc.cjs`,
`.config/${name}rc`,
`.config/${name}rc.json`,
`.config/${name}rc.js`,
`.config/${name}rc.cjs`,
`${name}.config.js`,
`${name}.config.cjs`,
];
}
function getSearchPaths(startDir, stopDir) {
return startDir
.split(path.sep)
.reduceRight((acc, _, ind, arr) => {
const currentPath = arr.slice(0, ind + 1).join(path.sep);
if (!acc.passedStopDir)
acc.searchPlaces.push(currentPath || path.sep);
if (currentPath === stopDir)
acc.passedStopDir = true;
return acc;
}, { searchPlaces: [], passedStopDir: false }).searchPlaces;
}
exports.defaultLoaders = Object.freeze({
'.js': require,
'.json': require,
'.cjs': require,
noExt(_, content) {
return JSON.parse(content);
},
});
function getExtDesc(ext) {
return ext === 'noExt' ? 'files without extensions' : `extension "${ext}"`;
}
function getOptions(name, options = {}) {
const conf = {
stopDir: os.homedir(),
searchPlaces: getDefaultSearchPlaces(name),
ignoreEmptySearchPlaces: true,
transform: (x) => x,
packageProp: [name],
...options,
loaders: { ...exports.defaultLoaders, ...options.loaders },
};
conf.searchPlaces.forEach(place => {
const key = path.extname(place) || 'noExt';
const loader = conf.loaders[key];
if (!loader) {
throw new Error(`No loader specified for ${getExtDesc(key)}, so searchPlaces item "${place}" is invalid`);
}
if (typeof loader !== 'function') {
throw new Error(`loader for ${getExtDesc(key)} is not a function (type provided: "${typeof loader}"), so searchPlaces item "${place}" is invalid`);
}
});
return conf;
}
function getPackageProp(props, obj) {
if (typeof props === 'string' && props in obj)
return obj[props];
return ((Array.isArray(props) ? props : props.split('.')).reduce((acc, prop) => (acc === undefined ? acc : acc[prop]), obj) || null);
}
function getSearchItems(searchPlaces, searchPaths) {
return searchPaths.reduce((acc, searchPath) => {
searchPlaces.forEach(sp => acc.push({
searchPlace: sp,
filepath: path.join(searchPath, sp),
loaderKey: path.extname(sp) || 'noExt',
}));
return acc;
}, []);
}
function validateFilePath(filepath) {
if (!filepath)
throw new Error('load must pass a non-empty string');
}
function validateLoader(loader, ext) {
if (!loader)
throw new Error(`No loader specified for extension "${ext}"`);
if (typeof loader !== 'function')
throw new Error('loader is not a function');
}
function lilconfig(name, options) {
const { ignoreEmptySearchPlaces, loaders, packageProp, searchPlaces, stopDir, transform, } = getOptions(name, options);
return {
async search(searchFrom = process.cwd()) {
const searchPaths = getSearchPaths(searchFrom, stopDir);
const result = {
config: null,
filepath: '',
};
const searchItems = getSearchItems(searchPlaces, searchPaths);
for (const { searchPlace, filepath, loaderKey } of searchItems) {
try {
await fs.promises.access(filepath);
}
catch (_a) {
continue;
}
const content = String(await fsReadFileAsync(filepath));
const loader = loaders[loaderKey];
if (searchPlace === 'package.json') {
const pkg = await loader(filepath, content);
const maybeConfig = getPackageProp(packageProp, pkg);
if (maybeConfig != null) {
result.config = maybeConfig;
result.filepath = filepath;
break;
}
continue;
}
const isEmpty = content.trim() === '';
if (isEmpty && ignoreEmptySearchPlaces)
continue;
if (isEmpty) {
result.isEmpty = true;
result.config = undefined;
}
else {
validateLoader(loader, loaderKey);
result.config = await loader(filepath, content);
}
result.filepath = filepath;
break;
}
if (result.filepath === '' && result.config === null)
return transform(null);
return transform(result);
},
async load(filepath) {
validateFilePath(filepath);
const absPath = path.resolve(process.cwd(), filepath);
const { base, ext } = path.parse(absPath);
const loaderKey = ext || 'noExt';
const loader = loaders[loaderKey];
validateLoader(loader, loaderKey);
const content = String(await fsReadFileAsync(absPath));
if (base === 'package.json') {
const pkg = await loader(absPath, content);
return transform({
config: getPackageProp(packageProp, pkg),
filepath: absPath,
});
}
const result = {
config: null,
filepath: absPath,
};
const isEmpty = content.trim() === '';
if (isEmpty && ignoreEmptySearchPlaces)
return transform({
config: undefined,
filepath: absPath,
isEmpty: true,
});
result.config = isEmpty
? undefined
: await loader(absPath, content);
return transform(isEmpty ? { ...result, isEmpty, config: undefined } : result);
},
};
}
exports.lilconfig = lilconfig;
function lilconfigSync(name, options) {
const { ignoreEmptySearchPlaces, loaders, packageProp, searchPlaces, stopDir, transform, } = getOptions(name, options);
return {
search(searchFrom = process.cwd()) {
const searchPaths = getSearchPaths(searchFrom, stopDir);
const result = {
config: null,
filepath: '',
};
const searchItems = getSearchItems(searchPlaces, searchPaths);
for (const { searchPlace, filepath, loaderKey } of searchItems) {
try {
fs.accessSync(filepath);
}
catch (_a) {
continue;
}
const loader = loaders[loaderKey];
const content = String(fs.readFileSync(filepath));
if (searchPlace === 'package.json') {
const pkg = loader(filepath, content);
const maybeConfig = getPackageProp(packageProp, pkg);
if (maybeConfig != null) {
result.config = maybeConfig;
result.filepath = filepath;
break;
}
continue;
}
const isEmpty = content.trim() === '';
if (isEmpty && ignoreEmptySearchPlaces)
continue;
if (isEmpty) {
result.isEmpty = true;
result.config = undefined;
}
else {
validateLoader(loader, loaderKey);
result.config = loader(filepath, content);
}
result.filepath = filepath;
break;
}
if (result.filepath === '' && result.config === null)
return transform(null);
return transform(result);
},
load(filepath) {
validateFilePath(filepath);
const absPath = path.resolve(process.cwd(), filepath);
const { base, ext } = path.parse(absPath);
const loaderKey = ext || 'noExt';
const loader = loaders[loaderKey];
validateLoader(loader, loaderKey);
const content = String(fs.readFileSync(absPath));
if (base === 'package.json') {
const pkg = loader(absPath, content);
return transform({
config: getPackageProp(packageProp, pkg),
filepath: absPath,
});
}
const result = {
config: null,
filepath: absPath,
};
const isEmpty = content.trim() === '';
if (isEmpty && ignoreEmptySearchPlaces)
return transform({
filepath: absPath,
config: undefined,
isEmpty: true,
});
result.config = isEmpty ? undefined : loader(absPath, content);
return transform(isEmpty ? { ...result, isEmpty, config: undefined } : result);
},
};
}
exports.lilconfigSync = lilconfigSync;

86
node_modules/lilconfig/package.json generated vendored
View File

@@ -1,48 +1,42 @@
{
"name": "lilconfig",
"version": "2.1.0",
"description": "A zero-dependency alternative to cosmiconfig",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"prebuild": "npm run clean",
"build": "tsc --declaration",
"postbuild": "du -h ./dist/*",
"clean": "rm -rf ./dist",
"test": "jest --coverage",
"lint": "eslint ./src/*.ts"
},
"keywords": [
"cosmiconfig",
"config",
"configuration",
"search"
],
"files": [
"dist/*"
],
"repository": {
"type": "git",
"url": "https://github.com/antonk52/lilconfig"
},
"bugs": "https://github.com/antonk52/lilconfig/issues",
"author": "antonk52",
"license": "MIT",
"devDependencies": {
"@types/jest": "^27.0.2",
"@types/node": "^14.18.36",
"@typescript-eslint/eslint-plugin": "^5.54.0",
"@typescript-eslint/parser": "^5.54.0",
"cosmiconfig": "^7.1.0",
"eslint": "^8.35.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^27.3.1",
"prettier": "^2.8.4",
"ts-jest": "27.0.7",
"typescript": "4.4.4"
},
"engines": {
"node": ">=10"
}
"name": "lilconfig",
"version": "3.1.3",
"description": "A zero-dependency alternative to cosmiconfig",
"main": "src/index.js",
"types": "src/index.d.ts",
"scripts": {
"test": "NODE_OPTIONS=--experimental-vm-modules ./node_modules/.bin/jest --coverage",
"lint": "biome ci ./src",
"types": "tsc"
},
"keywords": [
"cosmiconfig",
"config",
"configuration",
"search"
],
"files": [
"src/index.*"
],
"repository": {
"type": "git",
"url": "https://github.com/antonk52/lilconfig"
},
"bugs": "https://github.com/antonk52/lilconfig/issues",
"author": "antonk52",
"license": "MIT",
"devDependencies": {
"@biomejs/biome": "^1.6.0",
"@types/jest": "^29.5.12",
"@types/node": "^14.18.63",
"@types/webpack-env": "^1.18.5",
"cosmiconfig": "^8.3.6",
"jest": "^29.7.0",
"typescript": "^5.3.3",
"uvu": "^0.5.6"
},
"funding": "https://github.com/sponsors/antonk52",
"engines": {
"node": ">=14"
}
}

34
node_modules/lilconfig/readme.md generated vendored
View File

@@ -42,16 +42,18 @@ lilconfigSync(
*/
```
## ESM
ESM configs can be loaded with **async API only**. Specifically `js` files in projects with `"type": "module"` in `package.json` or `mjs` files.
## Difference to `cosmiconfig`
Lilconfig does not intend to be 100% compatible with `cosmiconfig` but tries to mimic it where possible. The key differences are:
- **no** support for yaml files out of the box(`lilconfig` attempts to parse files with no extension as JSON instead of YAML). You can still add the support for YAML files by providing a loader, see an [example](#yaml-loader) below.
- **no** cache
Lilconfig does not intend to be 100% compatible with `cosmiconfig` but tries to mimic it where possible. The key difference is **no** support for yaml files out of the box(`lilconfig` attempts to parse files with no extension as JSON instead of YAML). You can still add the support for YAML files by providing a loader, see an [example](#yaml-loader) below.
### Options difference between the two.
|cosmiconfig option | lilconfig |
|------------------------|-----------|
|cache | |
|cache | |
|loaders | ✅ |
|ignoreEmptySearchPlaces | ✅ |
|packageProp | ✅ |
@@ -89,30 +91,8 @@ lilconfig('myapp', options)
});
```
### ESM loader
Lilconfig v2 does not support ESM modules out of the box. However, you can support it with a custom a loader. Note that this will only work with the async `lilconfig` function and won't work with the sync `lilconfigSync`.
```js
import {lilconfig} from 'lilconfig';
const loadEsm = filepath => import(filepath);
lilconfig('myapp', {
loaders: {
'.js': loadEsm,
'.mjs': loadEsm,
}
})
.search()
.then(result => {
result // {config, filepath}
result.config.default // if config uses `export default`
});
```
## Version correlation
- lilconig v1 → cosmiconfig v6
- lilconig v2 → cosmiconfig v7
- lilconig v3 → cosmiconfig v8

54
node_modules/lilconfig/src/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,54 @@
export type LilconfigResult = null | {
filepath: string;
config: any;
isEmpty?: boolean;
};
interface OptionsBase {
cache?: boolean;
stopDir?: string;
searchPlaces?: string[];
ignoreEmptySearchPlaces?: boolean;
packageProp?: string | string[];
}
export type Transform =
| TransformSync
| ((result: LilconfigResult) => Promise<LilconfigResult>);
export type TransformSync = (result: LilconfigResult) => LilconfigResult;
type LoaderResult = any;
export type LoaderSync = (filepath: string, content: string) => LoaderResult;
export type Loader =
| LoaderSync
| ((filepath: string, content: string) => Promise<LoaderResult>);
export type Loaders = Record<string, Loader>;
export type LoadersSync = Record<string, LoaderSync>;
export interface Options extends OptionsBase {
loaders?: Loaders;
transform?: Transform;
}
export interface OptionsSync extends OptionsBase {
loaders?: LoadersSync;
transform?: TransformSync;
}
export declare const defaultLoadersSync: LoadersSync;
export declare const defaultLoaders: Loaders;
type ClearCaches = {
clearLoadCache: () => void;
clearSearchCache: () => void;
clearCaches: () => void;
};
type AsyncSearcher = {
search(searchFrom?: string): Promise<LilconfigResult>;
load(filepath: string): Promise<LilconfigResult>;
} & ClearCaches;
export declare function lilconfig(
name: string,
options?: Partial<Options>,
): AsyncSearcher;
type SyncSearcher = {
search(searchFrom?: string): LilconfigResult;
load(filepath: string): LilconfigResult;
} & ClearCaches;
export declare function lilconfigSync(
name: string,
options?: OptionsSync,
): SyncSearcher;

460
node_modules/lilconfig/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,460 @@
// @ts-check
const path = require('path');
const fs = require('fs');
const os = require('os');
const url = require('url');
const fsReadFileAsync = fs.promises.readFile;
/** @type {(name: string, sync: boolean) => string[]} */
function getDefaultSearchPlaces(name, sync) {
return [
'package.json',
`.${name}rc.json`,
`.${name}rc.js`,
`.${name}rc.cjs`,
...(sync ? [] : [`.${name}rc.mjs`]),
`.config/${name}rc`,
`.config/${name}rc.json`,
`.config/${name}rc.js`,
`.config/${name}rc.cjs`,
...(sync ? [] : [`.config/${name}rc.mjs`]),
`${name}.config.js`,
`${name}.config.cjs`,
...(sync ? [] : [`${name}.config.mjs`]),
];
}
/**
* @type {(p: string) => string}
*
* see #17
* On *nix, if cwd is not under homedir,
* the last path will be '', ('/build' -> '')
* but it should be '/' actually.
* And on Windows, this will never happen. ('C:\build' -> 'C:')
*/
function parentDir(p) {
return path.dirname(p) || path.sep;
}
/** @type {import('./index').LoaderSync} */
const jsonLoader = (_, content) => JSON.parse(content);
// Use plain require in webpack context for dynamic import
const requireFunc =
typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require;
/** @type {import('./index').LoadersSync} */
const defaultLoadersSync = Object.freeze({
'.js': requireFunc,
'.json': requireFunc,
'.cjs': requireFunc,
noExt: jsonLoader,
});
module.exports.defaultLoadersSync = defaultLoadersSync;
/** @type {import('./index').Loader} */
const dynamicImport = async id => {
try {
const fileUrl = url.pathToFileURL(id).href;
const mod = await import(/* webpackIgnore: true */ fileUrl);
return mod.default;
} catch (e) {
try {
return requireFunc(id);
} catch (/** @type {any} */ requireE) {
if (
requireE.code === 'ERR_REQUIRE_ESM' ||
(requireE instanceof SyntaxError &&
requireE
.toString()
.includes('Cannot use import statement outside a module'))
) {
throw e;
}
throw requireE;
}
}
};
/** @type {import('./index').Loaders} */
const defaultLoaders = Object.freeze({
'.js': dynamicImport,
'.mjs': dynamicImport,
'.cjs': dynamicImport,
'.json': jsonLoader,
noExt: jsonLoader,
});
module.exports.defaultLoaders = defaultLoaders;
/**
* @param {string} name
* @param {import('./index').Options | import('./index').OptionsSync} options
* @param {boolean} sync
* @returns {Required<import('./index').Options | import('./index').OptionsSync>}
*/
function getOptions(name, options, sync) {
/** @type {Required<import('./index').Options>} */
const conf = {
stopDir: os.homedir(),
searchPlaces: getDefaultSearchPlaces(name, sync),
ignoreEmptySearchPlaces: true,
cache: true,
transform: x => x,
packageProp: [name],
...options,
loaders: {
...(sync ? defaultLoadersSync : defaultLoaders),
...options.loaders,
},
};
conf.searchPlaces.forEach(place => {
const key = path.extname(place) || 'noExt';
const loader = conf.loaders[key];
if (!loader) {
throw new Error(`Missing loader for extension "${place}"`);
}
if (typeof loader !== 'function') {
throw new Error(
`Loader for extension "${place}" is not a function: Received ${typeof loader}.`,
);
}
});
return conf;
}
/** @type {(props: string | string[], obj: Record<string, any>) => unknown} */
function getPackageProp(props, obj) {
if (typeof props === 'string' && props in obj) return obj[props];
return (
(Array.isArray(props) ? props : props.split('.')).reduce(
(acc, prop) => (acc === undefined ? acc : acc[prop]),
obj,
) || null
);
}
/** @param {string} filepath */
function validateFilePath(filepath) {
if (!filepath) throw new Error('load must pass a non-empty string');
}
/** @type {(loader: import('./index').Loader, ext: string) => void} */
function validateLoader(loader, ext) {
if (!loader) throw new Error(`No loader specified for extension "${ext}"`);
if (typeof loader !== 'function') throw new Error('loader is not a function');
}
/** @type {(enableCache: boolean) => <T>(c: Map<string, T>, filepath: string, res: T) => T} */
const makeEmplace = enableCache => (c, filepath, res) => {
if (enableCache) c.set(filepath, res);
return res;
};
/** @type {import('./index').lilconfig} */
module.exports.lilconfig = function lilconfig(name, options) {
const {
ignoreEmptySearchPlaces,
loaders,
packageProp,
searchPlaces,
stopDir,
transform,
cache,
} = getOptions(name, options ?? {}, false);
const searchCache = new Map();
const loadCache = new Map();
const emplace = makeEmplace(cache);
return {
async search(searchFrom = process.cwd()) {
/** @type {import('./index').LilconfigResult} */
const result = {
config: null,
filepath: '',
};
/** @type {Set<string>} */
const visited = new Set();
let dir = searchFrom;
dirLoop: while (true) {
if (cache) {
const r = searchCache.get(dir);
if (r !== undefined) {
for (const p of visited) searchCache.set(p, r);
return r;
}
visited.add(dir);
}
for (const searchPlace of searchPlaces) {
const filepath = path.join(dir, searchPlace);
try {
await fs.promises.access(filepath);
} catch {
continue;
}
const content = String(await fsReadFileAsync(filepath));
const loaderKey = path.extname(searchPlace) || 'noExt';
const loader = loaders[loaderKey];
// handle package.json
if (searchPlace === 'package.json') {
const pkg = await loader(filepath, content);
const maybeConfig = getPackageProp(packageProp, pkg);
if (maybeConfig != null) {
result.config = maybeConfig;
result.filepath = filepath;
break dirLoop;
}
continue;
}
// handle other type of configs
const isEmpty = content.trim() === '';
if (isEmpty && ignoreEmptySearchPlaces) continue;
if (isEmpty) {
result.isEmpty = true;
result.config = undefined;
} else {
validateLoader(loader, loaderKey);
result.config = await loader(filepath, content);
}
result.filepath = filepath;
break dirLoop;
}
if (dir === stopDir || dir === parentDir(dir)) break dirLoop;
dir = parentDir(dir);
}
const transformed =
// not found
result.filepath === '' && result.config === null
? transform(null)
: transform(result);
if (cache) {
for (const p of visited) searchCache.set(p, transformed);
}
return transformed;
},
async load(filepath) {
validateFilePath(filepath);
const absPath = path.resolve(process.cwd(), filepath);
if (cache && loadCache.has(absPath)) {
return loadCache.get(absPath);
}
const {base, ext} = path.parse(absPath);
const loaderKey = ext || 'noExt';
const loader = loaders[loaderKey];
validateLoader(loader, loaderKey);
const content = String(await fsReadFileAsync(absPath));
if (base === 'package.json') {
const pkg = await loader(absPath, content);
return emplace(
loadCache,
absPath,
transform({
config: getPackageProp(packageProp, pkg),
filepath: absPath,
}),
);
}
/** @type {import('./index').LilconfigResult} */
const result = {
config: null,
filepath: absPath,
};
// handle other type of configs
const isEmpty = content.trim() === '';
if (isEmpty && ignoreEmptySearchPlaces)
return emplace(
loadCache,
absPath,
transform({
config: undefined,
filepath: absPath,
isEmpty: true,
}),
);
// cosmiconfig returns undefined for empty files
result.config = isEmpty ? undefined : await loader(absPath, content);
return emplace(
loadCache,
absPath,
transform(isEmpty ? {...result, isEmpty, config: undefined} : result),
);
},
clearLoadCache() {
if (cache) loadCache.clear();
},
clearSearchCache() {
if (cache) searchCache.clear();
},
clearCaches() {
if (cache) {
loadCache.clear();
searchCache.clear();
}
},
};
};
/** @type {import('./index').lilconfigSync} */
module.exports.lilconfigSync = function lilconfigSync(name, options) {
const {
ignoreEmptySearchPlaces,
loaders,
packageProp,
searchPlaces,
stopDir,
transform,
cache,
} = getOptions(name, options ?? {}, true);
const searchCache = new Map();
const loadCache = new Map();
const emplace = makeEmplace(cache);
return {
search(searchFrom = process.cwd()) {
/** @type {import('./index').LilconfigResult} */
const result = {
config: null,
filepath: '',
};
/** @type {Set<string>} */
const visited = new Set();
let dir = searchFrom;
dirLoop: while (true) {
if (cache) {
const r = searchCache.get(dir);
if (r !== undefined) {
for (const p of visited) searchCache.set(p, r);
return r;
}
visited.add(dir);
}
for (const searchPlace of searchPlaces) {
const filepath = path.join(dir, searchPlace);
try {
fs.accessSync(filepath);
} catch {
continue;
}
const loaderKey = path.extname(searchPlace) || 'noExt';
const loader = loaders[loaderKey];
const content = String(fs.readFileSync(filepath));
// handle package.json
if (searchPlace === 'package.json') {
const pkg = loader(filepath, content);
const maybeConfig = getPackageProp(packageProp, pkg);
if (maybeConfig != null) {
result.config = maybeConfig;
result.filepath = filepath;
break dirLoop;
}
continue;
}
// handle other type of configs
const isEmpty = content.trim() === '';
if (isEmpty && ignoreEmptySearchPlaces) continue;
if (isEmpty) {
result.isEmpty = true;
result.config = undefined;
} else {
validateLoader(loader, loaderKey);
result.config = loader(filepath, content);
}
result.filepath = filepath;
break dirLoop;
}
if (dir === stopDir || dir === parentDir(dir)) break dirLoop;
dir = parentDir(dir);
}
const transformed =
// not found
result.filepath === '' && result.config === null
? transform(null)
: transform(result);
if (cache) {
for (const p of visited) searchCache.set(p, transformed);
}
return transformed;
},
load(filepath) {
validateFilePath(filepath);
const absPath = path.resolve(process.cwd(), filepath);
if (cache && loadCache.has(absPath)) {
return loadCache.get(absPath);
}
const {base, ext} = path.parse(absPath);
const loaderKey = ext || 'noExt';
const loader = loaders[loaderKey];
validateLoader(loader, loaderKey);
const content = String(fs.readFileSync(absPath));
if (base === 'package.json') {
const pkg = loader(absPath, content);
return transform({
config: getPackageProp(packageProp, pkg),
filepath: absPath,
});
}
const result = {
config: null,
filepath: absPath,
};
// handle other type of configs
const isEmpty = content.trim() === '';
if (isEmpty && ignoreEmptySearchPlaces)
return emplace(
loadCache,
absPath,
transform({
filepath: absPath,
config: undefined,
isEmpty: true,
}),
);
// cosmiconfig returns undefined for empty files
result.config = isEmpty ? undefined : loader(absPath, content);
return emplace(
loadCache,
absPath,
transform(isEmpty ? {...result, isEmpty, config: undefined} : result),
);
},
clearLoadCache() {
if (cache) loadCache.clear();
},
clearSearchCache() {
if (cache) searchCache.clear();
},
clearCaches() {
if (cache) {
loadCache.clear();
searchCache.clear();
}
},
};
};