@logtape/testing 2.2.0-dev.751 → 2.2.0-dev.757
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mod.cjs +17 -7
- package/dist/mod.js +17 -7
- package/dist/mod.js.map +1 -1
- package/package.json +3 -3
package/dist/mod.cjs
CHANGED
|
@@ -92,13 +92,15 @@ function materializeLogRecord(record) {
|
|
|
92
92
|
const message = record.message;
|
|
93
93
|
const rawMessage = record.rawMessage;
|
|
94
94
|
const descriptors = Object.getOwnPropertyDescriptors(record);
|
|
95
|
+
if (!hasStringAccessorDescriptor(descriptors)) return record;
|
|
95
96
|
const messageDescriptor = descriptors.message;
|
|
96
97
|
const rawMessageDescriptor = descriptors.rawMessage;
|
|
97
|
-
if (isDataDescriptor(messageDescriptor) && isDataDescriptor(rawMessageDescriptor)) return record;
|
|
98
98
|
const snapshotDescriptors = Object.create(null);
|
|
99
99
|
for (const key of Reflect.ownKeys(descriptors)) {
|
|
100
100
|
if (isLogRecordKey(key)) continue;
|
|
101
|
-
|
|
101
|
+
const descriptor = descriptors[key];
|
|
102
|
+
if (descriptor == null) continue;
|
|
103
|
+
snapshotDescriptors[key] = isDataDescriptor(descriptor) ? descriptor : materializedDescriptor(Reflect.get(record, key), descriptor);
|
|
102
104
|
}
|
|
103
105
|
Object.assign(snapshotDescriptors, {
|
|
104
106
|
category: materializedDescriptor(record.category, descriptors.category),
|
|
@@ -110,6 +112,13 @@ function materializeLogRecord(record) {
|
|
|
110
112
|
});
|
|
111
113
|
return Object.defineProperties(Object.create(Object.getPrototypeOf(record)), snapshotDescriptors);
|
|
112
114
|
}
|
|
115
|
+
function hasStringAccessorDescriptor(descriptors) {
|
|
116
|
+
for (const key of Object.getOwnPropertyNames(descriptors)) {
|
|
117
|
+
const descriptor = descriptors[key];
|
|
118
|
+
if (descriptor != null && !isDataDescriptor(descriptor)) return true;
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
113
122
|
function isDataDescriptor(descriptor) {
|
|
114
123
|
return descriptor != null && "value" in descriptor;
|
|
115
124
|
}
|
|
@@ -160,7 +169,7 @@ function matchesProperties(properties, record, matcher) {
|
|
|
160
169
|
const props = properties ?? {};
|
|
161
170
|
if (typeof matcher === "function") return matcher(props, record);
|
|
162
171
|
for (const key of Object.keys(matcher)) {
|
|
163
|
-
if (!Object.
|
|
172
|
+
if (!Object.prototype.hasOwnProperty.call(props, key)) return false;
|
|
164
173
|
if (!matchesPropertyValue(props[key], matcher[key])) return false;
|
|
165
174
|
}
|
|
166
175
|
return true;
|
|
@@ -284,14 +293,15 @@ function formatSet(value) {
|
|
|
284
293
|
}
|
|
285
294
|
}
|
|
286
295
|
function safeJsonStringify(value) {
|
|
287
|
-
const
|
|
288
|
-
return JSON.stringify(value, (_key, item)
|
|
296
|
+
const ancestors = [];
|
|
297
|
+
return JSON.stringify(value, function(_key, item) {
|
|
289
298
|
if (typeof item === "bigint") return `${item}n`;
|
|
290
299
|
if (item instanceof RegExp) return String(item);
|
|
291
300
|
if (item instanceof Error) return `${item.name}: ${item.message}`;
|
|
292
301
|
if (typeof item === "object" && item != null) {
|
|
293
|
-
|
|
294
|
-
|
|
302
|
+
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) ancestors.pop();
|
|
303
|
+
if (ancestors.includes(item)) return "[Circular]";
|
|
304
|
+
ancestors.push(item);
|
|
295
305
|
if (item instanceof Map) return formatMapContents(item);
|
|
296
306
|
if (item instanceof Set) return Array.from(item);
|
|
297
307
|
}
|
package/dist/mod.js
CHANGED
|
@@ -91,13 +91,15 @@ function materializeLogRecord(record) {
|
|
|
91
91
|
const message = record.message;
|
|
92
92
|
const rawMessage = record.rawMessage;
|
|
93
93
|
const descriptors = Object.getOwnPropertyDescriptors(record);
|
|
94
|
+
if (!hasStringAccessorDescriptor(descriptors)) return record;
|
|
94
95
|
const messageDescriptor = descriptors.message;
|
|
95
96
|
const rawMessageDescriptor = descriptors.rawMessage;
|
|
96
|
-
if (isDataDescriptor(messageDescriptor) && isDataDescriptor(rawMessageDescriptor)) return record;
|
|
97
97
|
const snapshotDescriptors = Object.create(null);
|
|
98
98
|
for (const key of Reflect.ownKeys(descriptors)) {
|
|
99
99
|
if (isLogRecordKey(key)) continue;
|
|
100
|
-
|
|
100
|
+
const descriptor = descriptors[key];
|
|
101
|
+
if (descriptor == null) continue;
|
|
102
|
+
snapshotDescriptors[key] = isDataDescriptor(descriptor) ? descriptor : materializedDescriptor(Reflect.get(record, key), descriptor);
|
|
101
103
|
}
|
|
102
104
|
Object.assign(snapshotDescriptors, {
|
|
103
105
|
category: materializedDescriptor(record.category, descriptors.category),
|
|
@@ -109,6 +111,13 @@ function materializeLogRecord(record) {
|
|
|
109
111
|
});
|
|
110
112
|
return Object.defineProperties(Object.create(Object.getPrototypeOf(record)), snapshotDescriptors);
|
|
111
113
|
}
|
|
114
|
+
function hasStringAccessorDescriptor(descriptors) {
|
|
115
|
+
for (const key of Object.getOwnPropertyNames(descriptors)) {
|
|
116
|
+
const descriptor = descriptors[key];
|
|
117
|
+
if (descriptor != null && !isDataDescriptor(descriptor)) return true;
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
112
121
|
function isDataDescriptor(descriptor) {
|
|
113
122
|
return descriptor != null && "value" in descriptor;
|
|
114
123
|
}
|
|
@@ -159,7 +168,7 @@ function matchesProperties(properties, record, matcher) {
|
|
|
159
168
|
const props = properties ?? {};
|
|
160
169
|
if (typeof matcher === "function") return matcher(props, record);
|
|
161
170
|
for (const key of Object.keys(matcher)) {
|
|
162
|
-
if (!Object.
|
|
171
|
+
if (!Object.prototype.hasOwnProperty.call(props, key)) return false;
|
|
163
172
|
if (!matchesPropertyValue(props[key], matcher[key])) return false;
|
|
164
173
|
}
|
|
165
174
|
return true;
|
|
@@ -283,14 +292,15 @@ function formatSet(value) {
|
|
|
283
292
|
}
|
|
284
293
|
}
|
|
285
294
|
function safeJsonStringify(value) {
|
|
286
|
-
const
|
|
287
|
-
return JSON.stringify(value, (_key, item)
|
|
295
|
+
const ancestors = [];
|
|
296
|
+
return JSON.stringify(value, function(_key, item) {
|
|
288
297
|
if (typeof item === "bigint") return `${item}n`;
|
|
289
298
|
if (item instanceof RegExp) return String(item);
|
|
290
299
|
if (item instanceof Error) return `${item.name}: ${item.message}`;
|
|
291
300
|
if (typeof item === "object" && item != null) {
|
|
292
|
-
|
|
293
|
-
|
|
301
|
+
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) ancestors.pop();
|
|
302
|
+
if (ancestors.includes(item)) return "[Circular]";
|
|
303
|
+
ancestors.push(item);
|
|
294
304
|
if (item instanceof Map) return formatMapContents(item);
|
|
295
305
|
if (item instanceof Set) return Array.from(item);
|
|
296
306
|
}
|
package/dist/mod.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.js","names":["messageFormatter: TextFormatter","records: LogRecord[]","sink: Sink","record: LogRecord","match: LogRecordMatch","descriptor: PropertyDescriptor | undefined","key: PropertyKey","value: unknown","category: readonly string[]","expected: string | readonly string[] | RegExp","prefix: string | readonly string[]","category: string | readonly string[]","matcher: string | RegExp | ((record: LogRecord) => boolean)","text: string","matcher: string | RegExp","properties: Readonly<Record<string, unknown>> | null | undefined","matcher: Readonly<Record<string, unknown>> | PropertyMatcher","props: Readonly<Record<string, unknown>>","actual: unknown","expected: unknown","pattern: RegExp","rawMessage: string | TemplateStringsArray","lines: string[]","category: string | readonly string[] | RegExp","records: readonly LogRecord[]","properties: Readonly<Record<string, unknown>>","key: string","error: unknown","count: number","noun: string","value: ReadonlyMap<unknown, unknown>","value: ReadonlySet<unknown>","item: unknown"],"sources":["../src/mod.ts"],"sourcesContent":["import {\n getTextFormatter,\n type LogLevel,\n type LogRecord,\n type Sink,\n type TextFormatter,\n} from \"@logtape/logtape\";\n\nconst messageFormatter: TextFormatter = getTextFormatter({\n format: ({ message }) => message,\n lineEnding: \"lf\",\n timestamp: \"none\",\n});\n\n/**\n * A predicate that matches log record properties.\n *\n * The first argument is the resolved properties object. The second argument\n * is the full log record for cases where the predicate needs category, level,\n * or message context.\n *\n * @since 2.2.0\n */\nexport type PropertyMatcher = (\n properties: Readonly<Record<string, unknown>>,\n record: LogRecord,\n) => boolean;\n\n/**\n * A matcher for records collected by a {@link LogRecorder}.\n *\n * Object property matching is shallow: every own string key in the matcher\n * must exist on the record properties and match by value. Most values are\n * compared with `Object.is()`, `Date` values are compared by timestamp, and\n * regular expression matcher values match string property values. Use a\n * {@link PropertyMatcher} when a test needs absence checks or deeper matching.\n *\n * @since 2.2.0\n */\nexport interface LogRecordMatch {\n /**\n * Exact category matcher. A string is matched against the dot-joined\n * category, while an array is matched segment by segment. A regular\n * expression is tested against the dot-joined category.\n */\n readonly category?: string | readonly string[] | RegExp;\n\n /**\n * Category prefix matcher. A string is split on dots, while an array is\n * matched segment by segment.\n */\n readonly categoryPrefix?: string | readonly string[];\n\n /**\n * Exact severity level matcher.\n */\n readonly level?: LogLevel;\n\n /**\n * Rendered message matcher. String and regular expression matchers are\n * applied to the rendered message, using the same value rendering as\n * LogTape's default text formatter. A predicate receives the full record.\n */\n readonly message?: string | RegExp | ((record: LogRecord) => boolean);\n\n /**\n * Raw message matcher. A string record is matched directly. A tagged\n * template record is matched against the concatenated template strings.\n */\n readonly rawMessage?: string | RegExp;\n\n /**\n * Shallow property matcher or predicate.\n */\n readonly properties?: Readonly<Record<string, unknown>> | PropertyMatcher;\n\n /**\n * Full-record predicate for custom checks.\n */\n readonly predicate?: (record: LogRecord) => boolean;\n}\n\n/**\n * A test recorder for LogTape records.\n *\n * @since 2.2.0\n */\nexport interface LogRecorder {\n /**\n * A sink that appends each received record to {@link LogRecorder.records}.\n */\n readonly sink: Sink;\n\n /**\n * A snapshot of records collected so far, in sink call order.\n */\n readonly records: readonly LogRecord[];\n\n /**\n * Removes all collected records.\n */\n clear(): void;\n\n /**\n * Returns collected records and clears the recorder.\n */\n take(): readonly LogRecord[];\n\n /**\n * Finds the first collected record matching the given matcher.\n *\n * @param match The matcher to apply.\n * @returns The first matching record, or `undefined`.\n */\n find(match: LogRecordMatch): LogRecord | undefined;\n\n /**\n * Finds all collected records matching the given matcher.\n *\n * @param match The matcher to apply.\n * @returns All matching records in collection order.\n */\n filter(match: LogRecordMatch): readonly LogRecord[];\n\n /**\n * Asserts that at least one collected record matches the given matcher.\n *\n * @param match The matcher to apply.\n * @throws {Error} If no matching record exists.\n */\n assertLogged(match: LogRecordMatch): void;\n\n /**\n * Asserts that no collected record matches the given matcher.\n *\n * @param match The matcher to apply.\n * @throws {Error} If a matching record exists.\n */\n assertNotLogged(match: LogRecordMatch): void;\n}\n\n/**\n * Creates a LogTape test recorder.\n *\n * @example\n * ```ts\n * import { configure, getLogger, reset } from \"@logtape/logtape\";\n * import { createLogRecorder } from \"@logtape/testing\";\n *\n * const recorder = createLogRecorder();\n *\n * try {\n * await configure({\n * sinks: { recorder: recorder.sink },\n * loggers: [\n * { category: [\"my-lib\"], lowestLevel: \"debug\", sinks: [\"recorder\"] },\n * ],\n * });\n *\n * getLogger([\"my-lib\"]).info(\"User {userId} logged in.\", {\n * userId: 123,\n * });\n *\n * recorder.assertLogged({\n * category: [\"my-lib\"],\n * level: \"info\",\n * message: \"User 123 logged in.\",\n * properties: { userId: 123 },\n * });\n * } finally {\n * await reset();\n * }\n * ```\n *\n * @returns A recorder with a sink and assertion helpers.\n * @since 2.2.0\n */\nexport function createLogRecorder(): LogRecorder {\n const records: LogRecord[] = [];\n const sink: Sink = (record: LogRecord): void => {\n records.push(materializeLogRecord(record));\n };\n\n return {\n sink,\n get records(): readonly LogRecord[] {\n return records.slice();\n },\n clear(): void {\n records.length = 0;\n },\n take(): readonly LogRecord[] {\n return records.splice(0);\n },\n find(match: LogRecordMatch): LogRecord | undefined {\n return records.find((record) => matchesLogRecord(record, match));\n },\n filter(match: LogRecordMatch): readonly LogRecord[] {\n return records.filter((record) => matchesLogRecord(record, match));\n },\n assertLogged(match: LogRecordMatch): void {\n if (records.some((record) => matchesLogRecord(record, match))) return;\n\n throw new Error(\n [\n \"Expected a LogTape record matching:\",\n formatMatcher(match),\n \"\",\n `Recorded ${formatCount(records.length, \"record\")}:`,\n formatRecords(records),\n ].join(\"\\n\"),\n );\n },\n assertNotLogged(match: LogRecordMatch): void {\n const matching = records.filter((record) =>\n matchesLogRecord(record, match)\n );\n if (matching.length < 1) return;\n\n throw new Error(\n [\n \"Expected no LogTape record matching:\",\n formatMatcher(match),\n \"\",\n `Found ${formatCount(matching.length, \"matching record\")}:`,\n formatRecords(matching),\n ].join(\"\\n\"),\n );\n },\n };\n}\n\nfunction materializeLogRecord(record: LogRecord): LogRecord {\n const message = record.message;\n const rawMessage = record.rawMessage;\n const descriptors = Object.getOwnPropertyDescriptors(\n record,\n ) as PropertyDescriptorMap;\n const messageDescriptor = descriptors.message;\n const rawMessageDescriptor = descriptors.rawMessage;\n if (\n isDataDescriptor(messageDescriptor) &&\n isDataDescriptor(rawMessageDescriptor)\n ) {\n return record;\n }\n const snapshotDescriptors = Object.create(null) as PropertyDescriptorMap;\n for (const key of Reflect.ownKeys(descriptors)) {\n if (isLogRecordKey(key)) continue;\n snapshotDescriptors[key] = descriptors[key];\n }\n Object.assign(snapshotDescriptors, {\n category: materializedDescriptor(record.category, descriptors.category),\n level: materializedDescriptor(record.level, descriptors.level),\n message: materializedDescriptor(message, messageDescriptor),\n rawMessage: materializedDescriptor(rawMessage, rawMessageDescriptor),\n timestamp: materializedDescriptor(record.timestamp, descriptors.timestamp),\n properties: materializedDescriptor(\n record.properties,\n descriptors.properties,\n ),\n });\n return Object.defineProperties(\n Object.create(Object.getPrototypeOf(record)),\n snapshotDescriptors,\n ) as LogRecord;\n}\n\nfunction isDataDescriptor(\n descriptor: PropertyDescriptor | undefined,\n): descriptor is PropertyDescriptor & { readonly value: unknown } {\n return descriptor != null && \"value\" in descriptor;\n}\n\nfunction isLogRecordKey(key: PropertyKey): key is keyof LogRecord {\n return key === \"category\" ||\n key === \"level\" ||\n key === \"message\" ||\n key === \"rawMessage\" ||\n key === \"timestamp\" ||\n key === \"properties\";\n}\n\nfunction materializedDescriptor(\n value: unknown,\n descriptor: PropertyDescriptor | undefined,\n): PropertyDescriptor {\n return {\n configurable: descriptor?.configurable ?? true,\n enumerable: descriptor?.enumerable ?? true,\n value,\n writable: isDataDescriptor(descriptor) ? descriptor.writable : true,\n };\n}\n\nfunction matchesLogRecord(record: LogRecord, match: LogRecordMatch): boolean {\n if (\n match.category != null &&\n !matchesCategory(record.category, match.category)\n ) {\n return false;\n }\n if (\n match.categoryPrefix != null &&\n !matchesCategoryPrefix(record.category, match.categoryPrefix)\n ) {\n return false;\n }\n if (match.level != null && record.level !== match.level) return false;\n if (\n match.message != null &&\n !matchesMessage(record, match.message)\n ) {\n return false;\n }\n if (\n match.rawMessage != null &&\n !matchesText(renderRawMessage(record.rawMessage), match.rawMessage)\n ) {\n return false;\n }\n if (\n match.properties != null &&\n !matchesProperties(record.properties, record, match.properties)\n ) {\n return false;\n }\n if (match.predicate != null && !match.predicate(record)) return false;\n return true;\n}\n\nfunction matchesCategory(\n category: readonly string[],\n expected: string | readonly string[] | RegExp,\n): boolean {\n const joinedCategory = category.join(\".\");\n if (expected instanceof RegExp) {\n return testRegExp(expected, joinedCategory);\n }\n if (typeof expected === \"string\") {\n return joinedCategory === expected;\n }\n const expectedCategory = parseCategory(expected);\n return category.length === expectedCategory.length &&\n category.every((part, index) => part === expectedCategory[index]);\n}\n\nfunction matchesCategoryPrefix(\n category: readonly string[],\n prefix: string | readonly string[],\n): boolean {\n const expectedPrefix = parseCategory(prefix);\n return expectedPrefix.length <= category.length &&\n expectedPrefix.every((part, index) => part === category[index]);\n}\n\nfunction parseCategory(\n category: string | readonly string[],\n): readonly string[] {\n if (typeof category !== \"string\") return category;\n return category === \"\" ? [] : category.split(\".\");\n}\n\nfunction matchesMessage(\n record: LogRecord,\n matcher: string | RegExp | ((record: LogRecord) => boolean),\n): boolean {\n if (typeof matcher === \"function\") return matcher(record);\n return matchesText(renderMessage(record), matcher);\n}\n\nfunction matchesText(text: string, matcher: string | RegExp): boolean {\n return typeof matcher === \"string\"\n ? text === matcher\n : testRegExp(matcher, text);\n}\n\nfunction matchesProperties(\n properties: Readonly<Record<string, unknown>> | null | undefined,\n record: LogRecord,\n matcher: Readonly<Record<string, unknown>> | PropertyMatcher,\n): boolean {\n const props: Readonly<Record<string, unknown>> = properties ?? {};\n if (typeof matcher === \"function\") return matcher(props, record);\n for (const key of Object.keys(matcher)) {\n if (!Object.hasOwn(props, key)) return false;\n if (!matchesPropertyValue(props[key], matcher[key])) return false;\n }\n return true;\n}\n\nfunction matchesPropertyValue(actual: unknown, expected: unknown): boolean {\n if (actual instanceof Date && expected instanceof Date) {\n return Object.is(actual.getTime(), expected.getTime());\n }\n if (typeof actual === \"string\" && expected instanceof RegExp) {\n return testRegExp(expected, actual);\n }\n return Object.is(actual, expected);\n}\n\nfunction testRegExp(pattern: RegExp, text: string): boolean {\n if (!pattern.global && !pattern.sticky) {\n return pattern.test(text);\n }\n const clone = new RegExp(pattern.source, pattern.flags);\n return clone.test(text);\n}\n\nfunction renderRawMessage(rawMessage: string | TemplateStringsArray): string {\n return typeof rawMessage === \"string\" ? rawMessage : rawMessage.join(\"\");\n}\n\nfunction renderMessage(record: LogRecord): string {\n return messageFormatter(record).slice(0, -1);\n}\n\nfunction formatMatcher(match: LogRecordMatch): string {\n const lines: string[] = [];\n if (match.category != null) {\n lines.push(` category: ${formatCategoryMatcher(match.category)}`);\n }\n if (match.categoryPrefix != null) {\n lines.push(\n ` categoryPrefix: ${\n formatCategoryValue(parseCategory(match.categoryPrefix))\n }`,\n );\n }\n if (match.level != null) lines.push(` level: ${formatValue(match.level)}`);\n if (match.message != null) {\n lines.push(` message: ${formatMessageMatcher(match.message)}`);\n }\n if (match.rawMessage != null) {\n lines.push(` rawMessage: ${formatTextMatcher(match.rawMessage)}`);\n }\n if (match.properties != null) {\n lines.push(...formatPropertiesMatcher(match.properties));\n }\n if (match.predicate != null) lines.push(\" predicate: <predicate>\");\n return lines.length < 1 ? \" <any record>\" : lines.join(\"\\n\");\n}\n\nfunction formatCategoryMatcher(\n category: string | readonly string[] | RegExp,\n): string {\n return category instanceof RegExp\n ? String(category)\n : typeof category === \"string\"\n ? formatValue(category)\n : formatCategoryValue(category);\n}\n\nfunction formatCategoryValue(category: readonly string[]): string {\n return `[${category.map((part) => formatValue(part)).join(\", \")}]`;\n}\n\nfunction formatMessageMatcher(\n matcher: string | RegExp | ((record: LogRecord) => boolean),\n): string {\n return typeof matcher === \"function\" ? \"<predicate>\" : formatTextMatcher(\n matcher,\n );\n}\n\nfunction formatTextMatcher(matcher: string | RegExp): string {\n return typeof matcher === \"string\" ? formatValue(matcher) : String(matcher);\n}\n\nfunction formatPropertiesMatcher(\n matcher: Readonly<Record<string, unknown>> | PropertyMatcher,\n): string[] {\n if (typeof matcher === \"function\") return [\" properties: <predicate>\"];\n const lines = Object.keys(matcher).map((key) =>\n ` properties.${key}: ${formatPropertyValue(matcher, key)}`\n );\n return lines.length < 1 ? [\" properties: {}\"] : lines;\n}\n\nfunction formatRecords(records: readonly LogRecord[]): string {\n if (records.length < 1) return \" <none>\";\n const lines = records.slice(0, 3).map(formatRecord);\n if (records.length > 3) {\n lines.push(` ... ${records.length - 3} more`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction formatRecord(record: LogRecord): string {\n const category = formatCategory(record.category);\n return ` [${record.level}] ${category}: ${formatMessage(record)}${\n formatProperties(record.properties)\n }`;\n}\n\nfunction formatMessage(record: LogRecord): string {\n try {\n return renderMessage(record);\n } catch (error) {\n return formatAccessError(error);\n }\n}\n\nfunction formatCategory(category: readonly string[]): string {\n return category.length < 1 ? \"<root>\" : category.join(\".\");\n}\n\nfunction formatProperties(\n properties: Readonly<Record<string, unknown>> | null | undefined,\n): string {\n const props: Readonly<Record<string, unknown>> = properties ?? {};\n const entries = Object.keys(props);\n if (entries.length < 1) return \"\";\n const summary = entries.slice(0, 3).map((key) =>\n `${key}: ${formatPropertyValue(props, key)}`\n );\n if (entries.length > 3) summary.push(`... ${entries.length - 3} more`);\n return ` {${summary.join(\", \")}}`;\n}\n\nfunction formatPropertyValue(\n properties: Readonly<Record<string, unknown>>,\n key: string,\n): string {\n try {\n return formatValue(properties[key]);\n } catch (error) {\n return formatAccessError(error);\n }\n}\n\nfunction formatAccessError(error: unknown): string {\n return `<error: ${\n error instanceof Error ? error.message : safeString(error)\n }>`;\n}\n\nfunction formatCount(count: number, noun: string): string {\n return `${count} ${noun}${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") return JSON.stringify(value);\n if (typeof value === \"number\" && !Number.isFinite(value)) {\n return String(value);\n }\n if (typeof value === \"bigint\") return `${value}n`;\n if (typeof value === \"symbol\") return String(value);\n if (value instanceof RegExp) return String(value);\n if (value instanceof Error) {\n return `${value.name}: ${value.message}`;\n }\n if (value instanceof Map) return formatMap(value);\n if (value instanceof Set) return formatSet(value);\n try {\n return safeJsonStringify(value) ?? safeString(value);\n } catch {\n return safeString(value);\n }\n}\n\nfunction formatMap(value: ReadonlyMap<unknown, unknown>): string {\n const label = `Map(${value.size})`;\n try {\n const contents = formatMapContents(value);\n return `${label} ${safeJsonStringify(contents) ?? safeString(contents)}`;\n } catch {\n return label;\n }\n}\n\nfunction formatSet(value: ReadonlySet<unknown>): string {\n const label = `Set(${value.size})`;\n try {\n const contents = Array.from(value);\n return `${label} ${safeJsonStringify(contents) ?? safeString(contents)}`;\n } catch {\n return label;\n }\n}\n\nfunction safeJsonStringify(value: unknown): string | undefined {\n const seen = new WeakSet<object>();\n return JSON.stringify(value, (_key, item: unknown) => {\n if (typeof item === \"bigint\") return `${item}n`;\n if (item instanceof RegExp) return String(item);\n if (item instanceof Error) return `${item.name}: ${item.message}`;\n if (typeof item === \"object\" && item != null) {\n if (seen.has(item)) return \"[Circular]\";\n seen.add(item);\n if (item instanceof Map) return formatMapContents(item);\n if (item instanceof Set) return Array.from(item);\n }\n return item;\n });\n}\n\nfunction formatMapContents(\n value: ReadonlyMap<unknown, unknown>,\n): Readonly<Record<string, unknown>> | readonly (readonly [string, unknown])[] {\n const entries = Array.from(\n value,\n ([key, entryValue]) => [safeString(key), entryValue] as const,\n );\n const keys = entries.map(([key]) => key);\n const uniqueKeys = new Set(keys);\n return uniqueKeys.size === keys.length\n ? Object.fromEntries(entries)\n : entries;\n}\n\nfunction safeString(value: unknown): string {\n try {\n return String(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mod.js","names":["messageFormatter: TextFormatter","records: LogRecord[]","sink: Sink","record: LogRecord","match: LogRecordMatch","descriptors: PropertyDescriptorMap","descriptor: PropertyDescriptor | undefined","key: PropertyKey","value: unknown","category: readonly string[]","expected: string | readonly string[] | RegExp","prefix: string | readonly string[]","category: string | readonly string[]","matcher: string | RegExp | ((record: LogRecord) => boolean)","text: string","matcher: string | RegExp","properties: Readonly<Record<string, unknown>> | null | undefined","matcher: Readonly<Record<string, unknown>> | PropertyMatcher","props: Readonly<Record<string, unknown>>","actual: unknown","expected: unknown","pattern: RegExp","rawMessage: string | TemplateStringsArray","lines: string[]","category: string | readonly string[] | RegExp","records: readonly LogRecord[]","properties: Readonly<Record<string, unknown>>","key: string","error: unknown","count: number","noun: string","value: ReadonlyMap<unknown, unknown>","value: ReadonlySet<unknown>","ancestors: object[]","_key: string","item: unknown"],"sources":["../src/mod.ts"],"sourcesContent":["import {\n getTextFormatter,\n type LogLevel,\n type LogRecord,\n type Sink,\n type TextFormatter,\n} from \"@logtape/logtape\";\n\nconst messageFormatter: TextFormatter = getTextFormatter({\n format: ({ message }) => message,\n lineEnding: \"lf\",\n timestamp: \"none\",\n});\n\n/**\n * A predicate that matches log record properties.\n *\n * The first argument is the resolved properties object. The second argument\n * is the full log record for cases where the predicate needs category, level,\n * or message context.\n *\n * @since 2.2.0\n */\nexport type PropertyMatcher = (\n properties: Readonly<Record<string, unknown>>,\n record: LogRecord,\n) => boolean;\n\n/**\n * A matcher for records collected by a {@link LogRecorder}.\n *\n * Object property matching is shallow: every own string key in the matcher\n * must exist on the record properties and match by value. Most values are\n * compared with `Object.is()`, `Date` values are compared by timestamp, and\n * regular expression matcher values match string property values. Use a\n * {@link PropertyMatcher} when a test needs absence checks or deeper matching.\n *\n * @since 2.2.0\n */\nexport interface LogRecordMatch {\n /**\n * Exact category matcher. A string is matched against the dot-joined\n * category, while an array is matched segment by segment. A regular\n * expression is tested against the dot-joined category.\n */\n readonly category?: string | readonly string[] | RegExp;\n\n /**\n * Category prefix matcher. A string is split on dots, while an array is\n * matched segment by segment.\n */\n readonly categoryPrefix?: string | readonly string[];\n\n /**\n * Exact severity level matcher.\n */\n readonly level?: LogLevel;\n\n /**\n * Rendered message matcher. String and regular expression matchers are\n * applied to the rendered message, using the same value rendering as\n * LogTape's default text formatter. A predicate receives the full record.\n */\n readonly message?: string | RegExp | ((record: LogRecord) => boolean);\n\n /**\n * Raw message matcher. A string record is matched directly. A tagged\n * template record is matched against the concatenated template strings.\n */\n readonly rawMessage?: string | RegExp;\n\n /**\n * Shallow property matcher or predicate.\n */\n readonly properties?: Readonly<Record<string, unknown>> | PropertyMatcher;\n\n /**\n * Full-record predicate for custom checks.\n */\n readonly predicate?: (record: LogRecord) => boolean;\n}\n\n/**\n * A test recorder for LogTape records.\n *\n * @since 2.2.0\n */\nexport interface LogRecorder {\n /**\n * A sink that appends each received record to {@link LogRecorder.records}.\n */\n readonly sink: Sink;\n\n /**\n * A snapshot of records collected so far, in sink call order.\n */\n readonly records: readonly LogRecord[];\n\n /**\n * Removes all collected records.\n */\n clear(): void;\n\n /**\n * Returns collected records and clears the recorder.\n */\n take(): readonly LogRecord[];\n\n /**\n * Finds the first collected record matching the given matcher.\n *\n * @param match The matcher to apply.\n * @returns The first matching record, or `undefined`.\n */\n find(match: LogRecordMatch): LogRecord | undefined;\n\n /**\n * Finds all collected records matching the given matcher.\n *\n * @param match The matcher to apply.\n * @returns All matching records in collection order.\n */\n filter(match: LogRecordMatch): readonly LogRecord[];\n\n /**\n * Asserts that at least one collected record matches the given matcher.\n *\n * @param match The matcher to apply.\n * @throws {Error} If no matching record exists.\n */\n assertLogged(match: LogRecordMatch): void;\n\n /**\n * Asserts that no collected record matches the given matcher.\n *\n * @param match The matcher to apply.\n * @throws {Error} If a matching record exists.\n */\n assertNotLogged(match: LogRecordMatch): void;\n}\n\n/**\n * Creates a LogTape test recorder.\n *\n * @example\n * ```ts\n * import { configure, getLogger, reset } from \"@logtape/logtape\";\n * import { createLogRecorder } from \"@logtape/testing\";\n *\n * const recorder = createLogRecorder();\n *\n * try {\n * await configure({\n * sinks: { recorder: recorder.sink },\n * loggers: [\n * { category: [\"my-lib\"], lowestLevel: \"debug\", sinks: [\"recorder\"] },\n * ],\n * });\n *\n * getLogger([\"my-lib\"]).info(\"User {userId} logged in.\", {\n * userId: 123,\n * });\n *\n * recorder.assertLogged({\n * category: [\"my-lib\"],\n * level: \"info\",\n * message: \"User 123 logged in.\",\n * properties: { userId: 123 },\n * });\n * } finally {\n * await reset();\n * }\n * ```\n *\n * @returns A recorder with a sink and assertion helpers.\n * @since 2.2.0\n */\nexport function createLogRecorder(): LogRecorder {\n const records: LogRecord[] = [];\n const sink: Sink = (record: LogRecord): void => {\n records.push(materializeLogRecord(record));\n };\n\n return {\n sink,\n get records(): readonly LogRecord[] {\n return records.slice();\n },\n clear(): void {\n records.length = 0;\n },\n take(): readonly LogRecord[] {\n return records.splice(0);\n },\n find(match: LogRecordMatch): LogRecord | undefined {\n return records.find((record) => matchesLogRecord(record, match));\n },\n filter(match: LogRecordMatch): readonly LogRecord[] {\n return records.filter((record) => matchesLogRecord(record, match));\n },\n assertLogged(match: LogRecordMatch): void {\n if (records.some((record) => matchesLogRecord(record, match))) return;\n\n throw new Error(\n [\n \"Expected a LogTape record matching:\",\n formatMatcher(match),\n \"\",\n `Recorded ${formatCount(records.length, \"record\")}:`,\n formatRecords(records),\n ].join(\"\\n\"),\n );\n },\n assertNotLogged(match: LogRecordMatch): void {\n const matching = records.filter((record) =>\n matchesLogRecord(record, match)\n );\n if (matching.length < 1) return;\n\n throw new Error(\n [\n \"Expected no LogTape record matching:\",\n formatMatcher(match),\n \"\",\n `Found ${formatCount(matching.length, \"matching record\")}:`,\n formatRecords(matching),\n ].join(\"\\n\"),\n );\n },\n };\n}\n\nfunction materializeLogRecord(record: LogRecord): LogRecord {\n const message = record.message;\n const rawMessage = record.rawMessage;\n const descriptors = Object.getOwnPropertyDescriptors(\n record,\n ) as PropertyDescriptorMap;\n if (!hasStringAccessorDescriptor(descriptors)) {\n return record;\n }\n const messageDescriptor = descriptors.message;\n const rawMessageDescriptor = descriptors.rawMessage;\n const snapshotDescriptors = Object.create(null) as PropertyDescriptorMap;\n for (const key of Reflect.ownKeys(descriptors)) {\n if (isLogRecordKey(key)) continue;\n const descriptor = descriptors[key];\n if (descriptor == null) continue;\n snapshotDescriptors[key] = isDataDescriptor(descriptor)\n ? descriptor\n : materializedDescriptor(Reflect.get(record, key), descriptor);\n }\n Object.assign(snapshotDescriptors, {\n category: materializedDescriptor(record.category, descriptors.category),\n level: materializedDescriptor(record.level, descriptors.level),\n message: materializedDescriptor(message, messageDescriptor),\n rawMessage: materializedDescriptor(rawMessage, rawMessageDescriptor),\n timestamp: materializedDescriptor(record.timestamp, descriptors.timestamp),\n properties: materializedDescriptor(\n record.properties,\n descriptors.properties,\n ),\n });\n return Object.defineProperties(\n Object.create(Object.getPrototypeOf(record)),\n snapshotDescriptors,\n ) as LogRecord;\n}\n\nfunction hasStringAccessorDescriptor(\n descriptors: PropertyDescriptorMap,\n): boolean {\n for (const key of Object.getOwnPropertyNames(descriptors)) {\n const descriptor = descriptors[key];\n if (descriptor != null && !isDataDescriptor(descriptor)) return true;\n }\n return false;\n}\n\nfunction isDataDescriptor(\n descriptor: PropertyDescriptor | undefined,\n): descriptor is PropertyDescriptor & { readonly value: unknown } {\n return descriptor != null && \"value\" in descriptor;\n}\n\nfunction isLogRecordKey(key: PropertyKey): key is keyof LogRecord {\n return key === \"category\" ||\n key === \"level\" ||\n key === \"message\" ||\n key === \"rawMessage\" ||\n key === \"timestamp\" ||\n key === \"properties\";\n}\n\nfunction materializedDescriptor(\n value: unknown,\n descriptor: PropertyDescriptor | undefined,\n): PropertyDescriptor {\n return {\n configurable: descriptor?.configurable ?? true,\n enumerable: descriptor?.enumerable ?? true,\n value,\n writable: isDataDescriptor(descriptor) ? descriptor.writable : true,\n };\n}\n\nfunction matchesLogRecord(record: LogRecord, match: LogRecordMatch): boolean {\n if (\n match.category != null &&\n !matchesCategory(record.category, match.category)\n ) {\n return false;\n }\n if (\n match.categoryPrefix != null &&\n !matchesCategoryPrefix(record.category, match.categoryPrefix)\n ) {\n return false;\n }\n if (match.level != null && record.level !== match.level) return false;\n if (\n match.message != null &&\n !matchesMessage(record, match.message)\n ) {\n return false;\n }\n if (\n match.rawMessage != null &&\n !matchesText(renderRawMessage(record.rawMessage), match.rawMessage)\n ) {\n return false;\n }\n if (\n match.properties != null &&\n !matchesProperties(record.properties, record, match.properties)\n ) {\n return false;\n }\n if (match.predicate != null && !match.predicate(record)) return false;\n return true;\n}\n\nfunction matchesCategory(\n category: readonly string[],\n expected: string | readonly string[] | RegExp,\n): boolean {\n const joinedCategory = category.join(\".\");\n if (expected instanceof RegExp) {\n return testRegExp(expected, joinedCategory);\n }\n if (typeof expected === \"string\") {\n return joinedCategory === expected;\n }\n const expectedCategory = parseCategory(expected);\n return category.length === expectedCategory.length &&\n category.every((part, index) => part === expectedCategory[index]);\n}\n\nfunction matchesCategoryPrefix(\n category: readonly string[],\n prefix: string | readonly string[],\n): boolean {\n const expectedPrefix = parseCategory(prefix);\n return expectedPrefix.length <= category.length &&\n expectedPrefix.every((part, index) => part === category[index]);\n}\n\nfunction parseCategory(\n category: string | readonly string[],\n): readonly string[] {\n if (typeof category !== \"string\") return category;\n return category === \"\" ? [] : category.split(\".\");\n}\n\nfunction matchesMessage(\n record: LogRecord,\n matcher: string | RegExp | ((record: LogRecord) => boolean),\n): boolean {\n if (typeof matcher === \"function\") return matcher(record);\n return matchesText(renderMessage(record), matcher);\n}\n\nfunction matchesText(text: string, matcher: string | RegExp): boolean {\n return typeof matcher === \"string\"\n ? text === matcher\n : testRegExp(matcher, text);\n}\n\nfunction matchesProperties(\n properties: Readonly<Record<string, unknown>> | null | undefined,\n record: LogRecord,\n matcher: Readonly<Record<string, unknown>> | PropertyMatcher,\n): boolean {\n const props: Readonly<Record<string, unknown>> = properties ?? {};\n if (typeof matcher === \"function\") return matcher(props, record);\n for (const key of Object.keys(matcher)) {\n if (!Object.prototype.hasOwnProperty.call(props, key)) return false;\n if (!matchesPropertyValue(props[key], matcher[key])) return false;\n }\n return true;\n}\n\nfunction matchesPropertyValue(actual: unknown, expected: unknown): boolean {\n if (actual instanceof Date && expected instanceof Date) {\n return Object.is(actual.getTime(), expected.getTime());\n }\n if (typeof actual === \"string\" && expected instanceof RegExp) {\n return testRegExp(expected, actual);\n }\n return Object.is(actual, expected);\n}\n\nfunction testRegExp(pattern: RegExp, text: string): boolean {\n if (!pattern.global && !pattern.sticky) {\n return pattern.test(text);\n }\n const clone = new RegExp(pattern.source, pattern.flags);\n return clone.test(text);\n}\n\nfunction renderRawMessage(rawMessage: string | TemplateStringsArray): string {\n return typeof rawMessage === \"string\" ? rawMessage : rawMessage.join(\"\");\n}\n\nfunction renderMessage(record: LogRecord): string {\n return messageFormatter(record).slice(0, -1);\n}\n\nfunction formatMatcher(match: LogRecordMatch): string {\n const lines: string[] = [];\n if (match.category != null) {\n lines.push(` category: ${formatCategoryMatcher(match.category)}`);\n }\n if (match.categoryPrefix != null) {\n lines.push(\n ` categoryPrefix: ${\n formatCategoryValue(parseCategory(match.categoryPrefix))\n }`,\n );\n }\n if (match.level != null) lines.push(` level: ${formatValue(match.level)}`);\n if (match.message != null) {\n lines.push(` message: ${formatMessageMatcher(match.message)}`);\n }\n if (match.rawMessage != null) {\n lines.push(` rawMessage: ${formatTextMatcher(match.rawMessage)}`);\n }\n if (match.properties != null) {\n lines.push(...formatPropertiesMatcher(match.properties));\n }\n if (match.predicate != null) lines.push(\" predicate: <predicate>\");\n return lines.length < 1 ? \" <any record>\" : lines.join(\"\\n\");\n}\n\nfunction formatCategoryMatcher(\n category: string | readonly string[] | RegExp,\n): string {\n return category instanceof RegExp\n ? String(category)\n : typeof category === \"string\"\n ? formatValue(category)\n : formatCategoryValue(category);\n}\n\nfunction formatCategoryValue(category: readonly string[]): string {\n return `[${category.map((part) => formatValue(part)).join(\", \")}]`;\n}\n\nfunction formatMessageMatcher(\n matcher: string | RegExp | ((record: LogRecord) => boolean),\n): string {\n return typeof matcher === \"function\" ? \"<predicate>\" : formatTextMatcher(\n matcher,\n );\n}\n\nfunction formatTextMatcher(matcher: string | RegExp): string {\n return typeof matcher === \"string\" ? formatValue(matcher) : String(matcher);\n}\n\nfunction formatPropertiesMatcher(\n matcher: Readonly<Record<string, unknown>> | PropertyMatcher,\n): string[] {\n if (typeof matcher === \"function\") return [\" properties: <predicate>\"];\n const lines = Object.keys(matcher).map((key) =>\n ` properties.${key}: ${formatPropertyValue(matcher, key)}`\n );\n return lines.length < 1 ? [\" properties: {}\"] : lines;\n}\n\nfunction formatRecords(records: readonly LogRecord[]): string {\n if (records.length < 1) return \" <none>\";\n const lines = records.slice(0, 3).map(formatRecord);\n if (records.length > 3) {\n lines.push(` ... ${records.length - 3} more`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction formatRecord(record: LogRecord): string {\n const category = formatCategory(record.category);\n return ` [${record.level}] ${category}: ${formatMessage(record)}${\n formatProperties(record.properties)\n }`;\n}\n\nfunction formatMessage(record: LogRecord): string {\n try {\n return renderMessage(record);\n } catch (error) {\n return formatAccessError(error);\n }\n}\n\nfunction formatCategory(category: readonly string[]): string {\n return category.length < 1 ? \"<root>\" : category.join(\".\");\n}\n\nfunction formatProperties(\n properties: Readonly<Record<string, unknown>> | null | undefined,\n): string {\n const props: Readonly<Record<string, unknown>> = properties ?? {};\n const entries = Object.keys(props);\n if (entries.length < 1) return \"\";\n const summary = entries.slice(0, 3).map((key) =>\n `${key}: ${formatPropertyValue(props, key)}`\n );\n if (entries.length > 3) summary.push(`... ${entries.length - 3} more`);\n return ` {${summary.join(\", \")}}`;\n}\n\nfunction formatPropertyValue(\n properties: Readonly<Record<string, unknown>>,\n key: string,\n): string {\n try {\n return formatValue(properties[key]);\n } catch (error) {\n return formatAccessError(error);\n }\n}\n\nfunction formatAccessError(error: unknown): string {\n return `<error: ${\n error instanceof Error ? error.message : safeString(error)\n }>`;\n}\n\nfunction formatCount(count: number, noun: string): string {\n return `${count} ${noun}${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") return JSON.stringify(value);\n if (typeof value === \"number\" && !Number.isFinite(value)) {\n return String(value);\n }\n if (typeof value === \"bigint\") return `${value}n`;\n if (typeof value === \"symbol\") return String(value);\n if (value instanceof RegExp) return String(value);\n if (value instanceof Error) {\n return `${value.name}: ${value.message}`;\n }\n if (value instanceof Map) return formatMap(value);\n if (value instanceof Set) return formatSet(value);\n try {\n return safeJsonStringify(value) ?? safeString(value);\n } catch {\n return safeString(value);\n }\n}\n\nfunction formatMap(value: ReadonlyMap<unknown, unknown>): string {\n const label = `Map(${value.size})`;\n try {\n const contents = formatMapContents(value);\n return `${label} ${safeJsonStringify(contents) ?? safeString(contents)}`;\n } catch {\n return label;\n }\n}\n\nfunction formatSet(value: ReadonlySet<unknown>): string {\n const label = `Set(${value.size})`;\n try {\n const contents = Array.from(value);\n return `${label} ${safeJsonStringify(contents) ?? safeString(contents)}`;\n } catch {\n return label;\n }\n}\n\nfunction safeJsonStringify(value: unknown): string | undefined {\n const ancestors: object[] = [];\n return JSON.stringify(value, function (\n this: unknown,\n _key: string,\n item: unknown,\n ): unknown {\n if (typeof item === \"bigint\") return `${item}n`;\n if (item instanceof RegExp) return String(item);\n if (item instanceof Error) return `${item.name}: ${item.message}`;\n if (typeof item === \"object\" && item != null) {\n while (\n ancestors.length > 0 &&\n ancestors[ancestors.length - 1] !== this\n ) {\n ancestors.pop();\n }\n if (ancestors.includes(item)) return \"[Circular]\";\n ancestors.push(item);\n if (item instanceof Map) return formatMapContents(item);\n if (item instanceof Set) return Array.from(item);\n }\n return item;\n });\n}\n\nfunction formatMapContents(\n value: ReadonlyMap<unknown, unknown>,\n): Readonly<Record<string, unknown>> | readonly (readonly [string, unknown])[] {\n const entries = Array.from(\n value,\n ([key, entryValue]) => [safeString(key), entryValue] as const,\n );\n const keys = entries.map(([key]) => key);\n const uniqueKeys = new Set(keys);\n return uniqueKeys.size === keys.length\n ? Object.fromEntries(entries)\n : entries;\n}\n\nfunction safeString(value: unknown): string {\n try {\n return String(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logtape/testing",
|
|
3
|
-
"version": "2.2.0-dev.
|
|
3
|
+
"version": "2.2.0-dev.757+db546094",
|
|
4
4
|
"description": "Testing utilities for collecting and asserting LogTape records",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"logging",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"dist/"
|
|
49
49
|
],
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@logtape/logtape": "^2.2.0-dev.
|
|
51
|
+
"@logtape/logtape": "^2.2.0-dev.757+db546094"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"tsdown": "^0.12.7",
|
|
55
55
|
"typescript": "^5.8.3",
|
|
56
|
-
"@logtape/redaction": "^2.2.0-dev.
|
|
56
|
+
"@logtape/redaction": "^2.2.0-dev.757+db546094"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "tsdown",
|