169 lines
5.4 KiB
JavaScript
169 lines
5.4 KiB
JavaScript
/**
|
|
* Copyright 2022 Google LLC.
|
|
* Copyright (c) Microsoft Corporation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
import { assert } from '../../../utils/assert.js';
|
|
const specifiers = ['%s', '%d', '%i', '%f', '%o', '%O', '%c'];
|
|
function isFormatSpecifier(str) {
|
|
return specifiers.some((spec) => str.includes(spec));
|
|
}
|
|
/**
|
|
* @param args input remote values to be format printed
|
|
* @return parsed text of the remote values in specific format
|
|
*/
|
|
export function logMessageFormatter(args) {
|
|
let output = '';
|
|
const argFormat = args[0].value.toString();
|
|
const argValues = args.slice(1, undefined);
|
|
const tokens = argFormat.split(new RegExp(specifiers.map((spec) => `(${spec})`).join('|'), 'g'));
|
|
for (const token of tokens) {
|
|
if (token === undefined || token === '') {
|
|
continue;
|
|
}
|
|
if (isFormatSpecifier(token)) {
|
|
const arg = argValues.shift();
|
|
// raise an exception when less value is provided
|
|
assert(arg, `Less value is provided: "${getRemoteValuesText(args, false)}"`);
|
|
if (token === '%s') {
|
|
output += stringFromArg(arg);
|
|
}
|
|
else if (token === '%d' || token === '%i') {
|
|
if (arg.type === 'bigint' ||
|
|
arg.type === 'number' ||
|
|
arg.type === 'string') {
|
|
output += parseInt(arg.value.toString(), 10);
|
|
}
|
|
else {
|
|
output += 'NaN';
|
|
}
|
|
}
|
|
else if (token === '%f') {
|
|
if (arg.type === 'bigint' ||
|
|
arg.type === 'number' ||
|
|
arg.type === 'string') {
|
|
output += parseFloat(arg.value.toString());
|
|
}
|
|
else {
|
|
output += 'NaN';
|
|
}
|
|
}
|
|
else {
|
|
// %o, %O, %c
|
|
output += toJson(arg);
|
|
}
|
|
}
|
|
else {
|
|
output += token;
|
|
}
|
|
}
|
|
// raise an exception when more value is provided
|
|
if (argValues.length > 0) {
|
|
throw new Error(`More value is provided: "${getRemoteValuesText(args, false)}"`);
|
|
}
|
|
return output;
|
|
}
|
|
/**
|
|
* @param arg input remote value to be parsed
|
|
* @return parsed text of the remote value
|
|
*
|
|
* input: {"type": "number", "value": 1}
|
|
* output: 1
|
|
*
|
|
* input: {"type": "string", "value": "abc"}
|
|
* output: "abc"
|
|
*
|
|
* input: {"type": "object", "value": [["id", {"type": "number", "value": 1}]]}
|
|
* output: '{"id": 1}'
|
|
*
|
|
* input: {"type": "object", "value": [["font-size", {"type": "string", "value": "20px"}]]}
|
|
* output: '{"font-size": "20px"}'
|
|
*/
|
|
function toJson(arg) {
|
|
// arg type validation
|
|
if (arg.type !== 'array' &&
|
|
arg.type !== 'bigint' &&
|
|
arg.type !== 'date' &&
|
|
arg.type !== 'number' &&
|
|
arg.type !== 'object' &&
|
|
arg.type !== 'string') {
|
|
return stringFromArg(arg);
|
|
}
|
|
if (arg.type === 'bigint') {
|
|
return `${arg.value.toString()}n`;
|
|
}
|
|
if (arg.type === 'number') {
|
|
return arg.value.toString();
|
|
}
|
|
if (['date', 'string'].includes(arg.type)) {
|
|
return JSON.stringify(arg.value);
|
|
}
|
|
if (arg.type === 'object') {
|
|
return `{${arg.value
|
|
.map((pair) => {
|
|
return `${JSON.stringify(pair[0])}:${toJson(pair[1])}`;
|
|
})
|
|
.join(',')}}`;
|
|
}
|
|
if (arg.type === 'array') {
|
|
return `[${arg.value?.map((val) => toJson(val)).join(',') ?? ''}]`;
|
|
}
|
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
throw Error(`Invalid value type: ${arg}`);
|
|
}
|
|
function stringFromArg(arg) {
|
|
if (!Object.hasOwn(arg, 'value')) {
|
|
return arg.type;
|
|
}
|
|
switch (arg.type) {
|
|
case 'string':
|
|
case 'number':
|
|
case 'boolean':
|
|
case 'bigint':
|
|
return String(arg.value);
|
|
case 'regexp':
|
|
return `/${arg.value.pattern}/${arg.value.flags ?? ''}`;
|
|
case 'date':
|
|
return new Date(arg.value).toString();
|
|
case 'object':
|
|
return `Object(${arg.value?.length ?? ''})`;
|
|
case 'array':
|
|
return `Array(${arg.value?.length ?? ''})`;
|
|
case 'map':
|
|
return `Map(${arg.value?.length})`;
|
|
case 'set':
|
|
return `Set(${arg.value?.length})`;
|
|
default:
|
|
return arg.type;
|
|
}
|
|
}
|
|
export function getRemoteValuesText(args, formatText) {
|
|
const arg = args[0];
|
|
if (!arg) {
|
|
return '';
|
|
}
|
|
// if args[0] is a format specifier, format the args as output
|
|
if (arg.type === 'string' &&
|
|
isFormatSpecifier(arg.value.toString()) &&
|
|
formatText) {
|
|
return logMessageFormatter(args);
|
|
}
|
|
// if args[0] is not a format specifier, just join the args with \u0020 (unicode 'SPACE')
|
|
return args
|
|
.map((arg) => {
|
|
return stringFromArg(arg);
|
|
})
|
|
.join('\u0020');
|
|
}
|
|
//# sourceMappingURL=logHelper.js.map
|