Skip to content

refactor(formatter): Move general utility functions from YScope formatter to global utilities. #190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Nullable} from "../../../../typings/common";
import {YscopeFieldFormatter} from "../../../../typings/formatters";
import {JsonValue} from "../../../../typings/js";
import {jsonValueToString} from "../utils";
import {jsonValueToString} from "../../../../utils/formatters";


/**
Expand Down
14 changes: 8 additions & 6 deletions src/services/formatters/YscopeFormatter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import {
} from "../../../typings/formatters";
import {LogEvent} from "../../../typings/logs";
import {
getFormattedField,
jsonValueToString,
removeEscapeCharacters,
replaceDoubleBacklash,
} from "../../../utils/formatters";
import {
getFormattedField,
splitFieldPlaceholder,
YSCOPE_FIELD_FORMATTER_MAP,
} from "./utils";
Expand All @@ -29,8 +31,8 @@ class YscopeFormatter implements Formatter {

constructor (options: FormatterOptionsType) {
if (options.formatString.includes(REPLACEMENT_CHARACTER)) {
console.warn("Unicode replacement character `U+FFFD` is found in Decoder Format" +
' String, which will appear as "\\".');
console.warn("Unicode replacement character `U+FFFD` found in format string; " +
"it will be replaced with \"\\\"");
}

this.#processedFormatString = replaceDoubleBacklash(options.formatString);
Expand Down Expand Up @@ -62,9 +64,9 @@ class YscopeFormatter implements Formatter {
}

/**
* Parses field placeholders in format string. For each field placeholder, creates a
* corresponding `YscopeFieldFormatter` using the placeholder's field name, formatter type,
* and formatter options. Each `YscopeFieldFormatter` is then stored on the
* Parses field placeholders in format string. For each field, creates a corresponding
* `YscopeFieldPlaceholder` using the placeholder's field name, formatter type,
* and formatter options. Each `YscopeFieldPlaceholder` is then stored on the
* class-level array `#fieldPlaceholders`.
*
* @throws Error if `FIELD_PLACEHOLDER_REGEX` does not contain a capture group.
Expand Down
76 changes: 4 additions & 72 deletions src/services/formatters/YscopeFormatter/utils.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import {Nullable} from "../../../typings/common";
import {
COLON_REGEX,
DOUBLE_BACKSLASH,
PERIOD_REGEX,
REPLACEMENT_CHARACTER,
SINGLE_BACKSLASH,
YscopeFieldFormatterMap,
YscopeFieldPlaceholder,
} from "../../../typings/formatters";
import {JsonValue} from "../../../typings/js";
import {LogEvent} from "../../../typings/logs";
import {
jsonValueToString,
removeEscapeCharacters,
} from "../../../utils/formatters";
import {getNestedJsonValue} from "../../../utils/js";
import RoundFormatter from "./FieldFormatters/RoundFormatter";
import TimestampFormatter from "./FieldFormatters/TimestampFormatter";
Expand All @@ -23,71 +23,6 @@ const YSCOPE_FIELD_FORMATTER_MAP: YscopeFieldFormatterMap = Object.freeze({
round: RoundFormatter,
});


/**
* Removes all backslashes from a string. Purpose is to remove escape character in front of brace
* and colon characters.
*
* @param str
* @return Modified string.
*/
const removeBackslash = (str: string): string => {
return str.replaceAll(SINGLE_BACKSLASH, "");
};

/**
* Replaces all replacement characters in format string with a single backslash. Purpose is to
* remove, albeit indirectly through intermediate replacement character, escape character in
* front of a backslash character.
*
* @param str
* @return Modified string.
*/
const replaceReplacementCharacter = (str: string): string => {
return str.replaceAll(REPLACEMENT_CHARACTER, "\\");
};

/**
* Removes escape characters from a string.
*
* @param str
* @return Modified string.
*/
const removeEscapeCharacters = (str: string): string => {
// `removeBackslash()`, which removes all backlashes, is called before
// `replaceReplacementCharacter()` to prevent removal of escaped backslashes.
return replaceReplacementCharacter(removeBackslash(str));
};

/**
* Replaces all escaped backslashes in format string with replacement character.
* Replacement character is a rare character that is unlikely to be in user format string.
* Writing regex to distinguish between a single escape character ("\") and an escaped backslash
* ("\\") is challenging especially when they are in series. It is simpler to just replace
* escaped backslashes with a rare character and add them back after parsing field placeholder
* with regex is finished.
*
* @param formatString
* @return Modified format string.
*/
const replaceDoubleBacklash = (formatString: string): string => {
return formatString.replaceAll(DOUBLE_BACKSLASH, REPLACEMENT_CHARACTER);
};


/**
* Converts a JSON value to its string representation.
*
* @param input
* @return
*/
const jsonValueToString = (input: JsonValue | undefined): string => {
// Behaviour is different for `undefined`.
return "object" === typeof input ?
JSON.stringify(input) :
String(input);
};

/**
* Gets a formatted field. Specifically, retrieves a field from a log event using a placeholder's
* `fieldNameKeys`. The field is then formatted using the placeholder's `fieldFormatter`.
Expand Down Expand Up @@ -175,9 +110,6 @@ const splitFieldPlaceholder = (placeholderString: string): {

export {
getFormattedField,
jsonValueToString,
removeEscapeCharacters,
replaceDoubleBacklash,
splitFieldPlaceholder,
YSCOPE_FIELD_FORMATTER_MAP,
};
77 changes: 77 additions & 0 deletions src/utils/formatters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {
DOUBLE_BACKSLASH,
REPLACEMENT_CHARACTER,
SINGLE_BACKSLASH,
} from "../typings/formatters";
import {JsonValue} from "../typings/js";


/**
* Removes all backslashes from a string. Purpose is to remove escape character preceding
* other reserved characters.
*
* @param str
* @return Modified string.
*/
const removeBackslash = (str: string): string => {
return str.replaceAll(SINGLE_BACKSLASH, "");
};

/**
* Replaces all replacement characters with a single backslash. Purpose is to remove, albeit
* indirectly through intermediate replacement character, escape character in front of a backslash
* character.
*
* @param str
* @return Modified string.
*/
const replaceReplacementCharacter = (str: string): string => {
return str.replaceAll(REPLACEMENT_CHARACTER, "\\");
};

/**
* Removes escape characters from a string.
*
* @param str
* @return Modified string.
*/
const removeEscapeCharacters = (str: string): string => {
// `removeBackslash()`, which removes all backlashes, is called before
// `replaceReplacementCharacter()` to prevent removal of escaped backslashes.
return replaceReplacementCharacter(removeBackslash(str));
};

/**
* Replaces all escaped backslashes with replacement character. Replacement character is a rare
* character that is unlikely to be in user string. Writing regex to distinguish between
* a single escape character ("\") and an escaped backslash ("\\") is challenging especially
* when they are in series. It is simpler to just replace escaped backslashes with a rare character
* and add them back after parsing user string with regex is finished.
*
* @param string
* @return Modified string.
*/
const replaceDoubleBacklash = (string: string): string => {
return string.replaceAll(DOUBLE_BACKSLASH, REPLACEMENT_CHARACTER);
};


/**
* Converts a JSON value to its string representation.
*
* @param input
* @return
*/
const jsonValueToString = (input: JsonValue | undefined): string => {
// Behaviour is different for `undefined`.
return "object" === typeof input ?
JSON.stringify(input) :
String(input);
};


export {
jsonValueToString,
removeEscapeCharacters,
replaceDoubleBacklash,
};
Loading