Skip to content

Commit

Permalink
First run of Deno formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
legowerewolf committed Dec 4, 2020
1 parent cb1582c commit 3613377
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 184 deletions.
92 changes: 47 additions & 45 deletions classic-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,82 +13,84 @@ type Writer<T> = ((data: T) => void) | { write: (data: T) => void };
* @param writer writer to identify output function for
*/
const getWriteFunc = <T>(writer: Writer<T>) =>
"write" in writer ? writer.write.bind(writer) : writer;
"write" in writer ? writer.write.bind(writer) : writer;

/**
* Take a function and an object and produce a function with properties.
* @param func the function to attach properties to
* @param obj an object containing properties to copy to the function
*/
const enrichFunction = <F extends Function, O>(func: F, obj: O): F & O =>
Object.assign(func, obj);
Object.assign(func, obj);

/**
* A `Ratlogger` is a function that takes the components of a `RatlogData` and
* does something with it. It also exposes a `tag` property-function which produces
* an identical `Ratlogger` with the added tags.
*/
export type Ratlogger = ((
message: Stringable,
fields?: RatlogData["fields"],
...tags: Stringable[]
) => void) & { tag: (...tags: Stringable[]) => Ratlogger };
export type Ratlogger =
& ((
message: Stringable,
fields?: RatlogData["fields"],
...tags: Stringable[]
) => void)
& { tag: (...tags: Stringable[]) => Ratlogger };

/**
* Constructor for more customizable logger instances.
* @param writer a writable stream or function that can take RatlogData
* @param tags a list of tags to apply to every output from this logger
*/
const generateRatlogger = (
writer: Writer<RatlogData>,
...tags: Stringable[]
writer: Writer<RatlogData>,
...tags: Stringable[]
): Ratlogger => {
let originalTags = tags;
let originalTags = tags;

return enrichFunction(
(
message: Stringable,
fields?: RatlogData["fields"],
...tags: Stringable[]
): void => {
getWriteFunc(writer)({
message,
fields,
tags: originalTags.concat(tags),
});
},
{
tag: (
/** a list of tags to apply to every output from this logger */
...tags: Stringable[]
): Ratlogger => generateRatlogger(writer, ...originalTags.concat(tags)),
}
);
return enrichFunction(
(
message: Stringable,
fields?: RatlogData["fields"],
...tags: Stringable[]
): void => {
getWriteFunc(writer)({
message,
fields,
tags: originalTags.concat(tags),
});
},
{
tag: (
/** a list of tags to apply to every output from this logger */
...tags: Stringable[]
): Ratlogger => generateRatlogger(writer, ...originalTags.concat(tags)),
},
);
};

const ratlog = (() => {
return enrichFunction(
/**
return enrichFunction(
/**
* @param writer a writable stream or function
* @param tags a list of tags to apply to every output from this logger
* @returns a logging function bound to the writer
*/
(writer: Writer<string>, ...tags: Stringable[]) =>
generateRatlogger(
(data: RatlogData) => getWriteFunc(writer)(Ratlog.format(data)),
...tags
),
{
/** Constructor for more customizable logger instances. */
logger: generateRatlogger,
(writer: Writer<string>, ...tags: Stringable[]) =>
generateRatlogger(
(data: RatlogData) => getWriteFunc(writer)(Ratlog.format(data)),
...tags,
),
{
/** Constructor for more customizable logger instances. */
logger: generateRatlogger,

/** Exposure of the core Ratlog string formatter. */
stringify: Ratlog.format,
/** Exposure of the core Ratlog string formatter. */
stringify: Ratlog.format,

/** Exposure of the core Ratlog parser. */
parse: Ratlog.parse,
}
);
/** Exposure of the core Ratlog parser. */
parse: Ratlog.parse,
},
);
})();

export default ratlog;
120 changes: 61 additions & 59 deletions ratlog.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
escape,
escapeField,
escapeMessage,
escapeTag,
unescape,
unescapeField,
unescapeMessage,
unescapeTag,
escape,
escapeField,
escapeMessage,
escapeTag,
unescape,
unescapeField,
unescapeMessage,
unescapeTag,
} from "./stringmanip.ts";

/**
Expand All @@ -20,78 +20,80 @@ export type Stringable = string | { toString: () => string };
* The base Ratlog data type. All logs are serialized from and parsed to objects of this type.
*/
export interface RatlogData {
message: Stringable;
tags?: Stringable[];
fields?: Record<string, Stringable | null>;
message: Stringable;
tags?: Stringable[];
fields?: Record<string, Stringable | null>;
}

export default class Ratlog {
/**
/**
* Take a 'line' of Ratlog data and format it for output.
* @param data the log line to format
*/
static format(data: RatlogData): string {
let tagString =
data.tags?.length ?? 0 > 0
? `[${(data.tags ?? [])
.map((tag) => escapeTag(tag.toString()))
.join("|")}] `
: ``;
static format(data: RatlogData): string {
let tagString = data.tags?.length ?? 0 > 0
? `[${
(data.tags ?? [])
.map((tag) => escapeTag(tag.toString()))
.join("|")
}] `
: ``;

let messageString = escapeMessage(data.message.toString() ?? "");
let messageString = escapeMessage(data.message.toString() ?? "");

let fieldString = Object.entries(data.fields ?? {})
.map((entry) =>
entry.map((subentry) =>
subentry != null ? escapeField(subentry.toString()) : subentry
)
)
.map((entry) => `${entry[0]}${entry[1] != null ? `: ${entry[1]}` : ``}`)
.reduce((prev, cur) => `${prev} | ${cur}`, "");
let fieldString = Object.entries(data.fields ?? {})
.map((entry) =>
entry.map((subentry) =>
subentry != null ? escapeField(subentry.toString()) : subentry
)
)
.map((entry) => `${entry[0]}${entry[1] != null ? `: ${entry[1]}` : ``}`)
.reduce((prev, cur) => `${prev} | ${cur}`, "");

return escape("\n")(tagString + messageString + fieldString) + "\n";
}
return escape("\n")(tagString + messageString + fieldString) + "\n";
}

/**
/**
* Take a string and parse it.
*
* Known to work on standards-compliant Ratlog formatter output. Not guaranteed to work with log data that doesn't meet the spec.
*
* @param logline a line of text to parse as Ratlog data
*/
static parse(logline: string): RatlogData {
let data: Partial<RatlogData> = {};
static parse(logline: string): RatlogData {
let data: Partial<RatlogData> = {};

logline = logline.replace(/\n$/, ""); // Trim off the newline at the end
logline = logline.replace(/\n$/, ""); // Trim off the newline at the end

logline = unescape("\n")(logline);
logline = unescape("\n")(logline);

let tagSection = logline.match(/^\[(.*(?<!\\))\] ?/);
if (tagSection) {
data.tags = tagSection[1].split(/(?<!\\)\|/g).map(unescapeTag);
logline = logline.substring(tagSection[0].length);
}
let tagSection = logline.match(/^\[(.*(?<!\\))\] ?/);
if (tagSection) {
data.tags = tagSection[1].split(/(?<!\\)\|/g).map(unescapeTag);
logline = logline.substring(tagSection[0].length);
}

let messageSection = logline.match(/.*?(?= \|)/);
let messageString = messageSection ? messageSection[0] : logline;
logline = logline.substring(messageString.length);
data.message = unescapeMessage(messageString);
let messageSection = logline.match(/.*?(?= \|)/);
let messageString = messageSection ? messageSection[0] : logline;
logline = logline.substring(messageString.length);
data.message = unescapeMessage(messageString);

if (logline.length > 0)
data.fields = logline
.split(/ (?<!\\)\| /g)
.slice(1)
.reduce((fields: RatlogData["fields"], elem) => {
let parts = elem.split(/(?<!\\): /);
if (logline.length > 0) {
data.fields = logline
.split(/ (?<!\\)\| /g)
.slice(1)
.reduce((fields: RatlogData["fields"], elem) => {
let parts = elem.split(/(?<!\\): /);

return {
...fields,
[unescapeField(parts[0])]: parts[1]
? unescapeField(parts[1])
: null,
};
}, {});
return {
...fields,
[unescapeField(parts[0])]: parts[1]
? unescapeField(parts[1])
: null,
};
}, {});
}

return data as RatlogData;
}
return data as RatlogData;
}
}
56 changes: 29 additions & 27 deletions stringmanip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,60 @@
* @param mut an array of string transformation functions to be applied left-to-right to `str`
*/
export const apply = (str: string, mut: ((str: string) => string)[]) =>
mut.reduce((prev, func) => func(prev), str);
mut.reduce((prev, func) => func(prev), str);

/**
* Generate a function that escapes a given character for input strings
* @param symbol a symbol (character) to generate an escape function for
*/
export const escape = (symbol: string) => (
/** A string to escape */ input: string
) => {
switch (symbol) {
case "\n":
return input.replaceAll("\n", `\\n`);
default:
return input.replaceAll(symbol, `\\${symbol}`);
}
};
export const escape = (symbol: string) =>
(
/** A string to escape */ input: string,
) => {
switch (symbol) {
case "\n":
return input.replaceAll("\n", `\\n`);
default:
return input.replaceAll(symbol, `\\${symbol}`);
}
};

/**
* Generate a function that unescapes a given character for input strings
* @param symbol a symbol (character) to generate an unescape function for
*/
export const unescape = (symbol: string) => (
/** A string to unescape */ input: string
) => {
switch (symbol) {
case "\n":
return input.replaceAll(`\\n`, `\n`);
default:
return input.replaceAll(`\\${symbol}`, symbol);
}
};
export const unescape = (symbol: string) =>
(
/** A string to unescape */ input: string,
) => {
switch (symbol) {
case "\n":
return input.replaceAll(`\\n`, `\n`);
default:
return input.replaceAll(`\\${symbol}`, symbol);
}
};

/** Escape symbols unsafe for tags */
export const escapeTag = (tag: string) =>
apply(tag, [escape("]"), escape("|")]);
apply(tag, [escape("]"), escape("|")]);

/** Escape symbols unsafe for messages */
export const escapeMessage = (message: string) =>
apply(message, [escape("["), escape("|")]);
apply(message, [escape("["), escape("|")]);

/** Escape symbols unsafe for fields */
export const escapeField = (fieldval: string) =>
apply(fieldval, [escape(":"), escape("|")]);
apply(fieldval, [escape(":"), escape("|")]);

/** Unescape symbols unsafe for tags */
export const unescapeTag = (tag: string) =>
apply(tag, [unescape("]"), unescape("|")]);
apply(tag, [unescape("]"), unescape("|")]);

/** Unescape symbols unsafe for messages */
export const unescapeMessage = (message: string) =>
apply(message, [unescape("["), unescape("|")]);
apply(message, [unescape("["), unescape("|")]);

/** Unescape symbols unsafe for fields */
export const unescapeField = (fieldpart: string) =>
apply(fieldpart, [unescape(":"), unescape("|")]);
apply(fieldpart, [unescape(":"), unescape("|")]);
Loading

0 comments on commit 3613377

Please sign in to comment.