[6a3a178] | 1 | "use strict";
|
---|
| 2 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
| 3 | exports.lilconfigSync = exports.lilconfig = exports.defaultLoaders = void 0;
|
---|
| 4 | const path = require("path");
|
---|
| 5 | const fs = require("fs");
|
---|
| 6 | const os = require("os");
|
---|
| 7 | const fsReadFileAsync = fs.promises.readFile;
|
---|
| 8 | function getDefaultSearchPlaces(name) {
|
---|
| 9 | return [
|
---|
| 10 | 'package.json',
|
---|
| 11 | `.${name}rc.json`,
|
---|
| 12 | `.${name}rc.js`,
|
---|
| 13 | `${name}.config.js`,
|
---|
| 14 | `.${name}rc.cjs`,
|
---|
| 15 | `${name}.config.cjs`,
|
---|
| 16 | ];
|
---|
| 17 | }
|
---|
| 18 | function getSearchPaths(startDir, stopDir) {
|
---|
| 19 | return startDir
|
---|
| 20 | .split(path.sep)
|
---|
| 21 | .reduceRight((acc, _, ind, arr) => {
|
---|
| 22 | const currentPath = arr.slice(0, ind + 1).join(path.sep);
|
---|
| 23 | if (!acc.passedStopDir)
|
---|
| 24 | acc.searchPlaces.push(currentPath || path.sep);
|
---|
| 25 | if (currentPath === stopDir)
|
---|
| 26 | acc.passedStopDir = true;
|
---|
| 27 | return acc;
|
---|
| 28 | }, { searchPlaces: [], passedStopDir: false }).searchPlaces;
|
---|
| 29 | }
|
---|
| 30 | exports.defaultLoaders = Object.freeze({
|
---|
| 31 | '.js': require,
|
---|
| 32 | '.json': require,
|
---|
| 33 | '.cjs': require,
|
---|
| 34 | noExt(_, content) {
|
---|
| 35 | return JSON.parse(content);
|
---|
| 36 | },
|
---|
| 37 | });
|
---|
| 38 | function getExtDesc(ext) {
|
---|
| 39 | return ext === 'noExt' ? 'files without extensions' : `extension "${ext}"`;
|
---|
| 40 | }
|
---|
| 41 | function getOptions(name, options = {}) {
|
---|
| 42 | const conf = {
|
---|
| 43 | stopDir: os.homedir(),
|
---|
| 44 | searchPlaces: getDefaultSearchPlaces(name),
|
---|
| 45 | ignoreEmptySearchPlaces: true,
|
---|
| 46 | transform: (x) => x,
|
---|
| 47 | packageProp: [name],
|
---|
| 48 | ...options,
|
---|
| 49 | loaders: { ...exports.defaultLoaders, ...options.loaders },
|
---|
| 50 | };
|
---|
| 51 | conf.searchPlaces.forEach(place => {
|
---|
| 52 | const key = path.extname(place) || 'noExt';
|
---|
| 53 | const loader = conf.loaders[key];
|
---|
| 54 | if (!loader) {
|
---|
| 55 | throw new Error(`No loader specified for ${getExtDesc(key)}, so searchPlaces item "${place}" is invalid`);
|
---|
| 56 | }
|
---|
| 57 | if (typeof loader !== 'function') {
|
---|
| 58 | throw new Error(`loader for ${getExtDesc(key)} is not a function (type provided: "${typeof loader}"), so searchPlaces item "${place}" is invalid`);
|
---|
| 59 | }
|
---|
| 60 | });
|
---|
| 61 | return conf;
|
---|
| 62 | }
|
---|
| 63 | function getPackageProp(props, obj) {
|
---|
| 64 | if (typeof props === 'string' && props in obj)
|
---|
| 65 | return obj[props];
|
---|
| 66 | return ((Array.isArray(props) ? props : props.split('.')).reduce((acc, prop) => (acc === undefined ? acc : acc[prop]), obj) || null);
|
---|
| 67 | }
|
---|
| 68 | function getSearchItems(searchPlaces, searchPaths) {
|
---|
| 69 | return searchPaths.reduce((acc, searchPath) => {
|
---|
| 70 | searchPlaces.forEach(fileName => acc.push({
|
---|
| 71 | fileName,
|
---|
| 72 | filepath: path.join(searchPath, fileName),
|
---|
| 73 | loaderKey: path.extname(fileName) || 'noExt',
|
---|
| 74 | }));
|
---|
| 75 | return acc;
|
---|
| 76 | }, []);
|
---|
| 77 | }
|
---|
| 78 | function validateFilePath(filepath) {
|
---|
| 79 | if (!filepath)
|
---|
| 80 | throw new Error('load must pass a non-empty string');
|
---|
| 81 | }
|
---|
| 82 | function validateLoader(loader, ext) {
|
---|
| 83 | if (!loader)
|
---|
| 84 | throw new Error(`No loader specified for extension "${ext}"`);
|
---|
| 85 | if (typeof loader !== 'function')
|
---|
| 86 | throw new Error('loader is not a function');
|
---|
| 87 | }
|
---|
| 88 | function lilconfig(name, options) {
|
---|
| 89 | const { ignoreEmptySearchPlaces, loaders, packageProp, searchPlaces, stopDir, transform, } = getOptions(name, options);
|
---|
| 90 | return {
|
---|
| 91 | async search(searchFrom = process.cwd()) {
|
---|
| 92 | const searchPaths = getSearchPaths(searchFrom, stopDir);
|
---|
| 93 | const result = {
|
---|
| 94 | config: null,
|
---|
| 95 | filepath: '',
|
---|
| 96 | };
|
---|
| 97 | const searchItems = getSearchItems(searchPlaces, searchPaths);
|
---|
| 98 | for (const { fileName, filepath, loaderKey } of searchItems) {
|
---|
| 99 | try {
|
---|
| 100 | await fs.promises.access(filepath);
|
---|
| 101 | }
|
---|
| 102 | catch (_a) {
|
---|
| 103 | continue;
|
---|
| 104 | }
|
---|
| 105 | const content = String(await fsReadFileAsync(filepath));
|
---|
| 106 | const loader = loaders[loaderKey];
|
---|
| 107 | if (fileName === 'package.json') {
|
---|
| 108 | const pkg = loader(filepath, content);
|
---|
| 109 | const maybeConfig = getPackageProp(packageProp, pkg);
|
---|
| 110 | if (maybeConfig != null) {
|
---|
| 111 | result.config = maybeConfig;
|
---|
| 112 | result.filepath = filepath;
|
---|
| 113 | break;
|
---|
| 114 | }
|
---|
| 115 | continue;
|
---|
| 116 | }
|
---|
| 117 | const isEmpty = content.trim() === '';
|
---|
| 118 | if (isEmpty && ignoreEmptySearchPlaces)
|
---|
| 119 | continue;
|
---|
| 120 | if (isEmpty) {
|
---|
| 121 | result.isEmpty = true;
|
---|
| 122 | result.config = undefined;
|
---|
| 123 | }
|
---|
| 124 | else {
|
---|
| 125 | validateLoader(loader, loaderKey);
|
---|
| 126 | result.config = loader(filepath, content);
|
---|
| 127 | }
|
---|
| 128 | result.filepath = filepath;
|
---|
| 129 | break;
|
---|
| 130 | }
|
---|
| 131 | if (result.filepath === '' && result.config === null)
|
---|
| 132 | return transform(null);
|
---|
| 133 | return transform(result);
|
---|
| 134 | },
|
---|
| 135 | async load(filepath) {
|
---|
| 136 | validateFilePath(filepath);
|
---|
[e29cc2e] | 137 | const absPath = path.resolve(process.cwd(), filepath);
|
---|
| 138 | const { base, ext } = path.parse(absPath);
|
---|
[6a3a178] | 139 | const loaderKey = ext || 'noExt';
|
---|
| 140 | const loader = loaders[loaderKey];
|
---|
| 141 | validateLoader(loader, loaderKey);
|
---|
[e29cc2e] | 142 | const content = String(await fsReadFileAsync(absPath));
|
---|
[6a3a178] | 143 | if (base === 'package.json') {
|
---|
[e29cc2e] | 144 | const pkg = await loader(absPath, content);
|
---|
[6a3a178] | 145 | return transform({
|
---|
| 146 | config: getPackageProp(packageProp, pkg),
|
---|
[e29cc2e] | 147 | filepath: absPath,
|
---|
[6a3a178] | 148 | });
|
---|
| 149 | }
|
---|
| 150 | const result = {
|
---|
| 151 | config: null,
|
---|
[e29cc2e] | 152 | filepath: absPath,
|
---|
[6a3a178] | 153 | };
|
---|
| 154 | const isEmpty = content.trim() === '';
|
---|
| 155 | if (isEmpty && ignoreEmptySearchPlaces)
|
---|
| 156 | return transform({
|
---|
| 157 | config: undefined,
|
---|
[e29cc2e] | 158 | filepath: absPath,
|
---|
[6a3a178] | 159 | isEmpty: true,
|
---|
| 160 | });
|
---|
| 161 | result.config = isEmpty
|
---|
| 162 | ? undefined
|
---|
[e29cc2e] | 163 | : await loader(absPath, content);
|
---|
[6a3a178] | 164 | return transform(isEmpty ? { ...result, isEmpty, config: undefined } : result);
|
---|
| 165 | },
|
---|
| 166 | };
|
---|
| 167 | }
|
---|
| 168 | exports.lilconfig = lilconfig;
|
---|
| 169 | function lilconfigSync(name, options) {
|
---|
| 170 | const { ignoreEmptySearchPlaces, loaders, packageProp, searchPlaces, stopDir, transform, } = getOptions(name, options);
|
---|
| 171 | return {
|
---|
| 172 | search(searchFrom = process.cwd()) {
|
---|
| 173 | const searchPaths = getSearchPaths(searchFrom, stopDir);
|
---|
| 174 | const result = {
|
---|
| 175 | config: null,
|
---|
| 176 | filepath: '',
|
---|
| 177 | };
|
---|
| 178 | const searchItems = getSearchItems(searchPlaces, searchPaths);
|
---|
| 179 | for (const { fileName, filepath, loaderKey } of searchItems) {
|
---|
| 180 | try {
|
---|
| 181 | fs.accessSync(filepath);
|
---|
| 182 | }
|
---|
| 183 | catch (_a) {
|
---|
| 184 | continue;
|
---|
| 185 | }
|
---|
| 186 | const loader = loaders[loaderKey];
|
---|
| 187 | const content = String(fs.readFileSync(filepath));
|
---|
| 188 | if (fileName === 'package.json') {
|
---|
| 189 | const pkg = loader(filepath, content);
|
---|
| 190 | const maybeConfig = getPackageProp(packageProp, pkg);
|
---|
| 191 | if (maybeConfig != null) {
|
---|
| 192 | result.config = maybeConfig;
|
---|
| 193 | result.filepath = filepath;
|
---|
| 194 | break;
|
---|
| 195 | }
|
---|
| 196 | continue;
|
---|
| 197 | }
|
---|
| 198 | const isEmpty = content.trim() === '';
|
---|
| 199 | if (isEmpty && ignoreEmptySearchPlaces)
|
---|
| 200 | continue;
|
---|
| 201 | if (isEmpty) {
|
---|
| 202 | result.isEmpty = true;
|
---|
| 203 | result.config = undefined;
|
---|
| 204 | }
|
---|
| 205 | else {
|
---|
| 206 | validateLoader(loader, loaderKey);
|
---|
| 207 | result.config = loader(filepath, content);
|
---|
| 208 | }
|
---|
| 209 | result.filepath = filepath;
|
---|
| 210 | break;
|
---|
| 211 | }
|
---|
| 212 | if (result.filepath === '' && result.config === null)
|
---|
| 213 | return transform(null);
|
---|
| 214 | return transform(result);
|
---|
| 215 | },
|
---|
| 216 | load(filepath) {
|
---|
| 217 | validateFilePath(filepath);
|
---|
[e29cc2e] | 218 | const absPath = path.resolve(process.cwd(), filepath);
|
---|
| 219 | const { base, ext } = path.parse(absPath);
|
---|
[6a3a178] | 220 | const loaderKey = ext || 'noExt';
|
---|
| 221 | const loader = loaders[loaderKey];
|
---|
| 222 | validateLoader(loader, loaderKey);
|
---|
[e29cc2e] | 223 | const content = String(fs.readFileSync(absPath));
|
---|
[6a3a178] | 224 | if (base === 'package.json') {
|
---|
[e29cc2e] | 225 | const pkg = loader(absPath, content);
|
---|
[6a3a178] | 226 | return transform({
|
---|
| 227 | config: getPackageProp(packageProp, pkg),
|
---|
[e29cc2e] | 228 | filepath: absPath,
|
---|
[6a3a178] | 229 | });
|
---|
| 230 | }
|
---|
| 231 | const result = {
|
---|
| 232 | config: null,
|
---|
[e29cc2e] | 233 | filepath: absPath,
|
---|
[6a3a178] | 234 | };
|
---|
| 235 | const isEmpty = content.trim() === '';
|
---|
| 236 | if (isEmpty && ignoreEmptySearchPlaces)
|
---|
| 237 | return transform({
|
---|
[e29cc2e] | 238 | filepath: absPath,
|
---|
[6a3a178] | 239 | config: undefined,
|
---|
| 240 | isEmpty: true,
|
---|
| 241 | });
|
---|
[e29cc2e] | 242 | result.config = isEmpty ? undefined : loader(absPath, content);
|
---|
[6a3a178] | 243 | return transform(isEmpty ? { ...result, isEmpty, config: undefined } : result);
|
---|
| 244 | },
|
---|
| 245 | };
|
---|
| 246 | }
|
---|
| 247 | exports.lilconfigSync = lilconfigSync;
|
---|