Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
A JS/TS/Node utility for deep-assigning default property values to arbitrary objects, like Object.assign
with superpowers.
npm i deffo
The Defaults
class recursively merges two objects -- a defaults
object and a target
object -- into a new object combining their properties, using the target
property values where present.
class Defaults<T extends object, U extends DeepPartial<T> = DeepPartial<T>> {
constructor(defaults: T, replacer?: ReplacerObject<T>);
static with<T extends object, U extends DeepPartial<T>>(
defaults: T,
target: U,
replacer?: Replacer<T> | ReplacerObject<T>
): T & U;
assign(target: U, replacer?: Replacer<T> | ReplacerObject<T>): T & U;
}
import { Defaults } from "deffo";
const requestInit = new Defaults<RequestInit>({
method: "POST",
mode: "cors",
cache: "no-cache",
headers: {
"Content-Type": "application/json",
},
redirect: "follow",
});
const cacheNoFollow = requestInit.assign({
cache: "default",
headers: {
Foo: "bar",
},
redirect: "manual",
});
// {
// method: 'POST',
// mode: 'cors',
// cache: 'default',
// headers: {
// "Content-Type": "application/json",
// "Foo": "bar",
// },
// redirect: 'manual',
// }
The target
object will always be a DeepPartial
version of the defaults
object, in which all the properties are (recursively) optional. Providing a value for any property at any level will override that property, and that property only.
Sometimes you may want to customize the merge behavior, for example replacing a entire object, combining the default
and target
values, or otherwise transforming specific values. You can do this by providing a ReplacerObject
argument, which has a shape matching the defaults
object, in which any value can be a function that takes in both the default
and target
values for the property, and must return a value of the same type.
const postTemplate = {
id: 1,
type: "blog",
content: {
title: "TEMPLATE POST",
body: "This is a test",
},
};
const postDefaults = new Defaults(postTemplate, {
// The new `id` is the sum of the provided `id` and the default `id`
id: (defaultValue, targetValue) => defaultValue + targetValue,
// The post type "tweet" is replaced with "toot"; we're on Mastodon now
type: (_, targetValue) => {
if (targetValue === "tweet") {
return "toot";
} else {
return targetValue;
}
},
// All titles should be in uppercase
content: {
title: (_, targetValue) => {
return targetValue.toUpperCase();
},
},
});
const socialPost = postDefaults.assign({
id: 6,
type: "tweet",
content: {
title: "listen up",
},
});
// {
// id: 7,
// type: "toot",
// content: {
// title: "LISTEN UP",
// body: "This is a test",
// },
// };
Replacers will only be called when the property is present on the target
, and will only modify the target property.
If you don't wish to keep the Defaults
object around, you can apply defaults using the static method form. An optional replacer can be passed as the third argument.
const user = Defaults.with(
{
name: "Jane Doe",
role: "admin",
details: {
interests: ["coding"],
location: {
city: "Boulder",
state: "CO",
zip: 80302,
},
},
},
{
name: "Julie Sands",
details: {
city: "Denver",
zip: 80220,
},
}
);
// {
// name: "Julie Sands",
// role: "admin",
// details: {
// interests: ["coding"],
// location: {
// city: "Denver",
// state: "CO",
// zip: 80220,
// },
// },
// }
Array-based defaults and replacers are supported, and treat each indexed value as a numeric-keyed property. Because of this, it is recommended to use it only for tuple-like types with a fixed length. If you need to transform a dynamic list with defaults, transform them at the element level instead of at the whole array level.
type Token = { type: string; start: number; end: number };
const templatePair: [Token, string] = [
{ type: "identifier", start: 0, end: 1 },
"a",
];
const tokenDefaults = new Defaults(templatePair, [
undefined, // Do not replace the first element
(_, tv) => `_${tv}`, // Prefix the second element with "_"
]);
const tok = tokenDefaults.assign([{ start: 12, end: 13 }, "b"]);
// [{ type: "identifier", start: 12, end: 13 }, "_b"];
type DeepPartial<T> = T extends object
? {
[P in keyof T]?: DeepPartial<T[P]>;
}
: T;
type ReplacerFunction<T> = (defaultValue: T, targetValue: DeepPartial<T>) => T;
type ReplacerObject<T extends object> = {
[P in keyof T]?: Replacer<T[P]>;
};
type Replacer<T> = T extends object
? ReplacerObject<T> | ReplacerFunction<T>
: ReplacerFunction<T>;
MIT © Tobias Fried
FAQs
Deep defaults for complex objects
The npm package deffo receives a total of 4 weekly downloads. As such, deffo popularity was classified as not popular.
We found that deffo demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.