@parischap/pretty-print
Version:
A functional library to pretty-print and treeify objects
224 lines • 9.27 kB
JavaScript
/**
* This module implements a type that takes care of the formatting of non-primitive values. From the
* stringified representation of the properties of a non-primitive value which it receives, it must
* return the stringified representation of the whole non-primitive value. It can take care of
* aspects like adding specific array/object marks, printing on a single or multiple lines,
* indentation when printing on multiple lines, ...
*
* With the make function, you can define your own instances if the provided ones don't suit your
* needs.
*/
import { ASText } from '@parischap/ansi-styles';
import { MFunction, MInspectable, MMatch, MPipeable, MTuple } from '@parischap/effect-lib';
import { Array, Equal, flow, Function, Hash, Number, pipe, Predicate, Struct } from 'effect';
import * as PPStringifiedProperties from './StringifiedProperties.js';
import * as PPStringifiedValue from './StringifiedValue.js';
/**
* Module tag
*
* @category Models
*/
export const moduleTag = '@parischap/pretty-print/NonPrimitiveFormatter/';
const _TypeId = /*#__PURE__*/Symbol.for(moduleTag);
/**
* Type guard
*
* @category Guards
*/
export const has = u => Predicate.hasProperty(u, _TypeId);
/**
* Equivalence
*
* @category Equivalences
*/
export const equivalence = (self, that) => that.id === self.id;
/** Base */
const _TypeIdHash = /*#__PURE__*/Hash.hash(_TypeId);
const base = {
[_TypeId]: _TypeId,
[Equal.symbol](that) {
return has(that) && equivalence(this, that);
},
[Hash.symbol]() {
return pipe(this.id, Hash.hash, Hash.combine(_TypeIdHash), Hash.cached(this));
},
[MInspectable.IdSymbol]() {
return this.id;
},
... /*#__PURE__*/MInspectable.BaseProto(moduleTag),
...MPipeable.BaseProto
};
/**
* Constructor
*
* @category Constructors
*/
export const make = ({
id,
action
}) => Object.assign(MFunction.clone(action), {
id,
...base
});
/**
* Returns the `id` property of `self`
*
* @category Destructors
*/
export const id = /*#__PURE__*/Struct.get('id');
/**
* NonPrimitiveFormatter instance that will always print non-primitive values on a single line
*
* @category Instances
*/
export const singleLine = /*#__PURE__*/make({
id: 'SingleLine',
action: function ({
valueBasedStylerConstructor
}) {
const inBetweenPropertySeparatorTextFormatter = valueBasedStylerConstructor('InBetweenPropertySeparator');
const nonPrimitiveValueDelimitersTextFormatter = valueBasedStylerConstructor('NonPrimitiveValueDelimiters');
return ({
value,
header
}) => {
const inBetweenPropertySeparator = pipe(this.singleLineInBetweenPropertySeparatorMark, inBetweenPropertySeparatorTextFormatter(value));
const inContextNonPrimitiveValueDelimitersTextFormatter = nonPrimitiveValueDelimitersTextFormatter(value);
return Array.match({
onEmpty: pipe(this.multiLineStartDelimiterMark + this.multiLineEndDelimiterMark, inContextNonPrimitiveValueDelimitersTextFormatter, ASText.prepend(header), PPStringifiedValue.fromText, Function.constant),
onNonEmpty: flow(PPStringifiedProperties.addMarkInBetween(inBetweenPropertySeparator), PPStringifiedProperties.prependProperty(pipe(this.singleLineStartDelimiterMark, inContextNonPrimitiveValueDelimitersTextFormatter, ASText.prepend(header))), PPStringifiedProperties.appendProperty(inContextNonPrimitiveValueDelimitersTextFormatter(this.singleLineEndDelimiterMark)), PPStringifiedValue.fromStringifiedProperties, PPStringifiedValue.toSingleLine)
});
};
}
});
/**
* NonPrimitiveFormatter instance that will always print non-primitive values on multiple lines with
* a tab indentation
*
* @category Instances
*/
export const tabify = /*#__PURE__*/make({
id: 'Tabify',
action: function ({
valueBasedStylerConstructor,
markShowerConstructor
}) {
const inBetweenPropertySeparatorTextFormatter = valueBasedStylerConstructor('InBetweenPropertySeparator');
const nonPrimitiveValueDelimitersTextFormatter = valueBasedStylerConstructor('NonPrimitiveValueDelimiters');
const tabIndentMarkShower = markShowerConstructor('TabIndent');
return ({
value,
header
}) => {
const inBetweenPropertySeparator = pipe(this.multiLineInBetweenPropertySeparatorMark, inBetweenPropertySeparatorTextFormatter(value));
const inContextNonPrimitiveValueDelimitersTextFormatter = nonPrimitiveValueDelimitersTextFormatter(value);
const startDelimiterMarkAndHeader = pipe(this.multiLineStartDelimiterMark, inContextNonPrimitiveValueDelimitersTextFormatter, ASText.prepend(header));
const endDelimiterMark = inContextNonPrimitiveValueDelimitersTextFormatter(this.multiLineEndDelimiterMark);
const tab = tabIndentMarkShower(value);
return flow(PPStringifiedProperties.addMarkInBetween(inBetweenPropertySeparator), PPStringifiedProperties.tabify(tab), PPStringifiedProperties.prependProperty(startDelimiterMarkAndHeader), PPStringifiedProperties.appendProperty(endDelimiterMark), PPStringifiedValue.fromStringifiedProperties);
};
}
});
/**
* NonPrimitiveFormatter instance that will always print non-primitive values in a tree-like fashion
*
* @category Instances
*/
export const treeify = /*#__PURE__*/make({
id: 'Treeify',
action: ({
markShowerConstructor
}) => {
const treeIndentForFirstLineOfInitPropsMarkShower = markShowerConstructor('TreeIndentForFirstLineOfInitProps');
const treeIndentForTailLinesOfInitPropsMarkShower = markShowerConstructor('TreeIndentForTailLinesOfInitProps');
const treeIndentForFirstLineOfLastPropMarkShower = markShowerConstructor('TreeIndentForFirstLineOfLastProp');
const treeIndentForTailLinesOfLastPropMarkShower = markShowerConstructor('TreeIndentForTailLinesOfLastProp');
return ({
value
}) => flow(PPStringifiedProperties.treeify({
treeIndentForFirstLineOfInitProps: treeIndentForFirstLineOfInitPropsMarkShower(value),
treeIndentForTailLinesOfInitProps: treeIndentForTailLinesOfInitPropsMarkShower(value),
treeIndentForFirstLineOfLastProp: treeIndentForFirstLineOfLastPropMarkShower(value),
treeIndentForTailLinesOfLastProp: treeIndentForTailLinesOfLastPropMarkShower(value)
}), PPStringifiedValue.fromStringifiedProperties);
}
});
/**
* NonPrimitiveFormatter instance maker that will print non-primitive values on a single line if the
* actual number of their constituents (after filtering,...) is less than or equal to `limit`.
*
* @category Constructors
*/
export const splitOnConstituentNumberMaker = limit => make({
id: 'SplitWhenConstituentNumberExceeds' + limit,
action: function (params) {
const initializedSingleLine = singleLine.call(this, params);
const initilizedTabify = tabify.call(this, params);
return ({
value,
header
}) => flow(MMatch.make, MMatch.when(flow(Array.length, Number.lessThanOrEqualTo(limit)), initializedSingleLine({
value,
header
})), MMatch.orElse(initilizedTabify({
value,
header
})));
}
});
/**
* Calls `singleLine` if the total length of the properties to print (excluding formatting
* characters) is less than or equal to `limit`. Calls `tabify` otherwise
*
* @category Constructors
*/
export const splitOnTotalLengthMaker = limit => make({
id: 'SplitWhenTotalLengthExceeds' + limit,
action: function (params) {
const initializedSingleLine = singleLine.call(this, params);
const initilizedTabify = tabify.call(this, params);
const inBetweenSepLength = this.singleLineInBetweenPropertySeparatorMark.length;
const delimitersLength = this.singleLineStartDelimiterMark.length + this.singleLineEndDelimiterMark.length;
const delimitersLengthWhenEmpty = this.multiLineStartDelimiterMark.length + this.multiLineEndDelimiterMark.length;
return ({
value,
header
}) => flow(MMatch.make, MMatch.when(flow(MTuple.makeBothBy({
toFirst: PPStringifiedProperties.toLength,
toSecond: Array.match({
onEmpty: Function.constant(ASText.toLength(header) + delimitersLengthWhenEmpty),
onNonEmpty: flow(Array.length, Number.decrement, Number.multiply(inBetweenSepLength), Number.sum(delimitersLength), Number.sum(ASText.toLength(header)))
})
}), Number.sumAll, Number.lessThanOrEqualTo(limit)), initializedSingleLine({
value,
header
})), MMatch.orElse(initilizedTabify({
value,
header
})));
}
});
/**
* Calls `singleLine` if the length of the longest property to print (excluding formatting
* characters and object marks) is less than or equal to `limit`. Calls `tabify` otherwise
*
* @category Constructors
*/
export const splitOnLongestPropLengthMaker = limit => make({
id: 'SplitWhenLongestPropLengthExceeds' + limit,
action: function (params) {
const initializedSingleLine = singleLine.call(this, params);
const initilizedTabify = tabify.call(this, params);
return ({
value,
header
}) => flow(MMatch.make, MMatch.when(flow(PPStringifiedProperties.toLongestPropLength, Number.lessThanOrEqualTo(limit)), initializedSingleLine({
value,
header
})), MMatch.orElse(initilizedTabify({
value,
header
})));
}
});
//# sourceMappingURL=NonPrimitiveFormatter.js.map