Skip to Content
  • Website
Codsen
  • Home
  • Open Source
  • Articles
  • About

prevOpen Source→object-flatten-referencingnext

object-flatten-referencing7.2.1

Flatten complex nested objects according to a reference objects

Downloads per monthChangelogMIT Licenselibera manifesto
  • the top
  • Installation
  • Quick Take
  • Examples
  • IDEA
  • API — FLATTENREFERE…
  • API — FLATTENOBJEC…
  • API — FLATTENARR()
  • API — ARRAYIFFY()
  • API — DEFAULTS
  • API — VERSION
  • API — TYPES
  • THE ALGORITH…
  • IN PRACTICE
  • Changelog

Installation

Quick Take

Examples

  • Wrap an already wrapped value when prevention is disabled
  • Insert a break even when the previous line already contains one
  • Normalise a string setting to an array
  • Avoid adding a break after a line that already ends with one
  • Wrap flattened string values with custom markers
  • Inspect the exported flattening defaults
  • Disable wrapping across the complete input tree
  • Skip wrapping for keys that match a glob
  • Skip wrapping only at an exact nested path
  • Flatten an array with line breaks between rows
  • Flatten an object's keys and values to strings
  • Use HTML rather than XHTML line-break syntax
  • Leave an ignored key and its nested value unchanged
  • Merge array rows without inserting line breaks
  • Flatten input keys even when the reference has no matching key
  • Leave an unmatched input key unchanged
  • Throw when an input key is absent from the reference
  • Set the separator used by flattenObject
  • Keep values that already contain the wrapping markers
  • Leave templating statements unwrapped

Idea

Sometimes you need to make one nested object to look like another, type-wise.

For example, you’ve got a key a, whose value is array of object(s):

{
  a: [
    {
      b: "c",
      d: "e",
    },
  ];
}

but, you need the key to have its value as string:

{
  a: "b.c<br />d.e";
}

This library does such object “flattening”.

API — flattenReferencing()

The main function flattenReferencing() is imported like this:

It’s a function which takes three input arguments:

The Optional Options Object has the following shape:

KeyTypeObligatoryDefaultDescription
wrapHeadsWith
Type: String
Obligatory: no
Default: %%_
wrapHeadsWithStringno%%_Prepend this to each value, each result of flattening or simply other encountered value.
wrapTailsWith
Type: String
Obligatory: no
Default: _%%
wrapTailsWithStringno_%%Append this to each value, each result of flattening or simply other encountered value.
dontWrapKeys
Type: Array of strings or String
Obligatory: no
Default: empty array
dontWrapKeysArray of strings or Stringnoempty arrayNothing is appended or prepended to the keys that match value(s) given here (applies to child nodes as well). Those keys (and their child nodes) are not flattened either. This is used to prevent mangling of keys containing your data storage, for example. You can put wildcards (*) to match zero or more characters.
dontWrapPaths
Type: Array of strings or String
Obligatory: no
Default: empty array
dontWrapPathsArray of strings or Stringnoempty arrayThis is a more-precise cousin of dontWrapKeys. Put the exact path(s) to the key you want to ignore. Remember to append [number] after keys that have values as arrays. For example, here’s a path to ignore: modules[0].part2[1].ccc[0].kkk — key modules in root, equal to array. Take zero’th element from that array, it’s an object. Take that object’s key part2, it’s equal to an array. Take that array’s second element (index 1)… and so on. This path would be ignored, for example.
xhtml
Type: Boolean
Obligatory: no
Default: true
xhtmlBooleannotrueWhen flattening, arrays or plain objects are converted into strings. Each value is separated by a line break, and this controls which type to use: HTML (<br>) or XHTML (<br />)
preventDoubleWrapping
Type: Boolean
Obligatory: no
Default: true
preventDoubleWrappingBooleannotrueIf the current value already contains a string from wrapHeadsWith or wrapTailsWith, don’t wrap to prevent double wrapping.
preventWrappingIfContains
Type: Array of strings or String
Obligatory: no
Default: empty array
preventWrappingIfContainsArray of strings or Stringnoempty arraySometimes variables you set in mapping can have various notations, for example in Nunjucks default wrapHeadsWith would be {{ but also some variables are marked with {%. Obviously they would not get recognised and whole string containing them would get wrapped with let’s say {{ and }}. But no more. State your system variable heads and tails here, put them as string array.
objectKeyAndValueJoinChar
Type: String
Obligatory: no
Default: .
objectKeyAndValueJoinCharStringno.When an object is turned into a string, its key is joined with its value, with another string in-between. This controls what that in-between string is.
wrapGlobalFlipSwitch
Type: Boolean
Obligatory: no
Default: true
wrapGlobalFlipSwitchBooleannotrueYou can turn off the wrapping function completely using this.
ignore
Type: Array or String
Obligatory: no
Default: empty array
ignoreArray or Stringnoempty arrayDon’t apply any flattening to any of these keys. Naturally, don’t wrap them with anything either.
whatToDoWhenReferenceIsMissing
Type: Integer or Integer as String
Obligatory: no
Default: 0
whatToDoWhenReferenceIsMissingInteger or Integer as Stringno00 = skip, 1 = throw, 2 = flatten to string
mergeArraysWithLineBreaks
Type: Boolean
Obligatory: no
Default: true
mergeArraysWithLineBreaksBooleannotrueMerge arrays using <br />’s? It’s handy to turn it off when mapping variables on email templates where values in data arrays are IF statements, and <br />’s are hardcoded inside of them.
mergeWithoutTrailingBrIfLineContainsBr
Type: Boolean
Obligatory: no
Default: true
mergeWithoutTrailingBrIfLineContainsBrBooleannotrueWhen merging arrays to produce a string, each row’s contents will be checked do they contain <br, and if so, line break in front of it will not be added. Added in v4.
enforceStrictKeyset
Type: Boolean
Obligatory: no
Default: true
enforceStrictKeysetBooleannotrueAre you allowed to pass in an unrecognised keys in the options object?

Here are all defaults in one place for copying:

The function will return a new plain object, flattened according to your supplied reference object.

API — flattenObject()

The function flattenObject() is imported like this:

The first of the two building blocks described in The algorithm, exported so you can use it on its own. It flattens a plain object into an array of object-path notation strings:

Input argumentTypeObligatoryDescription
obj
Type: Plain object
Obligatory: yes
objPlain objectyesThe object to flatten.
opts
Type: Plain object
Obligatory: no
optsPlain objectnoOptional Options Object, the same one flattenReferencing() takes.
import { flattenObject } from "object-flatten-referencing";

console.log(flattenObject({ a: "b", c: { d: "e" } }));
// => ["a.b", "c.d.e"]

console.log(flattenObject({ a: ["b", "c"] }));
// => ["a.b", "a.c"]

API — flattenArr()

The function flattenArr() is imported like this:

The second building block. It flattens an array into a string:

Input argumentTypeObligatoryDefaultDescription
arr
Type: Array
Obligatory: yes
Default:
arrArrayyesThe array to flatten.
opts
Type: Plain object
Obligatory: no
Default:
optsPlain objectnoOptional Options Object, the same one flattenReferencing() takes.
wrap
Type: Boolean
Obligatory: no
Default: false
wrapBooleannofalseSet to true to wrap each value with opts.wrapHeadsWith/opts.wrapTailsWith.
joinArraysUsingBrs
Type: Boolean
Obligatory: no
Default: false
joinArraysUsingBrsBooleannofalseSet to true to join with <br /> (honouring opts.mergeArraysWithLineBreaks and opts.xhtml) instead of a single space.
import { flattenArr } from "object-flatten-referencing";

console.log(flattenArr(["a", "b"], { wrapHeadsWith: "{{ ", wrapTailsWith: " }}" }, true));
// => "{{ a }} {{ b }}"

console.log(flattenArr(["a", "b"], {}, false, true));
// => "a<br />b"

API — arrayiffy()

This package re-exports arrayiffy from arrayiffy-if-string, so that consumers already importing from here don’t need a second dependency to normalise the string-or-array options:

import { arrayiffy } from "object-flatten-referencing";

console.log(arrayiffy("a"));
// => ["a"]

API — defaults

You can import defaults:

It's a plain object:

The main function calculates the options to be used by merging the options you passed with these defaults.

API — version

You can import version:

API — types

This package is written in TypeScript and exports the type Opts, the Optional Options Object documented above:

import type { Opts } from "object-flatten-referencing";

The algorithm

In its core, this library uses two functions:

  • one which flattens objects
  • another which flattens arrays

Objects are flattened into arrays (yes, not strings) in the following fashion:

// from:
{
  a: 'b',
  c: 'd'
}
// to:
['%%_a.b_%%', '%%_c.d_%%']

Arrays are flattened into strings:

// from:
["a", "b", "c"];
// to:
("%%_a_%%<br />%%_b_%%<br />%%_c_%%");

This library recursively traverses both inputs, compares their types and if one type is lesser in the food chain (object vs. string), it uses the above functions to flatten all mismatching elements into strings.

In practice

In practice, this library is used to map the variables in email templates.

For example, your data content file in JSON (development version) that controls your template is:

// data file:
{
  "title": "Welcome",
  "name": "John"
}

but you need to turn it into the following when generating PROD version:

// you want your data file to look like this after processing:
{
  "title": "Welcome",
  "name": "${object.name}"
}

To achieve that, you use another JSON mapping file,

// mapping file:
{
  "name": {
    "object": "name"
  }
}

It’s easy to merge the mapping file onto the data file, but you get:

// intermediate data file after merging the mapping file over data file
{
  "title": "Welcome",
  "name": {
    "object": "name"
  }
}

Now you need to flatten the above object, so that the key called name has a value of string type, not object. This library helps to achieve that:

const mergedDataFile = {
  title: "Welcome",
  name: {
    object: "name",
  },
};
const reference = {
  title: "Welcome",
  name: "John",
};
mergedDataFile = flattenReferencing(mergedDataFile, reference, {
  wrapHeadsWith: "${",
  wrapTailsWith: "}",
});
console.log(JSON.stringify(mergedDataFile, null, 4));
// => {
//      "title": "Welcome",
//      "name": "${object.name}"
//    }

Voilà!

Changelog

Open Changelog
↑ back to top
prev next

Copyright

All rights reserved © Roy Revelt 2026
All our open source packages are under MIT licenceopens in a new tab

Activities

🐛 See a bug? Raise an issueopens in a new tab
💘 Check out the Indiewebopens in a new tab and Libera manifestoopens in a new tab