Course outline
Full-Stack course / JavaScript fundamentals

Round-trip config through text

Lab

How to fetch and submit this exercise

Once: install the tool and connect your account.

curl -fsSL https://gonomicon.com/install.sh | sh
gonomicon login

Each exercise: download it, edit the file named in the instructions, then submit.

gonomicon fetch fs-week-2/03-07-roundtrip-config-text
cd 03-07-roundtrip-config-text
gonomicon submit

The runner depends on the exercise: JavaScript/TypeScript/React labs run with Vitest, Python labs with pytest, and config-file labs (Docker, CI, Terraform, Nginx) are checked by parsing your file. gonomicon test runs the visible checks on your computer first; submitting also runs the hidden checks on our server.

Round-trip config through text

Write functions that save an app configuration object to text and load it back, plus a checker that tells you whether anything was lost along the way.

Worked example

Here's the same save/load pair for a shopping cart:

const cart = {
  items: ["pen", "notebook"],
  discountCode: undefined,
  customer: { name: "Jess", loyalty: { points: 120, tier: "gold" } },
};

function toSavedText(cart) {
  return JSON.stringify(cart);
}

function fromSavedText(text) {
  return JSON.parse(text);
}

const text = toSavedText(cart);
console.log(text);

const restored = fromSavedText(text);
console.log(restored);
console.log(Object.keys(cart).length, Object.keys(restored).length);
console.log(restored.customer.loyalty.tier);
{"items":["pen","notebook"],"customer":{"name":"Jess","loyalty":{"points":120,"tier":"gold"}}}
{
  items: [ 'pen', 'notebook' ],
  customer: { name: 'Jess', loyalty: { points: 120, tier: 'gold' } }
}
3 2
gold

cart started with three top-level fields, but discountCode was undefined, and JSON.stringify() quietly left it out of the saved text - so restored only has two fields, not three. Everything else, even three levels deep (customer.loyalty.tier), came back exactly as it was. That gap between 3 and 2 is the thing your roundTrips function needs to notice and report.

Your task

Write function toSavedText(config). Return JSON.stringify(config).

Write function fromSavedText(text). Return JSON.parse(text).

Write function roundTrips(config). Return true only if fromSavedText(toSavedText(config)) is deeply equal to config - same fields, same nested values, all the way down - and false if anything differs, including a field that vanished because its value was undefined.

Rules

  • roundTrips must check equality all the way through nested objects and arrays, not just the top level.
  • A field present in config with the value undefined makes roundTrips return false, because that field won't exist in the restored copy at all.
  • Two values only count as equal if they're the same type - a number and a numeric-looking string are not interchangeable.
  • roundTrips doesn't change the config object it was given.

What you'll practice

Using JSON.stringify and JSON.parse to move data to text and back, and writing your own equality check that walks a nested structure using a loop and a work list, instead of trusting a shortcut that wouldn't catch a silently dropped field.

Run it

gonomicon fetch fs-week-2/03-07-roundtrip-config-text
cd 03-07-roundtrip-config-text
gonomicon test
gonomicon submit

Hints

  1. toSavedText and fromSavedText are each one line - JSON.stringify and JSON.parse do the whole job.
  2. For roundTrips, don't write a function that calls itself - instead keep an array you use as a work list of [originalValue, resultValue] pairs still waiting to be checked, and push() the nested pairs you discover onto it as you go, popping one off each time through a loop.
  3. When you pop a pair: if they're already === equal, move on. Otherwise compare typeof and Array.isArray on both sides first. For two plain objects, Object.keys(x).length must match a Set built from Object.keys(y) (and every one of x's keys must be in that Set) before you push each matching pair of values onto the work list; for two arrays, compare .length first, then push each index's pair.