### Install Structura.js via NPM Source: https://github.com/giusepperaso/structura.js/blob/master/docs/getting-started.md Install the library using npm for Node.js projects. ```bash npm i structurajs ``` -------------------------------- ### Run Development Server Source: https://github.com/giusepperaso/structura.js/blob/master/CONTRIBUTING.md Starts the development server to run the library in the browser. Requires creating and renaming a 'src/dev.ts' file from 'src/dev.example.ts'. ```bash npm run dev ``` -------------------------------- ### Install Volta Source: https://github.com/giusepperaso/structura.js/blob/master/CONTRIBUTING.md Installs Volta, a tool for managing Node.js versions, using a curl command. ```bash curl https://get.volta.sh | bash ``` -------------------------------- ### Basic Structura.js Usage Example Source: https://github.com/giusepperaso/structura.js/blob/master/docs/getting-started.md Demonstrates how to use the `produce` function to immutably update an object. Ensure the library is imported or available globally. ```typescript import { produce } from "structurajs" const ciao = { ciao: "mondo", test: { test: 1 } } const hello = produce(ciao, (draft) => { delete draft.ciao; draft.hello = "world"; }) console.assert(ciao !== hello, "the two objects are different"); console.assert(ciao.test === hello.test, "the two objects are the same"); ``` -------------------------------- ### Transpositions - Working Examples Source: https://github.com/giusepperaso/structura.js/blob/master/docs/edge-cases.md Demonstrates how to reassign keys of sub-objects within the draft, allowing for structural changes. This includes swapping elements in an array and modifying them. ```typescript const state = [[1], [2]] // this works well const newState1 = produce(state, (draft) => { const first = draft[0] draft[0] = draft[1] draft[1] = first }) ``` ```typescript // this also works const newState2 = produce(state, (draft) => { const first = draft[0] draft[0] = draft[1] draft[1] = first first.push(9999) }) ``` -------------------------------- ### Multiple References to the Same Object - Working Examples Source: https://github.com/giusepperaso/structura.js/blob/master/docs/edge-cases.md Shows how Structura.js correctly handles state where multiple properties reference the same object. Modifications to one reference are reflected in others when accessed appropriately. ```typescript const array = [1] const state = { test1: array, test2: array } // this works well const newState1 = produce(state, (draft) => { draft.test1.push(1) draft.test2.push(1) }) ``` ```typescript // this also works const newState2 = produce(state, (draft) => { draft.test1; draft.test2.push(1) }) ``` ```typescript // ...but this works const newState4 = produce(state, (draft) => { draft.test2.push(1) draft.test1 = draft.test1; }) ``` -------------------------------- ### Using asyncProduce for Asynchronous Object Updates Source: https://github.com/giusepperaso/structura.js/blob/master/docs/async.md Import and use `asyncProduce` for asynchronous operations within producers. This example demonstrates updating an object after a simulated delay. ```typescript import { asyncProduce } from "structurajs" const myObj = { t: 1 } const waitForIt = asyncProduce(myObj, async (draft) => { await new Promise((r) => setTimeout(r, 1000)) return { t: 2 } }) waitForIt.then((result) => { console.log(result) // { t: 2 } }) ``` -------------------------------- ### Multiple References to the Same Object - Non-Working Examples Source: https://github.com/giusepperaso/structura.js/blob/master/docs/edge-cases.md Highlights scenarios with multiple object references where modifications might not propagate as expected if certain access patterns are not followed. This is often due to how the draft is traversed. ```typescript // this does not work well because test1 will not reflect the modifications... const newState3 = produce(state, (draft) => { draft.test2.push(1) draft.test1; }) ``` ```typescript // this does not work well because test2 is never accessed, // so test2 will remain the same as before const newState5 = produce(state, (draft) => { draft.test1.push(1) }) ``` -------------------------------- ### Get all data associated with a draft Source: https://github.com/giusepperaso/structura.js/blob/master/docs/helpers.md Use `allData` to get a map of all data associated with the entire draft. The map keys are original objects, and values contain shallow clone information. ```typescript produce({ n: 1 }, (draft) => { target(draft) === allData(draft).get(original(draft)).shallow // false draft.n++; target(draft) === allData(draft).get(original(draft)).shallow // true }) ``` -------------------------------- ### Transpositions - Non-Working Example Source: https://github.com/giusepperaso/structura.js/blob/master/docs/edge-cases.md Illustrates a scenario where reassignment within the draft does not yield the expected results, specifically when creating a new object external to the draft's direct structure. ```typescript // this does not work well because the new object // will remain with a proxy attached via its prop const newState3 = produce(state, (draft) => { const first = draft[0] const newObj = { prop: first } draft.push(newObj as any) }) ``` -------------------------------- ### Get a snapshot of the current state Source: https://github.com/giusepperaso/structura.js/blob/master/docs/helpers.md The `snapshot` function provides a deep clone of the current draft state, similar to Immer's `current`. It is intended for debugging due to its performance cost. ```typescript produce({ n: 1 }, (draft) => { const saved = snapshot(draft) draft.n++; console.log(draft.n); // 2 console.log(saved.n); // 1 }) ``` -------------------------------- ### Get the original object from a draft Source: https://github.com/giusepperaso/structura.js/blob/master/docs/helpers.md Use `original` to retrieve the original, unmodified object from a draft or a portion of a draft. This is useful for comparing values before and after modifications. ```typescript produce({ n: 1, sub: { n:1 } }, (draft) => { draft.n++; draft.sub.n++; original(draft).n === 1; // true original(draft.sub).n === 1; // true }) ``` -------------------------------- ### Get item data from a draft Source: https://github.com/giusepperaso/structura.js/blob/master/docs/helpers.md The `itemData` helper retrieves data associated with a draft portion. It returns an object with a `shallow` property, indicating if the target is a shallow clone. ```typescript produce({ n: 1 }, (draft) => { target(draft) === itemData(draft).shallow // false draft.n++; target(draft) === itemData(draft).shallow // true }) ``` -------------------------------- ### Get the target object of a draft Source: https://github.com/giusepperaso/structura.js/blob/master/docs/helpers.md The `target` function returns the shallow cloned object if modifications occurred at that level, otherwise it returns the original object. This helps in identifying if a specific level of the draft was altered. ```typescript produce({ n: 1 }, (draft) => { target(draft) === original(draft) // true draft.n++; target(draft) === original(draft) // false original(draft).n === 1 // true target(draft).n === 2 // true }) ``` -------------------------------- ### Implicit Type Coercion Error in Structura.js Source: https://github.com/giusepperaso/structura.js/blob/master/docs/gotchas.md Without explicit type declarations, Structura.js may accept incorrect assignments, leading to unexpected results. This example shows a number being assigned where an object might have been intended. ```typescript const state = { test: 1 } // this is accepted, but it's wrong! // result will be 2 (the number assigned), but we probably wanted an object instead // (we likely forgot to wrap our function in curly brackets) const result = produce(state, (draft) => draft.test = 2) ``` -------------------------------- ### Run Benchmarks Source: https://github.com/giusepperaso/structura.js/blob/master/CONTRIBUTING.md Executes the project's benchmarks, generating screenshots and copying benchmark files to the docs folder. ```bash npm run benchmark ``` -------------------------------- ### Run Tests Source: https://github.com/giusepperaso/structura.js/blob/master/CONTRIBUTING.md Executes the test suite for the project, which also generates code coverage reports. ```bash npm run test ``` -------------------------------- ### Initialize and Configure Chart.js Bar Chart Source: https://github.com/giusepperaso/structura.js/blob/master/docs/public/benchmark/small_few.chart.html Sets up a Chart.js bar chart with specific data, styling, and tooltip callbacks for performance benchmarking. Ensure a canvas element with id 'chart1674500879005' exists in the HTML. ```javascript const ctx1674500879005 = document .getElementById('chart1674500879005') .getContext('2d') const chart1674500879005 = new Chart(ctx1674500879005, { type: 'bar', data: { labels: ["STRUCTURA (no strict copy)","STRUCTURA (with strict copy)","IMMER (no auto freeze)","IMMER (with auto freeze)","IMMUTABLE (no toJS)","IMMUTABLE (with toJS)"], datasets: [ { data: [1179869,432648,188285,173182,1959095,1764755], backgroundColor: ["hsl(72.276, 85%, 55%)","hsl(26.496, 85%, 55%)","hsl(11.531999999999998, 85%, 55%)","hsl(10.608000000000004, 85%, 55%)","hsl(120, 85%, 55%)","hsl(108.09599999999999, 85%, 55%)"], borderColor: ["hsl(72.276, 85%, 55%)","hsl(26.496, 85%, 55%)","hsl(11.531999999999998, 85%, 55%)","hsl(10.608000000000004, 85%, 55%)","hsl(120, 85%, 55%)","hsl(108.09599999999999, 85%, 55%)"], borderWidth: 2, }, ], }, options: { maintainAspectRatio: false, plugins: { title: { display: true, text: 'Produce small object with few modications', font: { size: 20 }, padding: 20, }, legend: { display: false, }, tooltip: { callbacks: { label: (context) => { return format(context.parsed.y) + ' ops/s' }, }, displayColors: false, backgroundColor: '#222222', padding: 10, cornerRadius: 5, intersect: false, }, }, scales: { x: { grid: { color: '#888888', }, }, y: { title: { display: true, text: 'Operations per second', padding: 10, }, grid: { color: '#888888', }, }, }, }, }) ``` -------------------------------- ### Configure Bar Chart for Performance Benchmark Source: https://github.com/giusepperaso/structura.js/blob/master/docs/public/benchmark/small_many.chart.html Initializes a bar chart to display performance benchmark results. It configures chart data, labels, colors, and tooltip callbacks for better data visualization. Use this to compare the performance of different JavaScript immutability libraries. ```javascript const ctx1674500911582 = document.getElementById('chart1674500911582').getContext('2d') const chart1674500911582 = new Chart(ctx1674500911582, { type: 'bar', data: { labels: ["STRUCTURA (no strict copy)","STRUCTURA (with strict copy)","IMMER (no auto freeze)","IMMER (with auto freeze)","IMMUTABLE (no toJS)","IMMUTABLE (with toJS)"], datasets: [ { data: [217162,160767,112527,108238,527133,512760], backgroundColor: ["hsl(49.440000000000005, 85%, 55%)","hsl(36.6, 85%, 55%)","hsl(25.619999999999994, 85%, 55%)","hsl(24.636000000000003, 85%, 55%)","hsl(120, 85%, 55%)","hsl(116.724, 85%, 55%)"], borderColor: ["hsl(49.440000000000005, 85%, 55%)","hsl(36.6, 85%, 55%)","hsl(25.619999999999994, 85%, 55%)","hsl(24.636000000000003, 85%, 55%)","hsl(120, 85%, 55%)","hsl(116.724, 85%, 55%)"], borderWidth: 2, }, ], }, options: { maintainAspectRatio: false, plugins: { title: { display: true, text: 'Produce small object with many modifications', font: { size: 20, }, padding: 20, }, legend: { display: false, }, tooltip: { callbacks: { label: (context) => { return format(context.parsed.y) + ' ops/s' }, }, displayColors: false, backgroundColor: '#222222', padding: 10, cornerRadius: 5, intersect: false, }, }, scales: { x: { grid: { color: '#888888', }, }, y: { title: { display: true, text: 'Operations per second', padding: 10, }, grid: { color: '#888888', }, }, }, }, }) ``` -------------------------------- ### Manual Immutable State Update Source: https://github.com/giusepperaso/structura.js/blob/master/docs/why-structura.md Demonstrates a manual approach to updating immutable state using the spread syntax. This method is fast but can become verbose and difficult to maintain for complex states. ```javascript const state = { sub: { prop1: 1 } } // this is fast and native, but it may become hard to read and mantain // very quickly if we have to do complex operations in the future const newState = { sub: { ...state.sub, prop2: 2 } } console.log(newState); ``` -------------------------------- ### Chart Configuration for Nested Object Benchmarks Source: https://github.com/giusepperaso/structura.js/blob/master/docs/public/benchmark/nested_few.chart.html This code configures a bar chart to display benchmark results. It includes data, labels, and custom options for tooltips and scales. The tooltip callback formats the y-axis values to show 'ops/s'. ```javascript const format = (num) => { const [whole, fraction] = String(num).split('.') const chunked = [] whole .split('') .reverse() .forEach((char, index) => { if (index % 3 === 0) { chunked.unshift([char]) } else { chunked[0].unshift(char) } }) const fractionStr = fraction !== undefined ? '.' + fraction : '' return ( chunked.map((chunk) => chunk.join('')).join(' ') + fractionStr ) } const ctx1674500824738 = document .getElementById('chart1674500824738') .getContext('2d') const chart1674500824738 = new Chart(ctx1674500824738, { type: 'bar', data: { labels: ["STRUCTURA (no strict copy)","STRUCTURA (with strict copy)","IMMER (no auto freeze)","IMMUTABLE (no toJS)"], datasets: [ { data: [8938,8352,7094,8152], backgroundColor: ["hsl(120, 85%, 55%)","hsl(112.128, 85%, 55%)","hsl(95.24400000000001, 85%, 55%)","hsl(109.45200000000001, 85%, 55%)"], borderColor: ["hsl(120, 85%, 55%)","hsl(112.128, 85%, 55%)","hsl(95.24400000000001, 85%, 55%)","hsl(109.45200000000001, 85%, 55%)"], borderWidth: 2, }, ], }, options: { maintainAspectRatio: false, plugins: { title: { display: true, text: 'Produce nested object with few modifications', font: { size: 20, }, padding: 20, }, legend: { display: false, }, tooltip: { callbacks: { label: (context) => { return format(context.parsed.y) + ' ops/s' }, }, displayColors: false, backgroundColor: '#222222', padding: 10, cornerRadius: 5, intersect: false, }, }, scales: { x: { grid: { color: '#888888', }, }, y: { title: { display: true, text: 'Operations per second', padding: 10, }, grid: { color: '#888888', }, }, }, }, }) ``` -------------------------------- ### Include Structura.js via CDN Source: https://github.com/giusepperaso/structura.js/blob/master/docs/getting-started.md Include the library in your HTML using a script tag for direct browser usage. ```html ``` -------------------------------- ### Bar Chart Configuration for Benchmarks Source: https://github.com/giusepperaso/structura.js/blob/master/docs/public/benchmark/nested_many.chart.html Configures a Chart.js bar chart to display performance benchmark results. Includes custom tooltips for operations per second and formatted labels. ```javascript const ctx1674500846136 = document.getElementById('chart1674500846136').getContext('2d') const chart1674500846136 = new Chart(ctx1674500846136, { type: 'bar', data: { labels: ["STRUCTURA (no strict copy)","STRUCTURA (with strict copy)","IMMER (no auto freeze)","IMMUTABLE (no toJS)"], datasets: [ { data: [6316,4331,3353,3402], backgroundColor: ["hsl(120, 85%, 55%)","hsl(82.28399999999999, 85%, 55%)","hsl(63.708000000000006, 85%, 55%)","hsl(64.63199999999999, 85%, 55%)"], borderColor: ["hsl(120, 85%, 55%)","hsl(82.28399999999999, 85%, 55%)","hsl(63.708000000000006, 85%, 55%)","hsl(64.63199999999999, 85%, 55%)"], borderWidth: 2, }, ], }, options: { maintainAspectRatio: false, plugins: { title: { display: true, text: 'Produce nested object with many modifications', font: { size: 20, }, padding: 20, }, legend: { display: false, }, tooltip: { callbacks: { label: (context) => { return format(context.parsed.y) + ' ops/s' }, }, displayColors: false, backgroundColor: '#222222', padding: 10, cornerRadius: 5, intersect: false, }, }, scales: { x: { grid: { color: '#888888', }, }, y: { title: { display: true, text: 'Operations per second', padding: 10, }, grid: { color: '#888888', }, }, }, }, }) ``` -------------------------------- ### Structura.js State Update Source: https://github.com/giusepperaso/structura.js/blob/master/docs/why-structura.md Demonstrates state updates with Structura.js, offering a syntax similar to Immer.js but with significantly higher performance, up to ~10x faster. ```javascript const state = { sub: { prop1: 1 } } // this example, despite being indistinguishable from the immer one, // is ~10x more performant! const newState = produce(state, (draft) => { draft.sub.prop2 = 2 }) ``` -------------------------------- ### Immer.js State Update Source: https://github.com/giusepperaso/structura.js/blob/master/docs/why-structura.md Shows how to update state using Immer.js, which provides a readable mutable syntax. However, Immer.js can be significantly slower than other solutions in real-world scenarios. ```javascript const state = { sub: { prop1: 1 } } // this is easy to read and write, but unfortunately it has usually worse // performance than the previous methods const newState = produce(state, (draft) => { draft.sub.prop2 = 2 }) ``` -------------------------------- ### Run Benchmarks Only Source: https://github.com/giusepperaso/structura.js/blob/master/CONTRIBUTING.md Executes only the project's benchmarks without additional operations like generating screenshots or copying files. ```bash npm run benchmark:only ``` -------------------------------- ### Immutable.js State Update Source: https://github.com/giusepperaso/structura.js/blob/master/docs/why-structura.md Illustrates state updates using Immutable.js. While Immutable.js offers good base performance, conversions to and from plain JavaScript objects can be slow, and it uses a proprietary syntax. ```javascript const state = { sub: { prop1: 1 } } // this is very slow const newState = fromJS(state) // this is fast, but uses a proprietary syntax newState.set(['sub','prop2'], 2); // this is very slow console.log(newState.toJS()); ``` -------------------------------- ### Using the freeze utility Source: https://github.com/giusepperaso/structura.js/blob/master/docs/freezing.md Illustrates the `freeze` utility from Structura.js. It can freeze at compile time by default, or at both runtime and compile time when the second argument is `true`. Runtime freezing attempts will throw exceptions. ```typescript import { freeze } from "structurajs"; const frozen_at_compile_time = freeze(newState); frozen_at_compile_time.push(5) // DOESN'T COMPILE //@ts-ignore frozen_at_compile_time.push(5) // it works const frozen_at_both_run_and_compile_time = freeze(newState, true); frozen_at_both_run_and_compile_time.push(5) // DOESN'T COMPILE //@ts-ignore frozen_at_compile_time.push(5) // WILL THROW AN EXCEPTION AT RUNTIME ``` -------------------------------- ### Compile-Time Freezing with TypeScript Source: https://github.com/giusepperaso/structura.js/blob/master/docs/freezing.md Demonstrates how to use TypeScript's `Freeze` type to ensure state is frozen at compile time. Attempts to mutate frozen state will result in compilation errors. ```typescript // freezing this way is unecessary, unless you want to be sure // that also the initial state is frozen const state = [1, 2, 3] as Freeze state.push(4) // DOESN'T COMPILE // newState gets automatically frozen const newState = produce(state, (draft) => { draft.push(4) }) newState.push(5) // DOESN'T COMPILE ``` -------------------------------- ### Chart.js Bar Chart Configuration Source: https://github.com/giusepperaso/structura.js/blob/master/docs/public/benchmark/wide_few.chart.html Configures a bar chart to display benchmark results. It includes data, labels, and customizable options for tooltips, titles, and axes. Use this snippet to visualize performance metrics from different libraries. ```javascript const format = (num) => { const [whole, fraction] = String(num).split('.') const chunked = [] whole .split('') .reverse() .forEach((char, index) => { if (index % 3 === 0) { chunked.unshift([char]) } else { chunked[0].unshift(char) } }) const fractionStr = fraction !== undefined ? '.' + fraction : '' return ( chunked.map((chunk) => chunk.join('')).join(' ') + fractionStr ) } const ctx1674500944728 = document .getElementById('chart1674500944728') .getContext('2d') const chart1674500944728 = new Chart(ctx1674500944728, { type: 'bar', data: { labels: ["STRUCTURA (no strict copy)","STRUCTURA (with stict copy)","IMMER (no auto freeze)","IMMER (with auto freeze)","IMMUTABLE (no toJS)","IMMUTABLE (with toJS)"], datasets: [ { data: [188,63,38,27,154,65], backgroundColor: ["hsl(120, 85%, 55%)","hsl(40.21200000000001, 85%, 55%)","hsl(24.251999999999995, 85%, 55%)","hsl(17.232, 85%, 55%)","hsl(98.29199999999999, 85%, 55%)","hsl(41.483999999999995, 85%, 55%)"], borderColor: ["hsl(120, 85%, 55%)","hsl(40.21200000000001, 85%, 55%)","hsl(24.251999999999995, 85%, 55%)","hsl(17.232, 85%, 55%)","hsl(98.29199999999999, 85%, 55%)","hsl(41.483999999999995, 85%, 55%)"], borderWidth: 2, }, ], }, options: { maintainAspectRatio: false, plugins: { title: { display: true, text: 'Produce wide object with few modifications', font: { size: 20 }, padding: 20, }, legend: { display: false, }, tooltip: { callbacks: { label: (context) => { return format(context.parsed.y) + ' ops/s' }, }, displayColors: false, backgroundColor: '#222222', padding: 10, cornerRadius: 5, intersect: false, }, }, scales: { x: { grid: { color: '#888888', }, }, y: { title: { display: true, text: 'Operations per second', padding: 10, }, grid: { color: '#888888', }, }, }, }, }) ``` -------------------------------- ### Deep Freezing with freeze utility Source: https://github.com/giusepperaso/structura.js/blob/master/docs/freezing.md Shows how to use the `freeze` utility with the `deep` option set to `true` (along with runtime freezing) to recursively freeze nested objects. Attempting to mutate deeply nested properties will throw a runtime exception. ```typescript const state = { sub: { n: 1 } }; const frozen = freeze(state, true, true); (frozen as any).sub.n++; // WILL THROW AN EXCEPTION AT RUNTIME ``` -------------------------------- ### Enable Standard JSON Patches Source: https://github.com/giusepperaso/structura.js/blob/master/docs/settings.md Activates the use of standard JSON patches instead of Structura's proprietary format. Call with `true` to enable and `false` to disable. ```typescript import { enableStandardPatches } from "structurajs"; enableStandardPatches(true); ``` ```typescript enableStandardPatches(false); ``` -------------------------------- ### Generate Patches with produceWithPatches Source: https://github.com/giusepperaso/structura.js/blob/master/docs/patches.md Utilize `produceWithPatches` for a more concise way to obtain the modified result, patches, and inverse patches in a single operation. ```typescript type Make = () => Record[] const makeObj: Make = () => [{ A: 1 }]; // first we get the result and the patches const [result, patches, inverse] = produceWithPatches(makeObj(), (draft) => { draft.push({ B: 2 }); }); // if we apply the patches from the same starting point, we get the same result const newResult = applyPatches(makeObj(), patches); expect(newResult).toEqual(result); // then, if we apply the inverse patches, we obtain the original state const undone = applyPatches(newResult, inverse); expect(undone).toEqual(makeObj()); ``` -------------------------------- ### Convert Structura patches to standard JSON Patches Source: https://github.com/giusepperaso/structura.js/blob/master/docs/helpers.md The `convertPatchesToStandard` helper transforms Structura's generated patches into the standard JSON Patch format. It can output paths as arrays or slash-separated strings. ```typescript const state = { sub: { n: 1 } }; const [_, patches] = produceWithPatches({ sub: { n: 1 } }, (draft) => { draft.sub.n++; }) const json_patches_arr_path = convertPatchesToStandard(patches) // [{ op: "replace", path: ["sub", "n"], value: 2 }] const json_patches_str_path = convertPatchesToStandard(patches, false) // [{ op: "replace", path: "/sub/n", value: 2 }] applyPatches(state, json_patches_arr_path).sub.n === 2 // true applyPatches(state, json_patches_str_path).sub.n === 2 // true ``` -------------------------------- ### JavaScript Chart Configuration Source: https://github.com/giusepperaso/structura.js/blob/master/docs/public/benchmark/wide_many.chart.html Configures a bar chart with custom data, styling, and interactive tooltips. The 'format' function is used to display large numbers in a human-readable format within the tooltips. ```javascript const format = (num) => { const [whole, fraction] = String(num).split('.') const chunked = [] whole .split('') .reverse() .forEach((char, index) => { if (index % 3 === 0) { chunked.unshift([char]) } else { chunked[0].unshift(char) } }) const fractionStr = fraction !== undefined ? '.' + fraction : '' return ( chunked.map((chunk) => chunk.join('')).join(' ') + fractionStr ) } const ctx1674500977646 = document .getElementById('chart1674500977646') .getContext('2d') const chart1674500977646 = new Chart(ctx1674500977646, { type: 'bar', data: { labels: ["STRUCTURA (no strict copy)","STRUCTURA (with strict copy)","IMMER (no auto freeze)","IMMER (with auto freeze)","IMMUTABLE (no toJS)","IMMUTABLE (with toJS)"], datasets: [ { data: [182,63,30,28,159,66], backgroundColor: ["hsl(120, 85%, 55%)","hsl(41.54400000000001, 85%, 55%)","hsl(19.776000000000003, 85%, 55%)","hsl(18.455999999999996, 85%, 55%)","hsl(104.83200000000001, 85%, 55%)","hsl(43.512, 85%, 55%)"], borderColor: ["hsl(120, 85%, 55%)","hsl(41.54400000000001, 85%, 55%)","hsl(19.776000000000003, 85%, 55%)","hsl(18.455999999999996, 85%, 55%)","hsl(104.83200000000001, 85%, 55%)","hsl(43.512, 85%, 55%)"], borderWidth: 2, }, ], }, options: { maintainAspectRatio: false, plugins: { title: { display: true, text: 'Produce wide object with many modifications', font: { size: 20 }, padding: 20, }, legend: { display: false, }, tooltip: { callbacks: { label: (context) => { return format(context.parsed.y) + ' ops/s' }, }, displayColors: false, backgroundColor: '#222222', padding: 10, cornerRadius: 5, intersect: false, }, }, scales: { x: { grid: { color: '#888888', }, }, y: { title: { display: true, text: 'Operations per second', padding: 10, }, grid: { color: '#888888', }, }, }, }, }) ``` -------------------------------- ### Generate Patches with Callback Source: https://github.com/giusepperaso/structura.js/blob/master/docs/patches.md Use the `produce` function with a callback to generate both the modified result and the associated patches and inverse patches. ```typescript type Make = () => Record[] const makeObj: Make = () => [{ A: 1 }]; // first we get the result and the patches let patches: Patch[] = []; let inverse: Patch[] = []; const result = produce( makeObj(), (draft) => { draft.push({ B: 2 }); }, (_patches, _inverse) => { patches = _patches; inverse = _inverse; } ); // if we apply the patches from the same starting point, we get the same result const newResult = applyPatches(makeObj(), patches); expect(newResult).toEqual(result); // then, if we apply the inverse patches, we obtain the original state const undone = applyPatches(newResult, inverse); expect(undone).toEqual(makeObj()); ``` -------------------------------- ### Change Multiple Settings at Once Source: https://github.com/giusepperaso/structura.js/blob/master/docs/settings.md Conveniently modifies multiple Structura settings simultaneously by directly assigning an object to the `Settings` property. ```typescript import { Settings } from "structurajs"; Object.assign(Settings, { autoFreeze: true, standardPatches: true, strictCopy: true }) ``` -------------------------------- ### Immutable Update of a Class Instance Source: https://github.com/giusepperaso/structura.js/blob/master/docs/examples.md Shows how to immutably update a class instance's properties or call its methods within the `produce` function. The original instance is preserved. Requires importing `produce` from `structurajs`. ```typescript import { produce } from "structurajs"; class MyClass { count = 1; increment() { this.count++; } } const myInstance = new MyClass(); const result = produce(myInstance, (draft) => { draft.increment(); }) myInstance.count === 1 // true result.count === 2 // true ``` -------------------------------- ### Return undefined using NOTHING Source: https://github.com/giusepperaso/structura.js/blob/master/docs/nothing.md Use the NOTHING constant when you need to return undefined from a producer. Note that NOTHING is an empty object, not strictly undefined. ```typescript import { NOTHING, produce } from "structurajs" const myObj = {} const newState = produce(myObj, (draft) => { return NOTHING }) console.log(newState === undefined) // true console.log(newState === NOTHING) // false! NOTHING is an empty object ``` -------------------------------- ### Immutable Update of a Date Object Source: https://github.com/giusepperaso/structura.js/blob/master/docs/examples.md Illustrates how to perform immutable updates on a `Date` object using `produce`. The original `Date` object is not modified. Requires importing `produce` from `structurajs`. ```typescript import { produce } from "structurajs"; const myDate = new Date const result = produce(myDate, (draft) => { draft.setDate(draft.getDate() + 1); // add a day }) myDate.getTime() !== result.getTime() // true ``` -------------------------------- ### Unfreezing state with unfreeze utility Source: https://github.com/giusepperaso/structura.js/blob/master/docs/freezing.md Shows the usage of the `unfreeze` utility to remove freezing from an object. Note that this utility will throw an exception if the object was frozen using `Object.freeze` or Structura.js's `freeze` utility at runtime. ```typescript import { unfreeze } from "structurajs"; unfreeze(newState).push(5); // it works ``` -------------------------------- ### Format Numbers for Display Source: https://github.com/giusepperaso/structura.js/blob/master/docs/public/benchmark/nested_many.chart.html Formats large numbers with spaces as thousands separators and includes a decimal part if present. Useful for making large benchmark results more readable. ```javascript const format = (num) => { const [whole, fraction] = String(num).split('.') const chunked = [] whole .split('') .reverse() .forEach((char, index) => { if (index % 3 === 0) { chunked.unshift([char]) } else { chunked[0].unshift(char) } }) const fractionStr = fraction !== undefined ? '.' + fraction : '' return ( chunked.map((chunk) => chunk.join('')).join(' ') + fractionStr ) } ``` -------------------------------- ### Format Number for Chart Tooltip Source: https://github.com/giusepperaso/structura.js/blob/master/docs/public/benchmark/small_few.chart.html Formats numbers with commas for thousands separators and handles decimal points, suitable for chart tooltips. ```javascript const format = (num) => { const [whole, fraction] = String(num).split('.') const chunked = [] whole .split('') .reverse() .forEach((char, index) => { if (index % 3 === 0) { chunked.unshift([char]) } else { chunked[0].unshift(char) } }) const fractionStr = fraction !== undefined ? '.' + fraction : '' return ( chunked.map((chunk) => chunk.join('')).join(' ') + fractionStr ) } ``` -------------------------------- ### Enable Auto Freeze Source: https://github.com/giusepperaso/structura.js/blob/master/docs/settings.md Activates runtime freezing of data structures. This is generally not needed as Structura supports compile-time freezing. Call with `true` to enable and `false` to disable. ```typescript import { enableAutoFreeze } from "structurajs"; enableAutoFreeze(true); ``` ```typescript enableAutoFreeze(false); ``` -------------------------------- ### Non-Mutative Application with Return Value Source: https://github.com/giusepperaso/structura.js/blob/master/docs/patches.md Demonstrates that `applyPatchesMutatively` does not work as expected when the producer function returns a new value instead of modifying the draft. ```typescript const original = [{ A: 1 }]; enableAutoFreeze(false); // don't freeze or it will be impossible to modify the object const [result, _patches, inverse] = produceWithPatches(original, (_draft) => { return [{ A: 2 }]; }); // this WILL NOT work mutatively const newResult = applyPatchesMutatively(result, inverse); expect(result).not.toBe(newResult); ``` -------------------------------- ### Returning and Modifying in the Same Producer Source: https://github.com/giusepperaso/structura.js/blob/master/docs/edge-cases.md Demonstrates how to modify a draft and return a new object within the same producer function. This allows for complex state updates where the returned value can be derived from the modified draft. ```typescript const newState = produce({ test1: [1], test2: [2] }, (draft) => { draft.test1.push(1) draft.test2.push(2) // this is just an example, but you could return anything return [draft.test1, draft.test2] }) ``` -------------------------------- ### Using target() to Avoid Dangling Proxies Source: https://github.com/giusepperaso/structura.js/blob/master/docs/gotchas.md The `target` helper function can be used to unproxy draft portions before assigning them to new objects, preventing dangling proxy references. ```typescript const result = produce({ example: { test: 2 } }, (draft) => { const newObj = {}; newObj.sub = target(draft.example); // result.newObj.sub is now safe to read/write because it's not a proxy draft.newObj = newObj; }) ``` -------------------------------- ### Using safeProduce for Strict Type Safety Source: https://github.com/giusepperaso/structura.js/blob/master/docs/gotchas.md The `safeProduce` helper enforces that the state and the returned draft have the same type, preventing common type-related errors without manual type declarations. ```typescript const state = { test: 1 } // ERROR! // this will not be accepted because safeProduce does not allow it // with the use of the helper, we don't have to explicity define types const result = safeProduce(state, (draft) => draft.test = 2) ``` -------------------------------- ### Unfreezing state with UnFreeze type Source: https://github.com/giusepperaso/structura.js/blob/master/docs/freezing.md Demonstrates how to use the `UnFreeze` type to remove the compile-time readonly flag from a frozen state, allowing mutations. ```typescript const newStateUnfrozen = newState as UnFreeze newState.push(5) // it works ``` -------------------------------- ### Direct Assignment to Draft Avoids Proxy Issues Source: https://github.com/giusepperaso/structura.js/blob/master/docs/gotchas.md Directly assigning a new object to the draft, rather than assigning a portion of the draft to an intermediate object, avoids dangling proxy reference issues. ```typescript const result = produce({ example: { test: 2 } }, (draft) => { // appending newObj immediately to the draft allows to have the correct behaviour later on draft.newObj = {}; newObj.sub = draft.example; }) ``` -------------------------------- ### Immutable Update of an Array Source: https://github.com/giusepperaso/structura.js/blob/master/docs/examples.md Demonstrates updating an element within an array immutably using `produce`. The original array remains unmodified. Requires importing `produce` from `structurajs`. ```typescript import { produce } from "structurajs"; const myArr = [1] const result = produce(myArr, (draft) => { draft[0]++ }) myArr[0] === 1 // true result[0] === 2 // true ``` -------------------------------- ### Enable Strict Copy Source: https://github.com/giusepperaso/structura.js/blob/master/docs/settings.md Enables strict copy mode to include non-enumerable properties during shallow copies, which is important for libraries like Vue and MobX. Call with `true` to enable and `false` to disable. ```typescript import { enableStrictCopy } from "structurajs"; enableStrictCopy(true); ``` ```typescript enableStrictCopy(false); ``` -------------------------------- ### Handling Circular References Automatically Source: https://github.com/giusepperaso/structura.js/blob/master/docs/edge-cases.md Illustrates Structura.js's automatic handling of circular references in state objects. Unlike some libraries, manual freezing is not required to prevent infinite loops during production. ```typescript const state: any = { test1: [1], test2: [2], test3: null } state.test3 = state // this works without going infinite const newState = produce(state, (draft) => { draft.test3.test1.push(1) }) ``` -------------------------------- ### Extend draftable types Source: https://github.com/giusepperaso/structura.js/blob/master/docs/helpers.md You can extend the default draftable types by importing `DraftableTypes` and pushing new string representations of objects to it. This allows custom classes to be draftable. ```typescript import { DraftableTypes } from "structurajs"; class MyClass { get [Symbol.toStringTag]() { return 'MyClass'; } } DraftableTypes.push("[object MyClass]"); ``` -------------------------------- ### Valid Producer Return Type in Structura.js Source: https://github.com/giusepperaso/structura.js/blob/master/docs/gotchas.md Producers in Structura.js can return any type, offering flexibility but also potential for errors if not managed carefully. ```typescript produce({}, () => { return 1; }) ``` -------------------------------- ### Immutable Update of an Object Source: https://github.com/giusepperaso/structura.js/blob/master/docs/examples.md Use `produce` to create a new object with an updated property, leaving the original object unchanged. Requires importing `produce` from `structurajs`. ```typescript import { produce } from "structurajs"; const myObj = { count: 1 } const result = produce(myObj, (draft) => { draft.count++; }) result.count === 2 // true myObj.count === 1 // true ``` -------------------------------- ### Apply Patches Mutatively Source: https://github.com/giusepperaso/structura.js/blob/master/docs/patches.md Use `applyPatchesMutatively` to modify an object in place without cloning, which is useful when direct mutation is desired. Ensure `enableAutoFreeze(false)` is called first if the object is frozen. ```typescript const original = [{ A: 1 }]; enableAutoFreeze(false); // don't freeze or it will be impossible to modify the object const [result, _patches, inverse] = produceWithPatches(original, (draft) => { draft.push({ A: 2 }); }); // this will modify the result itself, mutatively without any cloning const newResult = applyPatchesMutatively(result, inverse); expect(result).toBe(newResult); expect(result).toEqual(original); ``` -------------------------------- ### Dangling Proxy Reference with Unproxied Objects Source: https://github.com/giusepperaso/structura.js/blob/master/docs/gotchas.md Assigning a portion of a draft to an unproxied object and then reassigning it back can create dangling proxy references, leading to unpredictable behavior. ```typescript const result = produce({ example: { test: 2 } }, (draft) => { const newObj = {}; newObj.sub = draft.example; // result.newObj.sub will be a dangling proxy reference! // This may lead to unpredictable behaviour, expecially if you try to write later into it draft.newObj = newObj; }) ``` -------------------------------- ### Explicit Type Declaration for Producer Safety Source: https://github.com/giusepperaso/structura.js/blob/master/docs/gotchas.md Explicitly declaring generic parameters for producers prevents type errors by enforcing stricter type checking. ```typescript const state = { test: 1 } type T = { test: number } // ERROR! // this will not be accepted because we were more explicit with our types const result = produce(state, (draft) => draft.test = 2) ``` -------------------------------- ### Check if an object is a draft Source: https://github.com/giusepperaso/structura.js/blob/master/docs/helpers.md Use `isDraft` to determine if an object is a draft or part of a draft. It returns false for the original state and true for draft objects or their properties. ```typescript const state = { item: { n: 1 } } produce(state, (draft) => { isDraft(state) // false; isDraft(draft) // true; isDraft(draft.item) // true; }) ``` -------------------------------- ### Check if an object is draftable Source: https://github.com/giusepperaso/structura.js/blob/master/docs/helpers.md Use `isDraftable` to check if an object can be drafted. It supports various types including Objects, Arrays, Maps, Sets, RegExps, Strings, Numbers, Booleans, Dates, and Functions. Non-draftable objects may have a custom `Symbol.toStringTag`. ```typescript isDraftable({}) // true; isDraftable([]) // true; isDraftable(new class {}) // true; isDraftable(new String("draftable")) // true; isDraftable("non-draftable") // false; isDraftable(function() {}) // true; ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.