Skip to content

Commit

Permalink
fix(deps): update dependency jiti to v2 #13
Browse files Browse the repository at this point in the history
  • Loading branch information
jaywcjlove committed Dec 11, 2024
1 parent 4d74007 commit ce2c933
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 121 deletions.
79 changes: 68 additions & 11 deletions core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Auto Config Loader

Find and load configuration from a `package.json` property, `rc` file, or `CommonJS` module. It has smart default based on traditional expectations in the JavaScript ecosystem. But it's also flexible enough to search anywhere you want and load whatever you want.

[V1 To V2 Migration](#v1-to-v2-migration)

## Features

- Support [JSON](https://www.json.org), [JSONC](https://github.com/microsoft/node-jsonc-parser), [JSON5](https://json5.org/), [YAML](https://yaml.org/), [TOML](https://toml.io), [INI](https://en.wikipedia.org/wiki/INI_file), [CJS](http://www.commonjs.org), [Typescript](https://www.typescriptlang.org/), and ESM config load.
Expand Down Expand Up @@ -43,7 +45,7 @@ import { autoConf } from 'auto-config-loader';
// process.cwd() + 'namespace.config.cjs'
// process.cwd() + 'namespace.config.js'
// ........
const data = autoConf('namespace', {
const data = await autoConf('namespace', {
default: {
testItem2: 'some value'
}
Expand All @@ -68,22 +70,22 @@ interface Config {
name: string;
}

const result = loadConf<Config>('./app/app.config.js');
const result = await loadConf<Config>('./app/app.config.js');
// => { name: 'app' }
```

## Option

```ts
import { LoadConfOption } from 'auto-config-loader';
export type LoaderFunc<T> = (filepath: string, content: string, jsOption?: LoadConfOption) => T;
export type LoaderFunc<T> = (filepath: string, content: string, jsOption?: LoadConfOption) => T | Promise<T>;
export type Loader<T> = Record<string, LoaderFunc<T>>;
export interface AutoConfOption<T> {
searchPlaces?: string[];
/** An object that maps extensions to the loader functions responsible for loading and parsing files with those extensions. */
loaders?: Loader<T>;
/** Specify default configuration. It has the lowest priority and is applied after extending config. */
defaluts?: T;
default?: T;
/** Resolve configuration from this working directory. The default is `process.cwd()` */
cwd?: string;
/** Default transform js configuration */
Expand All @@ -92,12 +94,14 @@ export interface AutoConfOption<T> {
ignoreLog?: boolean;
mustExist?: boolean;
}
export declare const getConfigPath: () => string;
/**
* Find and load configuration from a `package.json` property, `rc` file, or `CommonJS` module.
* @param namespace {string} Configuration base name. The default is `autoconf`.
* @param option
* @param option
*/
export default function autoConf<T>(namespace?: string, option?: AutoConfOption<T>): {} & T;
export declare function autoConf<T>(namespace?: string, option?: AutoConfOption<T>): Promise<{} & T>;
export default autoConf;
```

Discover configurations in the specified directory order. When configuring a tool, you can use multiple file formats and put these in multiple places. Usually, a tool would mention this in its own README file, but by default, these are the following places, where `${moduleName}` represents the name of the tool:
Expand Down Expand Up @@ -187,7 +191,7 @@ function loadJS(filepath, content) {
});
}
const data = load('namespace', {
const data = await load('namespace', {
loaders: {
'.js': loadJS,
'.ts': loadJS,
Expand Down Expand Up @@ -276,7 +280,7 @@ function loadYaml(filepath, content) {
return yaml.parse(content);
}

const data = load('namespace', {
const data = await load('namespace', {
searchPlaces: [
'.namespacerc.yaml',
'.namespacerc.yml',
Expand All @@ -298,9 +302,9 @@ const data = load('namespace', {
```ts
export declare const merge: {
<TObject, TSource>(object: TObject, source: TSource): TObject & TSource;
<TObject_1, TSource1, TSource2>(object: TObject_1, source1: TSource1, source2: TSource2): TObject_1 & TSource1 & TSource2;
<TObject_2, TSource1_1, TSource2_1, TSource3>(object: TObject_2, source1: TSource1_1, source2: TSource2_1, source3: TSource3): TObject_2 & TSource1_1 & TSource2_1 & TSource3;
<TObject_3, TSource1_2, TSource2_2, TSource3_1, TSource4>(object: TObject_3, source1: TSource1_2, source2: TSource2_2, source3: TSource3_1, source4: TSource4): TObject_3 & TSource1_2 & TSource2_2 & TSource3_1 & TSource4;
<TObject, TSource1, TSource2>(object: TObject, source1: TSource1, source2: TSource2): TObject & TSource1 & TSource2;
<TObject, TSource1, TSource2, TSource3>(object: TObject, source1: TSource1, source2: TSource2, source3: TSource3): TObject & TSource1 & TSource2 & TSource3;
<TObject, TSource1, TSource2, TSource3, TSource4>(object: TObject, source1: TSource1, source2: TSource2, source3: TSource3, source4: TSource4): TObject & TSource1 & TSource2 & TSource3 & TSource4;
(object: any, ...otherArgs: any[]): any;
};
```
Expand All @@ -327,6 +331,59 @@ const configPath = getConfigPath();
// => /.autoconfrc.js
```

## V1 To V2 Migration

This guide provides the steps to migrate to the latest version of the configuration loader API.

### Key Changes

1. **Loader Functions Support Async**
- `LoaderFunc<T>` now supports returning `T` or `Promise<T>`.
- Update custom loaders to handle asynchronous operations if needed.

**Example:**
```ts
export type LoaderFunc<T> = (filepath: string, content: string, jsOption?: LoadConfOption) => T | Promise<T>;
```

2. **`autoConf` Returns a Promise**
- The `autoConf` function now returns a `Promise` instead of a synchronous result.
- Update your code to handle asynchronous calls.

**Example:**
```ts
export declare function autoConf<T>(namespace?: string, option?: AutoConfOption<T>): Promise<{} & T>;
```

### Migration Steps

#### 1. Update Custom Loader Functions

If you have custom loaders, update their return types to support asynchronous operations:

**Example:**

```ts
const jsonLoader: LoaderFunc<MyConfig> = async (filepath, content) => JSON.parse(content);
```

#### 2. Handle Asynchronous `autoConf` Calls

Update all calls to `autoConf` to use `await` or `.then` to handle Promises:

**Example Using `await`:**
```ts
const config = await autoConf('myNamespace', options);
console.log(config);
```

**Example Using `.then`:**
```ts
autoConf('myNamespace', options).then(config => {
console.log(config);
});
```

## Related

- [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig) Find and load configuration from a package.json property, rc file, or CommonJS module
Expand Down
4 changes: 2 additions & 2 deletions core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@
},
"dependencies": {
"ini": "^5.0.0",
"jiti": "^1.18.2",
"jiti": "^2.4.1",
"jsonc-eslint-parser": "^2.3.0",
"lodash.merge": "^4.6.2",
"sucrase": "^3.32.0",
"sucrase": "^3.35.0",
"toml-eslint-parser": "^0.10.0",
"yaml-eslint-parser": "^1.2.2"
},
Expand Down
6 changes: 3 additions & 3 deletions core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export * from './loader/ini';

export const merge = mergeFun;

export type LoaderFunc<T> = (filepath: string, content: string, jsOption?: LoadConfOption) => T;
export type LoaderFunc<T> = (filepath: string, content: string, jsOption?: LoadConfOption) => T | Promise<T>;
export type Loader<T> = Record<string, LoaderFunc<T>>;
export interface AutoConfOption<T> {
searchPlaces?: string[];
Expand All @@ -43,7 +43,7 @@ export const getConfigPath = () => configPath;
* @param namespace {string} Configuration base name. The default is `autoconf`.
* @param option
*/
export function autoConf<T>(namespace: string = 'autoconf', option: AutoConfOption<T> = {}) {
export async function autoConf<T>(namespace: string = 'autoconf', option: AutoConfOption<T> = {}) {
const {
searchPlaces = [],
default: defaultValue = {},
Expand Down Expand Up @@ -89,7 +89,7 @@ export function autoConf<T>(namespace: string = 'autoconf', option: AutoConfOpti
}

if (content && loaderFunc) {
resultData = loaderFunc(configPath, content, jsOption);
resultData = await loaderFunc(configPath, content, jsOption);
if (typeof resultData === 'function') {
return merge(defaultValue, resultData, { default: resultData });
}
Expand Down
33 changes: 21 additions & 12 deletions core/src/loader/js.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import jitiFactory from 'jiti';
import type { JITIOptions } from 'jiti/dist/types';
import { createJiti } from 'jiti';
import type jiti from 'jiti';
import { transform, Options } from 'sucrase';

let jiti: ReturnType<typeof jitiFactory> | null = null;
type Jiti = ReturnType<typeof jiti>;
type JITIOptions = Jiti['options'];

let jitiInstance: ReturnType<typeof jiti> | null = null;
function lazyJiti(option: JITIOptions = {}, transformOpt = {} as Options) {
return (
jiti ??
(jiti = jitiFactory(__filename, {
jitiInstance ??
(jitiInstance = createJiti(__filename, {
interopDefault: true,
...option,
transform: (opts) => {
Expand All @@ -25,22 +28,28 @@ export interface LoadConfOption {
transformOption?: Options;
}

export function loadConf<T>(path: string, option: LoadConfOption = {}): T {
export async function loadConf<T>(path: string, option: LoadConfOption = {}): Promise<T> {
const { jiti = true, jitiOptions, transformOption } = option;
let config = (function () {
let config = await (async function () {
try {
if (jiti) {
return path ? lazyJiti(jitiOptions, transformOption)(path) : {};
return path ? await lazyJiti(jitiOptions, transformOption).import(path) : {};
} else {
return path ? require(path) : {};
}
} catch {
return lazyJiti(jitiOptions, transformOption)(path);
return await lazyJiti(jitiOptions, transformOption).import(path);
}
})();
return config.default ?? config;

// Ensure both default export and named exports are handled
if (config.default) {
config = { ...config.default, ...config };
}

return config;
}

export function jsLoader<T>(filepath: string, content: string, option: LoadConfOption = {}): T {
return loadConf<T>(filepath, option);
export async function jsLoader<T>(filepath: string, content: string, option: LoadConfOption = {}): Promise<T> {
return await loadConf<T>(filepath, option);
}
Loading

0 comments on commit ce2c933

Please sign in to comment.