diff --git a/package.json b/package.json index 1560c68..038aac0 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "scripts": { "build": "tsc --pretty", "lint": "eslint . --fix --ignore-path .gitignore", - "test": "node --test" + "test": "npm run build && node --test" }, "repository": { "url": "https://github.com/blacha/pretty-json-log" diff --git a/src/pretty/simple.ts b/src/pretty/simple.ts index 57d1d11..b1afbd8 100644 --- a/src/pretty/simple.ts +++ b/src/pretty/simple.ts @@ -11,6 +11,8 @@ function getLogStatus(level: number): string { return c.bgRed('FATAL'); } +type LogObject = Record; + export const PrettySimplePino = { Ignore: new Set([ // pino formats @@ -22,7 +24,7 @@ export const PrettySimplePino = { 'name', 'msg', ]), - formatObject(obj: Record, prefix = ''): string[] { + formatObject(obj: LogObject, prefix = ''): string[] { const kvs = []; for (const key of Object.keys(obj)) { if (PrettySimplePino.Ignore.has(key)) continue; @@ -35,9 +37,9 @@ export const PrettySimplePino = { if (typeofValue === 'number') { output = c.yellow(String(value)); } else if (typeofValue === 'string') { - output = c.green(value); + output = c.green(value as string); } else if (typeofValue === 'object') { - const subOutput = this.formatObject(value, prefix); + const subOutput = this.formatObject(value as LogObject, prefix); if (subOutput.length > 0) { output = `{ ${subOutput.join(' ')} }`; } diff --git a/src/transform.test.ts b/src/transform.test.ts new file mode 100644 index 0000000..6a544a1 --- /dev/null +++ b/src/transform.test.ts @@ -0,0 +1,23 @@ +import assert from 'node:assert'; +import { describe, it } from 'node:test'; + +import { tryGetJson } from './transform.js'; + +describe('transform', () => { + describe('tryGetJson', () => { + it('returns null for invalid JSON', () => { + assert.strictEqual(tryGetJson(''), null); + assert.strictEqual(tryGetJson('foo'), null); + assert.strictEqual(tryGetJson('{"foo":'), null); + assert.strictEqual(tryGetJson('2024-01-01T19:53:58 {"foo":'), null); + assert.strictEqual(tryGetJson('2024-01-01T19:53:58 {"foo": "bar"}}'), null); + }); + + it('returns the parsed JSON', () => { + assert.deepStrictEqual(tryGetJson('{}'), {}); + assert.deepStrictEqual(tryGetJson('{"foo": "bar"}'), { foo: 'bar' }); + assert.deepStrictEqual(tryGetJson('2024-01-01T19:53:58 {"foo": "bar"}'), { foo: 'bar' }); + assert.deepStrictEqual(tryGetJson('2024-01-01T19:53:58 {"foo": "bar"} garbage'), { foo: 'bar' }); + }); + }); +}); diff --git a/src/transform.ts b/src/transform.ts index 12eced1..e0cf96b 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -4,9 +4,15 @@ import { StringDecoder } from 'string_decoder'; import { LogMessage, LogSkipLine } from './msg.js'; import { PrettySimple } from './pretty/simple.js'; -function tryGetJson(data: string): null | Record { +export function tryGetJson(data: string): null | Record { + const jsonStart = data.indexOf('{'); + if (jsonStart === -1) return null; + + const jsonEnd = data.lastIndexOf('}'); + if (jsonEnd === -1) return null; + try { - return JSON.parse(data); + return JSON.parse(data.slice(jsonStart, jsonEnd + 1)); } catch { return null; }