🧰 Essentials | Package exports - traced-fabric/core GitHub Wiki

📜 Table of contents

🛠️ Basic functions

🔧 traceFabric(...)

Track the mutation of a given JSON-like object or array. Other tracedFabric can be nested inside.

The trace (array of mutations), that is produced by the tracedFabric on values mutation, can be used to apply them to other objects or arrays, using the applyTrace(...) function.

Arguments

  • value - an object or array that will be deeply tracked. Value is JSON.stringify safe. The type of the value should be the same as JSONStructure.
  • onMutation optional - a function that is triggered when the traced value is mutated. The function receives the mutation as an argument and should return the mutation to be saved to the trace. If no modification is needed, return the original mutation; otherwise, return the modified mutation for storage.

Returns

Object with the following properties:

  • value - the traced proxy of the given value.
  • trace - the array of mutations that are made to the value.
  • clearTrace - a function that clears the trace.

Example

const bestDays = traceFabric([2, 7, 16]);
const fabric = traceFabric({
  season: 'winter',
  bestDays: bestDays.value,
});

fabric.value.season = 'summer';
fabric.value.bestDays.push(25);
bestDays.value.push(26);

console.log(fabric.trace);
// [{
//   mutated: 'object', type: 'set',
//   targetChain: ['season'],
//   value: 'summer',
// }, {
//   mutated: 'array', type: 'set',
//   targetChain: ['bestDays', 3],
//   value: 25,
// }, {
//   mutated: 'array', type: 'set',
//   targetChain: ['bestDays', 4],
//   value: 26,
// }]

With the custom onMutation function, that adds a timestamp to the mutation.

const bestDays = traceFabric([2, 7, 16]);
const fabric = traceFabric({
  season: 'winter',
  bestDays: bestDays.value,
}, mutation => ({
  ...mutation,
  timestamp: Date.now(),
}));

fabric.value.season = 'summer';
fabric.value.bestDays.push(25);
bestDays.value.push(26);

console.log(fabric.trace);
// [{
//   mutated: 'object',
//   targetChain: ['season'],
//   value: 'summer',
//   type: 'set',
//   timestamp: 1725368703427,
// }, {
//   mutated: 'array',
//   targetChain: ['bestDays', 3],
//   value: 25,
//   type: 'set',
//   timestamp: 1725368703428,
// }, {
//   mutated: 'array',
//   targetChain: ['bestDays', 4],
//   value: 26,
//   type: 'set',
//   timestamp: 1725368703428,
// }]

🔧 applyTrace(...)

Applies tracedFabric mutations to the given value. The value should have the same state as the traceFabric value before allied mutations.

[!WARNING] This function mutates the value directly.

Arguments

  • value - the object to which the trace will be directly applied.
  • trace - the trace (array of mutations) to apply to the given value.

Example

const fabric = traceFabric({
  season: 'winter',
  besetDays: [12, 15, 17],
});
const target = {
  season: 'winter',
  besetDays: [12, 15, 17],
};

target.season = 'summer';
target.besetDays.push(20);

applyTrace(target, fabric.trace);

console.log(target);
// {
//   season: "summer",
//   besetDays: [ 12, 15, 17, 20 ],
// }

🔧 deepClone(...)

Deep clone an object or array.

Primarily used to clone tracedFabric and tracedValues without inheriting proxy traps, and potentially breaking tracedFabric.

[!NOTE] deepClone(...) will not copy symbols

Arguments

  • value - The value to clone

Returns

The cloned value

Example

const fabric = traceFabric({ season: 'winter', bestDays: [2, 7, 16] });
const clone = deepClone(fabric.value);

console.log(clone); // { season: 'winter', bestDays: [2, 7, 16] }
console.log(clone === fabric.value); // false
console.log(clone.bestDays === fabric.value.bestDays); // false

🛠️ Utility functions

🪛 isStructure(...)

Checks if the value is a typeof object and not null.

Arguments

  • value - value that needs to be checked

Returns

Boolean

Example

console.log(isStructure({ hello: 'world' })); // true
console.log(isStructure(['hello', 'world'])); // true

console.log(isStructure(1)); // false
console.log(isStructure(true)); // false
console.log(isStructure('hello')); // false
console.log(isStructure(null)); // false
console.log(isStructure(undefined)); // false
console.log(isStructure(true)); // false

🪛 isTracedFabric(...)

Checks if the given value is a tracedFabric.

To check the definition of tracedFabric, see Wiki - 📜 Naming

Arguments

  • value - value that needs to be checked

Returns

Boolean

Example

const traced = traceFabric({ // --> tracedFabric AND traced
  innerArray: [1, 2, 3], // --> tracedValue AND traced
});

console.log(isTracedFabric(traced.value)); // true
console.log(isTracedFabric(traced.value.innerArray)); // false

🪛 isTracedValue(...)

Checks if the given value is a tracedValue.

To check the definition of tracedValue, see Wiki - 📜 Naming

Arguments

  • value - value that needs to be checked

Returns

Boolean

Example

const traced = traceFabric({ // --> tracedFabric AND traced
  innerArray: [1, 2, 3], // --> tracedValue AND traced
});

console.log(isTracedValue(traced.value)); // false
console.log(isTracedValue(traced.value.innerArray)); // true

🪛 isTraced(...)

Checks if the given value is a traced.

To check the definition of traced, see Wiki - 📜 Naming

Arguments

  • value - value that needs to be checked

Returns

Boolean

Example

const traced = traceFabric({ // --> tracedFabric AND traced
  innerArray: [1, 2, 3], // --> tracedValue AND traced
});

console.log(isTraced(traced.value)); // true
console.log(isTraced(traced.value.innerArray)); // true

🪛 withoutTracing(...)

Ignores recording of all mutations to trace in the given function. The function should not be async, as it turns off the tracing globally.

[!WARNING] Use with caution, as it can lead to breaking applyTrace function, because of the missing mutations.

Arguments

  • callback - function in which tracing is disabled

Returns

Same as the return value of the given function

Example

const fabric = traceFabric({ season: 'winter' });

fabric.value.season = 'spring'; // adds mutation to the traceLogs
withoutTracing(() => {
  fabric.value.season = 'summer'; // no mutation is added to the traceLogs
});

console.log(fabric.trace);
// [{
//   mutated: "object",
//   targetChain: [ "season" ],
//   value: "spring",
//   type: "set",
// }]

🪛 isTracing(...)

Check if tracing is enabled. If the tracing is enabled, the mutations are recorded in the trace.

Returns

Boolean

Example

console.log(isTracing()); // true

withoutTracing(() => {
  console.log(isTracing()); // false
});

🛠️ Miscellaneous

🪛 removeTraceSubscription(...)

Will unsubscribe the receiver from the sender. So after mutating the sender, the receiver will not receive any updates.

Needs to be used to speed up garbage collection.

Arguments

  • changesSender - the sender of the updates (value that is a part of the receiver).
  • changesReceiver - receiver of the updates.

Same as the return value of the given function

Example

const globalMessages = traceFabric(['Welcome!']);

function userLifecycle(): void {
  const user = traceFabric({
    globalMessages: globalMessages.value,
  });

  // The `globalMessages` subscribes to the `user` value to send updates.
  // To speed up the gc, remove the subscription, at the end of the `user` lifecycle.
  removeTraceSubscription(globalMessages.value, user.value);
}