formatted-json-stringify
Version:
An advanced & customisable version of the javascript JSON.stringify() function.
186 lines (185 loc) • 7.95 kB
JavaScript
"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;