You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
3.3 KiB
150 lines
3.3 KiB
const PrimitiveType = 1;
|
|
const ObjectType = 2;
|
|
const ArrayType = 3;
|
|
const PromiseType = 4;
|
|
const ReadableStringType = 5;
|
|
const ReadableObjectType = 6;
|
|
// https://tc39.es/ecma262/#table-json-single-character-escapes
|
|
const escapableCharCodeSubstitution = { // JSON Single Character Escape Sequences
|
|
0x08: '\\b',
|
|
0x09: '\\t',
|
|
0x0a: '\\n',
|
|
0x0c: '\\f',
|
|
0x0d: '\\r',
|
|
0x22: '\\\"',
|
|
0x5c: '\\\\'
|
|
};
|
|
|
|
function isLeadingSurrogate(code) {
|
|
return code >= 0xD800 && code <= 0xDBFF;
|
|
}
|
|
|
|
function isTrailingSurrogate(code) {
|
|
return code >= 0xDC00 && code <= 0xDFFF;
|
|
}
|
|
|
|
function isReadableStream(value) {
|
|
return (
|
|
typeof value.pipe === 'function' &&
|
|
typeof value._read === 'function' &&
|
|
typeof value._readableState === 'object' && value._readableState !== null
|
|
);
|
|
}
|
|
|
|
function replaceValue(holder, key, value, replacer) {
|
|
if (value && typeof value.toJSON === 'function') {
|
|
value = value.toJSON();
|
|
}
|
|
|
|
if (replacer !== null) {
|
|
value = replacer.call(holder, String(key), value);
|
|
}
|
|
|
|
switch (typeof value) {
|
|
case 'function':
|
|
case 'symbol':
|
|
value = undefined;
|
|
break;
|
|
|
|
case 'object':
|
|
if (value !== null) {
|
|
const cls = value.constructor;
|
|
if (cls === String || cls === Number || cls === Boolean) {
|
|
value = value.valueOf();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
function getTypeNative(value) {
|
|
if (value === null || typeof value !== 'object') {
|
|
return PrimitiveType;
|
|
}
|
|
|
|
if (Array.isArray(value)) {
|
|
return ArrayType;
|
|
}
|
|
|
|
return ObjectType;
|
|
}
|
|
|
|
function getTypeAsync(value) {
|
|
if (value === null || typeof value !== 'object') {
|
|
return PrimitiveType;
|
|
}
|
|
|
|
if (typeof value.then === 'function') {
|
|
return PromiseType;
|
|
}
|
|
|
|
if (isReadableStream(value)) {
|
|
return value._readableState.objectMode ? ReadableObjectType : ReadableStringType;
|
|
}
|
|
|
|
if (Array.isArray(value)) {
|
|
return ArrayType;
|
|
}
|
|
|
|
return ObjectType;
|
|
}
|
|
|
|
function normalizeReplacer(replacer) {
|
|
if (typeof replacer === 'function') {
|
|
return replacer;
|
|
}
|
|
|
|
if (Array.isArray(replacer)) {
|
|
const allowlist = new Set(replacer
|
|
.map(item => {
|
|
const cls = item && item.constructor;
|
|
return cls === String || cls === Number ? String(item) : null;
|
|
})
|
|
.filter(item => typeof item === 'string')
|
|
);
|
|
|
|
return [...allowlist];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function normalizeSpace(space) {
|
|
if (typeof space === 'number') {
|
|
if (!Number.isFinite(space) || space < 1) {
|
|
return false;
|
|
}
|
|
|
|
return ' '.repeat(Math.min(space, 10));
|
|
}
|
|
|
|
if (typeof space === 'string') {
|
|
return space.slice(0, 10) || false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
module.exports = {
|
|
escapableCharCodeSubstitution,
|
|
isLeadingSurrogate,
|
|
isTrailingSurrogate,
|
|
type: {
|
|
PRIMITIVE: PrimitiveType,
|
|
PROMISE: PromiseType,
|
|
ARRAY: ArrayType,
|
|
OBJECT: ObjectType,
|
|
STRING_STREAM: ReadableStringType,
|
|
OBJECT_STREAM: ReadableObjectType
|
|
},
|
|
|
|
isReadableStream,
|
|
replaceValue,
|
|
getTypeNative,
|
|
getTypeAsync,
|
|
normalizeReplacer,
|
|
normalizeSpace
|
|
};
|