UNPKG

@slightning/anything-to-string

Version:
618 lines (565 loc) 15.5 kB
# Anything To String ![npm version](https://img.shields.io/npm/v/@slightning/anything-to-string) ![license](https://img.shields.io/npm/l/@slightning/anything-to-string) Converts anything in JavaScript/TypeScript to a string with detailed formatting options. ## Supported Types - Primitives: `null`, `undefined`, `string`, `number`, `boolean` - Object Wrappers: `String`, `Number`, `Boolean` - Special Objects: `RegExp`, `Symbol`, `BigInt` - Collections: `Set`, `Map`, `WeakRef` - Errors: `Error` and all its subclasses - DOM: `HTMLElement` - Complex Types: `Array`, `Object`, `Function` (including arrow functions and classes) ## Installation ```bash npm install @slightning/anything-to-string # or yarn add @slightning/anything-to-string ``` ## Use ```JavaScript const { stringify } = require("@slightning/anything-to-string") const basicObject = { null: null, undefined: undefined, string: "string", number: 1, boolean: true, String: new String("test"), Number: new Number(1), Boolean: new Boolean(true), RegExp: /test/g, [Symbol("Key")]: Symbol("Symbol"), bigint: BigInt("10000000000000000000000000000000000000000000000000000000000000000"), Set: new Set(), Map: new Map(), WeakRef: new WeakRef({}), Error: new Error("test"), Array: [,], object: {}, get test() { return "value from getter" }, set test(value) { console.log("set value: " + value) } } Object.defineProperty(basicObject, "ref", { value: basicObject }) const data = { null: null, undefined: undefined, string: "string", number: 1, boolean: true, String: new String("test"), Number: new Number(1), Boolean: new Boolean(true), RegExp: /test/g, [Symbol("Key")]: Symbol("Symbol"), bigint: BigInt("10000000000000000000000000000000000000000000000000000000000000000"), Set: new Set(Object.values(basicObject)), Map: new Map(Object.entries(basicObject)), WeakRef: new WeakRef(basicObject), Error: new Error("test"), Array: Object.values(basicObject), object: basicObject, get test() { return "value from getter" }, set test(value) { console.log("set value: " + value) } } Object.defineProperty(data, "ref", { value: data }) console.log(stringify(data)) ``` Output ``` <ref *2> Object { null: null undefined: undefined string: [string: "string"] number: [number: 1] boolean: [boolean: true] String: String("test") String { length: 4 } Number: Number(1) {} Boolean: Boolean(true) {} RegExp: RegExp(/test/g) RegExp { lastIndex: 0 } bigint: [bigint: 10000000000000000000000000000000000000000000000000000000000000000] Set: Set { [[Values]]: 0: null 1: undefined 2: "string" 3: 1 4: true 5: String("test") 6: Number(1) 7: Boolean(true) 8: RegExp(/test/g) 9: 10000000000000000000000000000000000000000000000000000000000000000 10: Set { [[Values]]: None } 11: Map { [[Entries]]: None } 12: WeakRef { [[WeakRefTarget]]: [object Object] } 13: Error: test 14: [ None ] 15: {} 16: "value from getter" } Map: Map { [[Entries]]: 0: key: "null" value: null 1: key: "undefined" value: undefined 2: key: "string" value: "string" 3: key: "number" value: 1 4: key: "boolean" value: true 5: key: "String" value: String("test") 6: key: "Number" value: Number(1) 7: key: "Boolean" value: Boolean(true) 8: key: "RegExp" value: RegExp(/test/g) 9: key: "bigint" value: 10000000000000000000000000000000000000000000000000000000000000000 10: key: "Set" value: Set { [[Values]]: None } 11: key: "Map" value: Map { [[Entries]]: None } 12: key: "WeakRef" value: WeakRef { [[WeakRefTarget]]: [object Object] } 13: key: "Error" value: Error: test 14: key: "Array" value: [ None ] 15: key: "object" value: {} 16: key: "test" value: "value from getter" } WeakRef: WeakRef { [[WeakRefTarget]]: <ref *1> Object { null: null undefined: undefined string: "string" number: 1 boolean: true String: "test" Number: 1 Boolean: true RegExp: /test/g bigint: 10000000000000000000000000000000000000000000000000000000000000000 Set: Set(0) Map: Map(0) WeakRef: [WeakRef] Error: [Error] Array: Array(1) object: [object Object] } } Error: Error: test at <anonymous>:1:1 Array: Array { 0: null 1: undefined 2: "string" 3: 1 4: true 5: String("test") 6: Number(1) 7: Boolean(true) 8: RegExp(/test/g) 9: 10000000000000000000000000000000000000000000000000000000000000000 10: Set { [[Values]]: None } 11: Map { [[Entries]]: None } 12: WeakRef { [[WeakRefTarget]]: [object Object] } 13: Error: test 14: [ None ] 15: {} 16: "value from getter" length: 17 } object: [Circular *1] test: [string: "value from getter"] ref: [Circular *2] [Symbol(Key)]: Symbol(Symbol) get test: get test() { return "value from getter"; } set test: set test(value) { console.log("set value: " + value); } [[Prototype]]: Object { constructor: function Object() { [native code] } __defineGetter__: function __defineGetter__() { [native code] } __defineSetter__: function __defineSetter__() { [native code] } hasOwnProperty: function hasOwnProperty() { [native code] } __lookupGetter__: function __lookupGetter__() { [native code] } __lookupSetter__: function __lookupSetter__() { [native code] } isPrototypeOf: function isPrototypeOf() { [native code] } propertyIsEnumerable: function propertyIsEnumerable() { [native code] } toString: function toString() { [native code] } valueOf: function valueOf() { [native code] } __proto__: null toLocaleString: function toLocaleString() { [native code] } } } ``` ## Config Let's continue with the above example and make the following modifications: ```diff - const { stringify } = require("@slightning/anything-to-string") + const { stringify, Rules } = require("@slightning/anything-to-string") const basicObject = { null: null, undefined: undefined, ... Object.defineProperty(data, "ref", { value: data }) - console.log(stringify(data)) + console.log(stringify(data, { + rules: Rules.LESSER, // Rule set, Rules.LESSER keeps less information + depth: 0 // Maximum depth limit, '0' means no limit + })) ``` Output ``` Object { null: null undefined: undefined string: "string" number: 1 boolean: true String: String("test") Number: Number(1) Boolean: Boolean(true) RegExp: RegExp(/test/g) bigint: 10000000000000000000000000000000000000000000000000000000000000000 Set: Set { [[Values]]: 0: null 1: undefined 2: "string" 3: 1 4: true 5: String("test") 6: Number(1) 7: Boolean(true) 8: RegExp(/test/g) 9: 10000000000000000000000000000000000000000000000000000000000000000 10: Set { [[Values]]: None } 11: Map { [[Entries]]: None } 12: WeakRef { [[WeakRefTarget]]: {} } 13: Error: test 14: [ None ] 15: {} 16: "value from getter" } Map: Map { [[Entries]]: "null": null "undefined": undefined "string": "string" "number": 1 "boolean": true "String": String("test") "Number": Number(1) "Boolean": Boolean(true) "RegExp": RegExp(/test/g) "bigint": 10000000000000000000000000000000000000000000000000000000000000000 "Set": Set { [[Values]]: None } "Map": Map { [[Entries]]: None } "WeakRef": WeakRef { [[WeakRefTarget]]: {} } "Error": Error: test "Array": [ None ] "object": {} "test": "value from getter" } WeakRef: WeakRef { [[WeakRefTarget]]: Object { null: null undefined: undefined string: "string" number: 1 boolean: true String: String("test") Number: Number(1) Boolean: Boolean(true) RegExp: RegExp(/test/g) bigint: 10000000000000000000000000000000000000000000000000000000000000000 Set: Set { [[Values]]: None } Map: Map { [[Entries]]: None } WeakRef: WeakRef { [[WeakRefTarget]]: {} } Error: Error: test Array: [ None ] object: {} } } Error: Error: test Array: [ null, undefined, "string", 1, true, String("test"), Number(1), Boolean(true), RegExp(/test/g), 10000000000000000000000000000000000000000000000000000000000000000, Set { [[Values]]: None }, Map { [[Entries]]: None }, WeakRef { [[WeakRefTarget]]: {} }, Error: test, [ None ], {}, "value from getter" ] object: Object { null: null undefined: undefined string: "string" number: 1 boolean: true String: String("test") Number: Number(1) Boolean: Boolean(true) RegExp: RegExp(/test/g) bigint: 10000000000000000000000000000000000000000000000000000000000000000 Set: Set { [[Values]]: None } Map: Map { [[Entries]]: None } WeakRef: WeakRef { [[WeakRefTarget]]: {} } Error: Error: test Array: [ None ] object: {} } } ``` ### rules The rule defines how to turn an object into a string. Default rules include Rules.MINIMUM, Rules.LESSER, Rules.MAJOR, Rules.MAXIMUM. Their names represent the level of detail in which information is retained. Example: ```JavaScript const { stringify, Rules } = require("@slightning/anything-to-string") function test() { console.log("hello") } console.log(stringify(test, { rules: Rules.MINIMUM })) // output: [Function: test] console.log(stringify(test, { rules: Rules.LESSER })) // output: function test() { console.log("hello") } console.log(stringify(test, { rules: Rules.MAJOR })) // output: // function test() { // console.log("hello") // } console.log(stringify(test, { rules: Rules.MAXIMUM })) // (lots of output) ``` #### Custom Rule ```JavaScript const { stringify, Rules } = require("@slightning/anything-to-string") console.log(stringify("data", { rules: [ new class { test(data) { return typeof data == "string" // Apply rule for strings } toString(data, config) { return config.ignoreString ? "" : JSON.stringify(data) } }, ...Rules.LESSER ], ignoreString: true // Custom config })) // output: (nothing) ``` tips: You may need to add a `.d.ts` file to your project to declare the custom config type. ```typescript declare module "@slightning/anything-to-string" { interface Config { ignoreString?: boolean } } ``` If you want to use existing rules in your custom rule, you can use `AnythingRule`. ```JavaScript const { stringify, Rules, AnythingRule } = require("@slightning/anything-to-string") class Ref { constructor(value) { this.value = value } } console.log(stringify("data", { rules: [ new class { test(data) { return data instanceof Ref // Apply rule for Ref }, // Ref may contain circular reference. // To handle circular reference, you need to prepare the value first. // Just call `prepare` method of `AnythingRule` to prepare the value. prepare(data, config, context) { new AnythingRule().prepare(data.value, config, context) }, toString(data, config, context) { return "Ref(" + new AnythingRule().toString(data.value, config, context) + ")" } }, ...Rules.LESSER ] })) // output: Ref("data") ``` ### indent The number of indented Spaces or indented string. Default is 4. ```JavaScript const { stringify, Rules } = require("@slightning/anything-to-string") console.log(stringify(["data"], { rules: Rules.LESSER, indent: 2 })) // output: // Array [ // "data" // ] console.log(stringify(["data"], { rules: Rules.LESSER, indent: "|--|" })) // output: // Array [ // |--|"data" // ] ``` ### depth Maximum recursion depth. ### object - `unenumerable`: Include non-enumerable attributes. - `symbol`: Include properties with symbol as keys. - `get`: Include computed attribute. - `getter`: Include getter. - `setter`: Include setter. - `prototype`: Include prototype. - `exclude`: Exclude properties with the specified names or symbols. Example ```JavaScript const { stringify, Rules } = require("@slightning/anything-to-string") console.log(stringify({ get a() { return "value from getter" }, [Symbol("symbol")]: "value" }, { rules: Rules.LESSER, object: { symbol: true, get: true, getter: true, prototype: true } })) // output: // Object { // a: "value from getter" // [Symbol(symbol)]: "value" // get a: get a() { return "value from getter" } // [[Prototype]]: Object { // [[Prototype]]: null // } // } ```