UNPKG

@dbl0null/slow-json-stringify

Version:

The slow.. well actually fastest JSON stringifier in the galaxy.

1 lines 15.3 kB
{"version":3,"file":"sjs.mjs","sources":["../src/_makeChunks.mjs","../src/_utils.mjs","../src/_makeQueue.mjs","../src/_prepare.mjs","../src/_select.mjs","../src/sjs.mjs"],"sourcesContent":["const _replaceString = type => type.indexOf('string') !== -1 ? '\"__par__\"' : '__par__'\n\n// 3 possibilities after arbitrary property:\n// - \", => non-last string property\n// - , => non-last non-string property\n// - \" => last string property\nconst _matchStartRe = /^(\",|,|\")/\n\nconst _chunkRegex = /\"\\w+__sjs\"/g\n\n/**\n * @param {string} str - prepared string already validated.\n * @param {array} queue - queue containing the property name to match\n * (used for building dynamic regex) needed for the preparation of\n * chunks used in different scenarios.\n */\nconst _makeChunks = (str, queue) => {\n const chunks = str\n // Matching prepared properties and replacing with target with or without\n // double quotes.\n // => Avoiding unnecessary concatenation of doublequotes during serialization.\n .replace(_chunkRegex, _replaceString)\n .split('__par__')\n const result = []\n\n let _i\n const length = chunks.length\n for (let i = 0; i < length; ++i) {\n const chunk = chunks[i]\n\n // Using dynamic regex to ensure that only the correct property\n // at the end of the string it's actually selected.\n // => e.g. ,\"a\":{\"a\": => ,\"a\":{\n const matchProp = `(\"${queue[i]?.name}\":(\"?))$`\n\n // Check if current chunk is the last one inside a nested property\n const isLast = (_i = i + 1) === length || (\n (_i = chunks[_i].indexOf('}')) &&\n (_i === 0 || _i === 1)\n )\n\n // If the chunk is the last one the `isUndef` case should match\n // the preceding comma too.\n const matchPropRe = new RegExp(isLast ? `(,?)${matchProp}` : matchProp)\n\n const withoutInitial = chunk.replace(_matchStartRe, '')\n\n result.push({\n // notify that the chunk preceding the current one has not\n // its corresponding property undefined.\n // => This is a V8 optimization as it's way faster writing\n // the value of a property than writing the entire property.\n flag: false,\n pure: chunk,\n // Without initial part\n prevUndef: withoutInitial,\n // Without property chars\n isUndef: chunk.replace(matchPropRe, ''),\n // Only remaining chars (can be zero chars)\n bothUndef: withoutInitial.replace(matchPropRe, '')\n })\n }\n\n return result\n}\n\nexport { _makeChunks }\n","/**\n * `_find` is a super fast deep property finder.\n * It dynamically build the function needed to reach the desired\n * property.\n *\n * e.g.\n * obj = {a: {b: {c: 1}}}\n * _find(['a','b','c']) => (obj) => (((obj || {}).a || {}).b || {}).c\n *\n * @param {array} path - path to reach object property.\n */\nconst _find = path => {\n let str = 'obj'\n\n for (let i = 0; i < path.length; ++i) {\n str = `(${str}||{}).${path[i]}`\n }\n\n return eval(`(obj => ${str})`)\n}\n\nconst __find = path => {\n let str = 'obj'\n\n for (let i = 0; i < path.length; ++i) {\n str += `?.['${path[i]}']`\n }\n\n return eval(`(obj => ${str})`)\n}\n\nfunction _arraySerializer (serializer, array) {\n // Stringifying more complex array using the provided sjs schema\n let acc = ''\n const len = array.length - 1\n for (let i = 0; i < len; ++i) {\n acc += `${serializer(array[i])},`\n }\n\n // Prevent slice for removing unnecessary comma.\n acc += serializer(array[len])\n return `[${acc}]`\n}\n\n/**\n * `_makeArraySerializer` is simply a wrapper of another `sjs` schema\n * used for the serialization of arrais.\n */\nconst _makeArraySerializer = serializer => {\n if (typeof serializer === 'function') return _arraySerializer.bind(this, serializer)\n return JSON.stringify\n}\n\nconst TYPES = ['number', 'string', 'boolean', 'array', 'null']\n\n/* #__PURE__ */\nfunction checkType (type) {\n if (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production' && !TYPES.includes(type)) {\n throw new Error(\n `Expected one of: \"number\", \"string\", \"boolean\", \"array\", \"null\". received \"${type}\" instead`\n )\n }\n}\n\nconst fnUser = value => value\n\n/**\n * @param type number|string|boolean|array|null\n * @param serializer\n * @returns\n */\nconst attr = (type, serializer) => {\n /* #__PURE__ */\n checkType(type)\n\n const usedSerializer = serializer || fnUser\n\n return {\n isSJS: true,\n type,\n serializer:\n type === 'array' ? _makeArraySerializer(serializer) : usedSerializer\n }\n}\n\n// Little utility for escaping convenience.\n// => if no regex is provided, a default one will be used.\nconst _defaultRegex = /[\\t\\n\\r\"\\\\]/g\nconst _escapeCallback = char => '\\\\' + char\nconst escape = (regex = _defaultRegex) => str => str.replace(regex, _escapeCallback)\n\nexport { __find, _find, escape, attr }\n","import { __find } from './_utils.mjs'\n\n/**\n * @param {object} originalSchema\n * @param {array} queue\n * @param {string|object} obj\n * @param {array} acc\n */\nfunction _prepareQueue (originalSchema, queue, obj, acc = []) {\n // this looks weird for objects, but is actually exactly what we want: object.toString() === '[object Object]'. We only want actual strings.\n if (obj.toString().indexOf('__sjs') !== -1) {\n const find = __find(acc)\n const { serializer } = find(originalSchema)\n\n queue.push({\n serializer,\n find,\n name: acc[acc.length - 1]\n })\n return\n }\n\n // Recursively going deeper.\n // NOTE: While going deeper, the current prop is pushed into the accumulator\n // to keep track of the position inside of the object.\n const keys = Object.keys(obj)\n for (let i = 0; i < keys.length; ++i) {\n const key = keys[i]\n _prepareQueue(originalSchema, queue, obj[key], [...acc, key])\n }\n}\n\n/**\n * @param {object} preparedSchema - schema already validated\n * with modified prop values to avoid clashes.\n * @param {object} originalSchema - User provided schema\n * => contains array stringification serializers that are lost during preparation.\n */\nconst _makeQueue = (preparedSchema, originalSchema) => {\n const queue = []\n _prepareQueue(originalSchema, queue, preparedSchema)\n return queue\n}\n\nexport { _makeQueue }\n","const _stringifyCallback = (_, value) => {\n if (!value.isSJS) return value\n return `${value.type}__sjs`\n}\n\n/**\n * `_prepare` - aims to normalize the schema provided by the user.\n * It will convert the schema in both a parseable string and an object\n * useable for making the chunks needed for the serialization part.\n * @param {object} schema - user provided schema\n */\nconst _prepare = schema => {\n const _preparedString = JSON.stringify(schema, _stringifyCallback)\n const _preparedSchema = JSON.parse(_preparedString)\n\n return {\n _preparedString,\n _preparedSchema\n }\n}\n\nexport { _prepare }\n","/**\n * `select` function takes all the possible chunks from the\n * current index and set the more appropriate one in relation\n * to the current `value` and the `flag` state.\n *\n * => This approach avoids the use of Regex during serialization.\n *\n * @param {any} chunks - value to serialize.\n */\nconst _select = chunks => (value, index) => {\n const chunk = chunks[index]\n\n if (value !== undefined) {\n if (chunk.flag) {\n return chunk.prevUndef + value\n }\n return chunk.pure + value\n }\n\n // If the current value is undefined set a flag on the next\n // chunk stating that the previous prop is undefined.\n chunks[index + 1].flag = true\n\n if (chunk.flag) {\n return chunk.bothUndef\n }\n return chunk.isUndef\n}\n\nexport { _select }\n","import { _makeChunks } from './_makeChunks.mjs'\nimport { _makeQueue } from './_makeQueue.mjs'\nimport { _prepare } from './_prepare.mjs'\nimport { _select } from './_select.mjs'\nimport { attr, escape } from './_utils.mjs'\n\n// Doing a lot of preparation work before returning the final function responsible for\n// the stringification.\nconst sjs = schema => {\n const { _preparedString, _preparedSchema } = _prepare(schema)\n\n // Providing preparedSchema for univocal correspondence between created queue and chunks.\n // Provided original schema to keep track of the original properties that gets destroied\n // during schema preparation => e.g. array stringification method.\n const queue = _makeQueue(_preparedSchema, schema)\n const chunks = _makeChunks(_preparedString, queue)\n const selectChunk = _select(chunks)\n\n // Exposed function\n return obj => {\n let temp = ''\n\n for (let i = 0; i < queue.length; ++i) {\n const { serializer, find } = queue[i]\n const raw = find(obj)\n\n temp += selectChunk(serializer(raw), i)\n }\n\n const { flag, pure, prevUndef } = chunks[chunks.length - 1]\n\n return temp + (flag ? prevUndef : pure)\n }\n}\n\nexport { sjs, attr, escape }\n"],"names":["_replaceString","type","indexOf","_matchStartRe","_chunkRegex","_makeChunks","str","queue","chunks","replace","split","result","_i","length","i","chunk","matchProp","name","isLast","matchPropRe","RegExp","withoutInitial","push","flag","pure","prevUndef","isUndef","bothUndef","__find","path","eval","_arraySerializer","serializer","array","acc","len","_makeArraySerializer","bind","this","JSON","stringify","fnUser","value","attr","usedSerializer","isSJS","_defaultRegex","_escapeCallback","char","escape","regex","_prepareQueue","originalSchema","obj","toString","find","keys","Object","key","_makeQueue","preparedSchema","_stringifyCallback","_","_prepare","schema","_preparedString","_preparedSchema","parse","_select","index","undefined","sjs","selectChunk","temp","raw"],"mappings":"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"}