From 48558ce533379e39e3c59659555e3c98cd0b30b8 Mon Sep 17 00:00:00 2001 From: Min Van Date: Thu, 4 Sep 2025 15:27:28 +0700 Subject: [PATCH 1/2] add addTimestampsToConsoleMethods --- api-extractor/js-utils.api.json | 24 +++++ api-extractor/js-utils.api.md | 3 + .../js-utils.addtimestampstoconsolemethods.md | 19 ++++ docs/js-utils.md | 13 +++ src/addTimestampsToConsoleMethods.ts | 88 +++++++++++++++++++ src/index.ts | 1 + 6 files changed, 148 insertions(+) create mode 100644 docs/js-utils.addtimestampstoconsolemethods.md create mode 100644 src/addTimestampsToConsoleMethods.ts diff --git a/api-extractor/js-utils.api.json b/api-extractor/js-utils.api.json index 7c2c558..697f743 100644 --- a/api-extractor/js-utils.api.json +++ b/api-extractor/js-utils.api.json @@ -172,6 +172,30 @@ "name": "", "preserveMemberOrder": false, "members": [ + { + "kind": "Function", + "canonicalReference": "@asl-19/js-utils!addTimestampsToConsoleMethods:function(1)", + "docComment": "/**\n * Add timestamps to console.log, console.info, console.warn, and console.error messages.\n *\n * If a message already starts with a timestamp (in the format added by this function), another timestamp will not be added.\n *\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "addTimestampsToConsoleMethods: () => " + }, + { + "kind": "Content", + "text": "void" + } + ], + "fileUrlPath": "dist/addTimestampsToConsoleMethods.d.ts", + "returnTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [], + "name": "addTimestampsToConsoleMethods" + }, { "kind": "Function", "canonicalReference": "@asl-19/js-utils!asType:function(1)", diff --git a/api-extractor/js-utils.api.md b/api-extractor/js-utils.api.md index d653288..9ad8add 100644 --- a/api-extractor/js-utils.api.md +++ b/api-extractor/js-utils.api.md @@ -6,6 +6,9 @@ import { ParsedUrlQuery } from 'querystring'; +// @public +export const addTimestampsToConsoleMethods: () => void; + // @public export const asType: (value: T) => T; diff --git a/docs/js-utils.addtimestampstoconsolemethods.md b/docs/js-utils.addtimestampstoconsolemethods.md new file mode 100644 index 0000000..0d73b5e --- /dev/null +++ b/docs/js-utils.addtimestampstoconsolemethods.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [@asl-19/js-utils](./js-utils.md) > [addTimestampsToConsoleMethods](./js-utils.addtimestampstoconsolemethods.md) + +## addTimestampsToConsoleMethods() function + +Add timestamps to console.log, console.info, console.warn, and console.error messages. + +If a message already starts with a timestamp (in the format added by this function), another timestamp will not be added. + +**Signature:** + +```typescript +addTimestampsToConsoleMethods: () => void +``` +**Returns:** + +void + diff --git a/docs/js-utils.md b/docs/js-utils.md index 5fe13ef..5d8aec3 100644 --- a/docs/js-utils.md +++ b/docs/js-utils.md @@ -23,6 +23,19 @@ Description +[addTimestampsToConsoleMethods()](./js-utils.addtimestampstoconsolemethods.md) + + + + +Add timestamps to console.log, console.info, console.warn, and console.error messages. + +If a message already starts with a timestamp (in the format added by this function), another timestamp will not be added. + + + + + [asType(value)](./js-utils.astype.md) diff --git a/src/addTimestampsToConsoleMethods.ts b/src/addTimestampsToConsoleMethods.ts new file mode 100644 index 0000000..e2e0e6f --- /dev/null +++ b/src/addTimestampsToConsoleMethods.ts @@ -0,0 +1,88 @@ +// eslint-disable-next-line no-console +const originalConsoleLog = console.log; +const originalConsoleInfo = console.info; +const originalConsoleWarn = console.warn; +const originalConsoleError = console.error; + +const datePartsRegExp = + /(?\d\d\d\d-\d\d-\d\d)T(?\d\d:\d\d:\d\d)/; + +/** + * Matches strings that start with a date stamp like "[2025-01-01 01:23:45" + * + * (Note the lack of trailing square bracket since serverLog can include URL + * path after the timestamp but before the closing square bracket). + */ +const startsWithDateStampRegExp = /^\[\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/; + +const getFormattedCurrentDateTimePrefix = () => { + const date = new Date(); + + const datePartsMatch = datePartsRegExp.exec(date.toISOString()); + + return datePartsMatch && + typeof datePartsMatch.groups === "object" && + typeof datePartsMatch.groups.date === "string" && + typeof datePartsMatch.groups.hoursMinutesSeconds === "string" + ? `[${datePartsMatch.groups.date} ${datePartsMatch.groups.hoursMinutesSeconds}]` + : "[????-??-?? ??:??:??]"; // This shouldn’t ever happen! +}; + +/** + * @param {{ + * args: Array; + * consoleMethod: typeof console.log } + * } params} + * @returns void + */ +const callConsoleMethodWithTimestampPrefixIfNotAlreadyTimestamped = ({ + args, + consoleMethod, +}: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + args: Array; + consoleMethod: typeof console.log; +}) => { + if (typeof args[0] === "string" && startsWithDateStampRegExp.test(args[0])) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + consoleMethod(...args); + } else { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + consoleMethod(getFormattedCurrentDateTimePrefix(), ...args); + } +}; + +/** + * + * Add timestamps to console.log, console.info, console.warn, and console.error + * messages. + * + * If a message already starts with a timestamp (in the format added by this + * function), another timestamp will not be added. + * @public + */ +const addTimestampsToConsoleMethods = () => { + // eslint-disable-next-line no-console + console.log = (...args) => + callConsoleMethodWithTimestampPrefixIfNotAlreadyTimestamped({ + args, + consoleMethod: originalConsoleLog, + }); + console.info = (...args) => + callConsoleMethodWithTimestampPrefixIfNotAlreadyTimestamped({ + args, + consoleMethod: originalConsoleInfo, + }); + console.warn = (...args) => + callConsoleMethodWithTimestampPrefixIfNotAlreadyTimestamped({ + args, + consoleMethod: originalConsoleWarn, + }); + console.error = (...args) => + callConsoleMethodWithTimestampPrefixIfNotAlreadyTimestamped({ + args, + consoleMethod: originalConsoleError, + }); +}; + +export default addTimestampsToConsoleMethods; diff --git a/src/index.ts b/src/index.ts index 04a6037..4218939 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ * @packageDocumentation */ +export { default as addTimestampsToConsoleMethods } from "./addTimestampsToConsoleMethods.js"; export { default as asType } from "./asType.js"; export { default as cleanUrlQueryString } from "./cleanUrlQueryString.js"; export { default as constructUrl } from "./constructUrl.js"; From 8c2a5c80dea9f91d96b6661a29b6af98698ed59b Mon Sep 17 00:00:00 2001 From: Min Van Date: Thu, 4 Sep 2025 16:07:35 +0700 Subject: [PATCH 2/2] update addTimestampsToConsoleMethods --- src/addTimestampsToConsoleMethods.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/addTimestampsToConsoleMethods.ts b/src/addTimestampsToConsoleMethods.ts index e2e0e6f..243ca90 100644 --- a/src/addTimestampsToConsoleMethods.ts +++ b/src/addTimestampsToConsoleMethods.ts @@ -25,9 +25,23 @@ const getFormattedCurrentDateTimePrefix = () => { typeof datePartsMatch.groups.date === "string" && typeof datePartsMatch.groups.hoursMinutesSeconds === "string" ? `[${datePartsMatch.groups.date} ${datePartsMatch.groups.hoursMinutesSeconds}]` - : "[????-??-?? ??:??:??]"; // This shouldn’t ever happen! + : "[????-??-?? ??:??:??]"; // This shouldn't ever happen! }; +/** + * TypeScript verification that the regex pattern matches the timestamp format. + * This ensures that startsWithDateStampRegExp will correctly identify timestamps + * generated by both addTimestampsToConsoleMethods and serverLog. + */ + +// Runtime verification that the regex matches the actual format +const _testTimestampFormat = getFormattedCurrentDateTimePrefix(); +if (!startsWithDateStampRegExp.test(_testTimestampFormat)) { + throw new Error( + "startsWithDateStampRegExp does not match the date format produced by getFormattedCurrentDateTimePrefix/serverLog", + ); +} + /** * @param {{ * args: Array;