Pārlūkot izejas kodu

feat: purifyObj function

Sv443 1 mēnesi atpakaļ
vecāks
revīzija
5d71770
5 mainītis faili ar 56 papildinājumiem un 1 dzēšanām
  1. 5 0
      .changeset/long-apricots-wave.md
  2. 1 0
      README-summary.md
  3. 1 0
      README.md
  4. 39 0
      docs.md
  5. 10 1
      lib/misc.ts

+ 5 - 0
.changeset/long-apricots-wave.md

@@ -0,0 +1,5 @@
+---
+"@sv443-network/userutils": minor
+---
+
+Added function `purifyObj()` to remove an object's prototype chain (i.e. omit all inherited properties like `toString`, `__proto__`, etc.)

+ 1 - 0
README-summary.md

@@ -74,6 +74,7 @@ View the documentation of previous major releases:
     - [`consumeGen()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#consumegen) - consumes a ValueGen and returns the value
     - [`consumeGen()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#consumegen) - consumes a ValueGen and returns the value
     - [`consumeStringGen()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#consumestringgen) - consumes a StringGen and returns the string
     - [`consumeStringGen()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#consumestringgen) - consumes a StringGen and returns the string
     - [`getListLength()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
     - [`getListLength()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
+    - [`purifyObj()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#purifyobj) - removes the prototype chain (all default properties like `toString`, `__proto__`, etc.) from an object
 - **Arrays:**
 - **Arrays:**
     - [`randomItem()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#randomitem) - returns a random item from an array
     - [`randomItem()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#randomitem) - returns a random item from an array
     - [`randomItemIndex()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#randomitemindex) - returns a tuple of a random item and its index from an array
     - [`randomItemIndex()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#randomitemindex) - returns a tuple of a random item and its index from an array

+ 1 - 0
README.md

@@ -77,6 +77,7 @@ View the documentation of previous major releases:
     - [`consumeGen()`](./docs.md#consumegen) - consumes a ValueGen and returns the value
     - [`consumeGen()`](./docs.md#consumegen) - consumes a ValueGen and returns the value
     - [`consumeStringGen()`](./docs.md#consumestringgen) - consumes a StringGen and returns the string
     - [`consumeStringGen()`](./docs.md#consumestringgen) - consumes a StringGen and returns the string
     - [`getListLength()`](./docs.md#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
     - [`getListLength()`](./docs.md#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
+    - [`purifyObj()`](./docs.md#purifyobj) - removes the prototype chain (all default properties like `toString`, `__proto__`, etc.) from an object
   - [**Arrays:**](./docs.md#arrays)
   - [**Arrays:**](./docs.md#arrays)
     - [`randomItem()`](./docs.md#randomitem) - returns a random item from an array
     - [`randomItem()`](./docs.md#randomitem) - returns a random item from an array
     - [`randomItemIndex()`](./docs.md#randomitemindex) - returns a tuple of a random item and its index from an array
     - [`randomItemIndex()`](./docs.md#randomitemindex) - returns a tuple of a random item and its index from an array

+ 39 - 0
docs.md

@@ -66,6 +66,7 @@ For submitting bug reports or feature requests, please use the [GitHub issue tra
     - [`consumeGen()`](#consumegen) - consumes a ValueGen and returns the value
     - [`consumeGen()`](#consumegen) - consumes a ValueGen and returns the value
     - [`consumeStringGen()`](#consumestringgen) - consumes a StringGen and returns the string
     - [`consumeStringGen()`](#consumestringgen) - consumes a StringGen and returns the string
     - [`getListLength()`](#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
     - [`getListLength()`](#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
+    - [`purifyObj()`](#purifyobj) - removes the prototype chain (all default properties like `toString`, `__proto__`, etc.) from an object
   - [**Arrays:**](#arrays)
   - [**Arrays:**](#arrays)
     - [`randomItem()`](#randomitem) - returns a random item from an array
     - [`randomItem()`](#randomitem) - returns a random item from an array
     - [`randomItemIndex()`](#randomitemindex) - returns a tuple of a random item and its index from an array
     - [`randomItemIndex()`](#randomitemindex) - returns a tuple of a random item and its index from an array
@@ -2624,6 +2625,42 @@ getListLength({ foo: "bar" }, false); // NaN
 ```
 ```
 </details>
 </details>
 
 
+<br>
+
+### purifyObj()
+Signature:  
+```ts
+purifyObj<TObj extends object>(obj: TObj): TObj
+```
+  
+Turns the passed object into a "pure" object without a prototype chain, meaning it won't have any default properties like `toString`, `__proto__`, `__defineGetter__`, etc.  
+This could be useful to prevent prototype pollution attacks or to clean up object literals, at the cost of being harder to work with in some cases.  
+It also effectively transforms a [`Stringifiable`](#stringifiable) value into one that will throw a TypeError when stringified instead of defaulting to `[object Object]`  
+  
+<details><summary><b>Example - click to view</b></summary>
+
+```ts
+import { purifyObj } from "@sv443-network/userutils";
+
+const impureObj = {
+  foo: "bar",
+};
+
+console.log(impureObj.toString);         // [Function: toString]
+console.log(impureObj.__proto__);        // { ... }
+console.log(impureObj.__defineGetter__); // [Function: __defineGetter__]
+console.log(`${impureObj}`);             // "[object Object]"
+
+
+const pureObj = purifyObj(impureObj);
+
+console.log(pureObj.toString);         // undefined
+console.log(pureObj.__proto__);        // undefined
+console.log(pureObj.__defineGetter__); // undefined
+console.log(`${pureObj}`);             // TypeError: Cannot convert object to string
+```
+</details>
+
 <br><br>
 <br><br>
 
 
 <!-- #region Arrays -->
 <!-- #region Arrays -->
@@ -3318,6 +3355,8 @@ To be considered stringifiable, the object needs to have a `toString()` method t
 Most primitives have this method, but something like undefined or null does not.  
 Most primitives have this method, but something like undefined or null does not.  
 Having this method allows not just explicit conversion by using `.toString()`, but also implicit conversion by passing it into the `String()` constructor or interpolating it in a template literal string.  
 Having this method allows not just explicit conversion by using `.toString()`, but also implicit conversion by passing it into the `String()` constructor or interpolating it in a template literal string.  
   
   
+To make an object explicitly *not stringifiable* (so it throws an error when being converted to a string), you can pass it to [`purifyObj()`](#purifyobj) to remove its prototype chain, including the `toString()` method.  
+  
 <details><summary><b>Example - click to view</b></summary>
 <details><summary><b>Example - click to view</b></summary>
 
 
 ```ts
 ```ts

+ 10 - 1
lib/misc.ts

@@ -123,7 +123,7 @@ export async function consumeGen<TValueType>(valGen: ValueGen<TValueType>): Prom
   return await (typeof valGen === "function"
   return await (typeof valGen === "function"
     ? (valGen as (() => Promise<TValueType> | TValueType))()
     ? (valGen as (() => Promise<TValueType> | TValueType))()
     : valGen
     : valGen
-  )as TValueType;
+  ) as TValueType;
 }
 }
 
 
 /**
 /**
@@ -165,3 +165,12 @@ export function getListLength(obj: ListWithLength, zeroOnInvalid = true): number
           ? 0
           ? 0
           : NaN;
           : NaN;
 }
 }
+
+/**
+ * Turns the passed object into a "pure" object without a prototype chain, meaning it won't have any default properties like `toString`, `__proto__`, `__defineGetter__`, etc.  
+ * This makes the object immune to prototype pollution attacks and allows for cleaner object literals, at the cost of being harder to work with in some cases.  
+ * It also effectively transforms a `Stringifiable` value into one that will throw a TypeError when stringified instead of defaulting to `[object Object]`
+ */
+export function purifyObj<TObj extends object>(obj: TObj): TObj {
+  return Object.assign(Object.create(null), obj);
+}