Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add defuSchema #104

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,19 @@ defuArrayFn({

**Note:** the function is called only if the value defined in defaults is an aray.

## Schema object
You can use `defuSchema` if you want to remove keys that are not present in the default object.

```js
console.log(
defuSchema(
{ a: 1, b: 2, c: 3, d: 4 },
{ a: 2, c: 4, d: 6, e: 8 }
)
);
// => { a: 1, c: 3, d: 4, e: 8 }
``

### Remarks

- `object` and `defaults` are not modified
Expand Down
4 changes: 2 additions & 2 deletions lib/defu.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { defu, createDefu, defuFn, defuArrayFn } = require('../dist/defu.cjs');
const { defu, createDefu, defuFn, defuArrayFn, defuSchema } = require('../dist/defu.cjs');

module.exports = defu;

Expand All @@ -8,4 +8,4 @@ module.exports.default = defu;
module.exports.createDefu = createDefu;
module.exports.defuFn = defuFn;
module.exports.defuArrayFn = defuArrayFn;

module.exports.defuSchema = defuSchema;
12 changes: 11 additions & 1 deletion src/defu.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { isPlainObject } from "./_utils";
import type { Merger, DefuFn as DefuFunction, DefuInstance } from "./types";
import type {
Merger,
DefuFn as DefuFunction,
DefuInstance,
DefuFnSchema,
} from "./types";

// Base function to apply defaults
function _defu<T>(
Expand Down Expand Up @@ -73,4 +78,9 @@ export const defuArrayFn = createDefu((object, key, currentValue) => {
}
});

// Custom version for skipping keys not present in defaults
export const defuSchema = createDefu((schema, key) => {
return !(key in schema);
}) as DefuFnSchema;

export type { Defu } from "./types";
18 changes: 18 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ export type DefuFn = <
...defaults: Defaults
) => Defu<Source, Defaults>;

export type DefuFnSchema = <
Source extends Input,
Defaults extends Array<Input | IgnoredInput>,
>(
source: Source,
...defaults: Defaults
) => Defaults extends [infer F, ...infer Rest]
? F extends Input
? Rest extends Array<Input | IgnoredInput>
? Defu<MergeObjects<F, F>, Rest>
: MergeObjects<F, F>
: F extends IgnoredInput
? Rest extends Array<Input | IgnoredInput>
? Defu<F, Rest>
: F
: F
: never;

export interface DefuInstance {
<Source extends Input, Defaults extends Array<Input | IgnoredInput>>(
source: Source | IgnoredInput,
Expand Down
21 changes: 20 additions & 1 deletion test/defu.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expectTypeOf } from "expect-type";
import { it, describe, expect } from "vitest";
import { defu, createDefu, defuFn, defuArrayFn } from "../src/defu";
import { defu, createDefu, defuFn, defuArrayFn, defuSchema } from "../src/defu";
import * as asteriskImport from "./fixtures/";

// Part of tests brought from jonschlinkert/defaults-deep (MIT)
Expand All @@ -23,6 +23,25 @@ describe("defu", () => {
expectTypeOf(result2).toMatchTypeOf<{ a: string; d: string }>();
});

it("defuSchema(): should skip keys non present in default object", () => {
const result = defuSchema(
{ a: 1, b: 2, c: 3, d: 4 },
{ a: 2, c: 4, d: 6, e: 8 },
);
expect(result).toEqual({
a: 1,
c: 3,
d: 4,
e: 8,
});
expectTypeOf(result).toEqualTypeOf<{
a: number;
c: number;
d: number;
e: number;
}>();
});

it("should copy nested values", () => {
const result = defu({ a: { b: "c" } }, { a: { d: "e" } });
expect(result).toEqual({
Expand Down