@tramvai/safe-strings
Advanced tools
Comparing version 0.5.2 to 0.5.4
@@ -1,11 +0,1 @@ | ||
/** | ||
* Stringify object to safe for evaluation json string | ||
* | ||
* @param {*} json | ||
* @return {String} safe for evaluation json string | ||
* @example | ||
* | ||
* safeStringify({ s:'test string' }) // => '{ "s":"test string" }' | ||
* safeStringify({ s:'some\u2028 test\u2029' }) // => '{ "s": "some\\u2028 test\\u2029" }' | ||
*/ | ||
export declare const safeStringify: (json: Record<string, any>) => string; |
export * from './safeStringify'; | ||
export * from './safeDehydrate'; | ||
export * from './safeParseJSON'; | ||
export * from './safeStringifyJSON'; | ||
export * from './removeXss'; |
import reduce from '@tinkoff/utils/array/reduce'; | ||
// eslint-disable-next-line no-useless-escape | ||
const UNSAFE_CHARS_REGEXP = /[<>\/\u2028\u2029]/g; | ||
const ESCAPED_CHARS = { | ||
'<': '\\u003C', | ||
'>': '\\u003E', | ||
'/': '\\u002F', | ||
'\u2028': '\\u2028', | ||
'\u2029': '\\u2029', | ||
}; | ||
const escape = (char) => ESCAPED_CHARS[char]; | ||
// source https://github.com/preactjs/preact-render-to-string/blob/60075a5a7389d638d535c85f3706739e9ba932bc/src/util.js | ||
// perf https://esbench.com/bench/5f88af6cb4632100a7dcd414 | ||
const ENCODED_ENTITIES = /[<\u2028\u2029]/; | ||
/** | ||
@@ -23,10 +16,40 @@ * Stringify object to safe for evaluation json string | ||
*/ | ||
function encodeEntities(str) { | ||
// Skip all work for strings with no entities needing encoding: | ||
if (str.length === 0 || ENCODED_ENTITIES.test(str) === false) | ||
return str; | ||
let last = 0; | ||
let i = 0; | ||
let out = ''; | ||
let ch = ''; | ||
// Seek forward in str until the next entity char: | ||
for (; i < str.length; i++) { | ||
switch (str.charCodeAt(i)) { | ||
case 60: // < | ||
ch = '\\u003C'; | ||
break; | ||
case 8232: // u2028 symbol (line separator) | ||
ch = '\\u2028'; | ||
break; | ||
case 8233: // u2029 symbol (paragraph separator) | ||
ch = '\\u2029'; | ||
break; | ||
default: | ||
continue; | ||
} | ||
// Append skipped/buffered characters and the encoded entity: | ||
if (i !== last) | ||
out += str.slice(last, i); | ||
out += ch; | ||
// Start the next seek/buffer after the entity's offset: | ||
last = i + 1; | ||
} | ||
if (i !== last) | ||
out += str.slice(last, i); | ||
return out; | ||
} | ||
const safeStringify$1 = (json) => { | ||
return JSON.stringify(json).replace(UNSAFE_CHARS_REGEXP, escape); | ||
return encodeEntities(JSON.stringify(json)); | ||
}; | ||
const safeDehydrate = (json) => { | ||
return safeStringify$1(json).replace(/\\/g, '\\\\').replace(/'/g, "\\'"); | ||
}; | ||
const safeParseJSON = (str, defaultValue = null) => { | ||
@@ -67,2 +90,2 @@ try { | ||
export { removeXss, safeDehydrate, safeParseJSON, safeStringify$1 as safeStringify, safeStringifyJSON }; | ||
export { removeXss, safeParseJSON, safeStringify$1 as safeStringify, safeStringifyJSON }; |
@@ -11,12 +11,5 @@ 'use strict'; | ||
// eslint-disable-next-line no-useless-escape | ||
const UNSAFE_CHARS_REGEXP = /[<>\/\u2028\u2029]/g; | ||
const ESCAPED_CHARS = { | ||
'<': '\\u003C', | ||
'>': '\\u003E', | ||
'/': '\\u002F', | ||
'\u2028': '\\u2028', | ||
'\u2029': '\\u2029', | ||
}; | ||
const escape = (char) => ESCAPED_CHARS[char]; | ||
// source https://github.com/preactjs/preact-render-to-string/blob/60075a5a7389d638d535c85f3706739e9ba932bc/src/util.js | ||
// perf https://esbench.com/bench/5f88af6cb4632100a7dcd414 | ||
const ENCODED_ENTITIES = /[<\u2028\u2029]/; | ||
/** | ||
@@ -32,10 +25,40 @@ * Stringify object to safe for evaluation json string | ||
*/ | ||
function encodeEntities(str) { | ||
// Skip all work for strings with no entities needing encoding: | ||
if (str.length === 0 || ENCODED_ENTITIES.test(str) === false) | ||
return str; | ||
let last = 0; | ||
let i = 0; | ||
let out = ''; | ||
let ch = ''; | ||
// Seek forward in str until the next entity char: | ||
for (; i < str.length; i++) { | ||
switch (str.charCodeAt(i)) { | ||
case 60: // < | ||
ch = '\\u003C'; | ||
break; | ||
case 8232: // u2028 symbol (line separator) | ||
ch = '\\u2028'; | ||
break; | ||
case 8233: // u2029 symbol (paragraph separator) | ||
ch = '\\u2029'; | ||
break; | ||
default: | ||
continue; | ||
} | ||
// Append skipped/buffered characters and the encoded entity: | ||
if (i !== last) | ||
out += str.slice(last, i); | ||
out += ch; | ||
// Start the next seek/buffer after the entity's offset: | ||
last = i + 1; | ||
} | ||
if (i !== last) | ||
out += str.slice(last, i); | ||
return out; | ||
} | ||
const safeStringify$1 = (json) => { | ||
return JSON.stringify(json).replace(UNSAFE_CHARS_REGEXP, escape); | ||
return encodeEntities(JSON.stringify(json)); | ||
}; | ||
const safeDehydrate = (json) => { | ||
return safeStringify$1(json).replace(/\\/g, '\\\\').replace(/'/g, "\\'"); | ||
}; | ||
const safeParseJSON = (str, defaultValue = null) => { | ||
@@ -77,5 +100,4 @@ try { | ||
exports.removeXss = removeXss; | ||
exports.safeDehydrate = safeDehydrate; | ||
exports.safeParseJSON = safeParseJSON; | ||
exports.safeStringify = safeStringify$1; | ||
exports.safeStringifyJSON = safeStringifyJSON; |
{ | ||
"name": "@tramvai/safe-strings", | ||
"version": "0.5.2", | ||
"version": "0.5.4", | ||
"description": "", | ||
@@ -21,3 +21,3 @@ "main": "lib/utils.js", | ||
"@tinkoff/utils": "^2.1.3", | ||
"tslib": "^2.0.3" | ||
"tslib": "^2.4.0" | ||
}, | ||
@@ -24,0 +24,0 @@ "sideEffects": false, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7465
183
9
Updatedtslib@^2.4.0