UNPKG

formatted-json-stringify

Version:

An advanced & customisable version of the javascript JSON.stringify() function.

186 lines (185 loc) 7.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ObjectSwitchFormatter = exports.ArrayFormatter = exports.ObjectFormatter = exports.TextFormatter = exports.PropertyFormatter = exports.DefaultFormatter = exports.custom = void 0; var custom; (function (custom) { /**## BaseFormatter `class` * The base of all formatters. This class can't be used directly, but needs to be extended from when creating custom formatters! */ class BaseFormatter { /**The name of this variable. Used as key in objects. */ name; /**Set this to `false` when this is a global variable or you don't want the key/name to be rendered. */ showKey; constructor(name) { this.name = name ?? ""; this.showKey = !(name == null); } /**Parse a variable trough this formatter! Returns a JSON string like `JSON.stringify()` */ stringify(data) { throw new Error("FJS.BaseFormatter: Tried to use uninplemented stringify() function!"); } } custom.BaseFormatter = BaseFormatter; })(custom || (exports.custom = custom = {})); /**## DefaultFormatter `class` * You can use this formatter when you don't know the contents of the variable! * * It just uses the default `JSON.stringify` under the hood! */ class DefaultFormatter extends custom.BaseFormatter { /**When enabled, objects & arrays will be rendered multiline instead of inline! */ multiline; /**The space or indentation for this object/array. 4 spaces by default. */ space; constructor(name, multiline, space) { super(name); this.multiline = multiline; this.space = space ?? " "; } stringify(data) { if (typeof data == "undefined") throw new Error(`FJS.PropertyFormatter: Property '${this.name}' is 'undefined' which is not allowed in JSON files!`); const key = this.showKey ? `"${this.name}":` : ""; const value = JSON.stringify(data, null, (this.multiline ? this.space : undefined)); return key + value; } } exports.DefaultFormatter = DefaultFormatter; /**## PropertyFormatter `class` * The formatter responsible for formatting `boolean`, `string`, `number` & `null` variables! */ class PropertyFormatter extends custom.BaseFormatter { stringify(data) { if (typeof data == "undefined") throw new Error(`FJS.PropertyFormatter: Property '${this.name}' is 'undefined' which is not allowed in JSON files!`); const key = this.showKey ? `"${this.name}":` : ""; const value = JSON.stringify(data); return key + value; } } exports.PropertyFormatter = PropertyFormatter; /**## TextFormatter `class` * The formatter responsible for adding custom text between properties in an object! */ class TextFormatter extends custom.BaseFormatter { /**The text to write on this row. */ text; constructor(text) { super(null); this.text = text ?? ""; } stringify() { return this.text; } } exports.TextFormatter = TextFormatter; /**## ObjectFormatter `class` * The formatter responsible for formatting `object` variables! */ class ObjectFormatter extends custom.BaseFormatter { /**When enabled, the object will be rendered multiline instead of inline! */ multiline; /**A collection of all the child-formatters in this object. */ children; /**When enabled, the object will still be rendered multiline when it's empty! */ multilineWhenEmpty; /**The space or indentation for this object. 4 spaces by default. */ space; constructor(name, multiline, children, multilineWhenEmpty, space) { super(name); this.multiline = multiline; this.children = children; this.multilineWhenEmpty = multilineWhenEmpty ?? false; this.space = space ?? " "; } stringify(data) { const children = this.children.map((child, index) => { const comma = (this.children.length == index + 1) ? "" : ","; if (child instanceof TextFormatter) return this.#indentWithoutFirst(child.stringify()); else { if (typeof data[child.name] == "undefined") throw new Error(`FJS.ObjectFormatter: Object property '${child.name}' is 'undefined' which is not allowed in JSON files!`); return this.#indentWithoutFirst(child.stringify(data[child.name]) + comma); } }); const key = this.showKey ? `"${this.name}":` : ""; const renderMultiline = this.multiline && (children.length > 0 || this.multilineWhenEmpty); const value = renderMultiline ? `{\n${this.space}${children.join(`\n${this.space}`)}\n}` : `{${children.join("")}}`; return key + value; } /**Private function for indenting all lines except the first row. */ #indentWithoutFirst(text) { return text.split("\n").map((row, index) => { if (index == 0) return row; else return this.space + row; }).join("\n"); } } exports.ObjectFormatter = ObjectFormatter; /**## ArrayFormatter `class` * The formatter responsible for formatting `array` variables! */ class ArrayFormatter extends custom.BaseFormatter { /**When enabled, the array will be rendered multiline instead of inline! */ multiline; /**The formatter that will be executed on all variables in the array. */ property; /**When enabled, the object will still be rendered multiline when it's empty! */ multilineWhenEmpty; /**The space or indentation for this array. 4 spaces by default. */ space; constructor(name, multiline, property, multilineWhenEmpty, space) { super(name); this.multiline = multiline; this.property = property; this.multilineWhenEmpty = multilineWhenEmpty ?? false; this.space = space ?? " "; } stringify(data) { const children = data.map((child, index) => { if (typeof child == "undefined") throw new Error(`FJS.ArrayFormatter: Value #${index} of array is 'undefined' which is not allowed in JSON files!`); const comma = (data.length == index + 1) ? "" : ","; return this.#indentWithoutFirst(this.property.stringify(child) + comma); }); const key = this.showKey ? `"${this.name}":` : ""; const renderMultiline = this.multiline && (children.length > 0 || this.multilineWhenEmpty); const value = renderMultiline ? `[\n${this.space}${children.join(`\n${this.space}`)}\n]` : `[${children.join("")}]`; return key + value; } /**Private function for indenting all lines except the first row. */ #indentWithoutFirst(text) { return text.split("\n").map((row, index) => { if (index == 0) return row; else return this.space + row; }).join("\n"); } } exports.ArrayFormatter = ArrayFormatter; /**## ObjectSwitchFormatter `class` * Use this utility class to switch `ObjectFormatter`'s based on a `key` and `value` match in the object. * * This could be used in combination with an `ArrayFormatter` to allow different objects to exist in the same array! */ class ObjectSwitchFormatter extends custom.BaseFormatter { /**A list of all available formatters to check for an object. */ formatters; constructor(name, formatters) { super(name); this.formatters = formatters; } stringify(data) { const result = this.formatters.find((formatter) => data[formatter.key] === formatter.value); if (!result) throw new Error("FJS.ObjectSwitchFormatter: No formatter matches the given object!"); const formatter = result.formatter; return formatter.stringify(data); } } exports.ObjectSwitchFormatter = ObjectSwitchFormatter;