UNPKG

@parischap/pretty-print

Version:
224 lines 9.27 kB
/** * 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