### 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.