sourav-das/stem-separator
3
1const util = require('./util')2 3module.exports = function stringify (value, replacer, space) {4 const stack = []5 let indent = ''6 let propertyList7 let replacerFunc8 let gap = ''9 let quote10 11 if (12 replacer != null &&13 typeof replacer === 'object' &&14 !Array.isArray(replacer)15 ) {16 space = replacer.space17 quote = replacer.quote18 replacer = replacer.replacer19 }20 21 if (typeof replacer === 'function') {22 replacerFunc = replacer23 } else if (Array.isArray(replacer)) {24 propertyList = []25 for (const v of replacer) {26 let item27 28 if (typeof v === 'string') {29 item = v30 } else if (31 typeof v === 'number' ||32 v instanceof String ||33 v instanceof Number34 ) {35 item = String(v)36 }37 38 if (item !== undefined && propertyList.indexOf(item) < 0) {39 propertyList.push(item)40 }41 }42 }43 44 if (space instanceof Number) {45 space = Number(space)46 } else if (space instanceof String) {47 space = String(space)48 }49 50 if (typeof space === 'number') {51 if (space > 0) {52 space = Math.min(10, Math.floor(space))53 gap = ' '.substr(0, space)54 }55 } else if (typeof space === 'string') {56 gap = space.substr(0, 10)57 }58 59 return serializeProperty('', {'': value})60 61 function serializeProperty (key, holder) {62 let value = holder[key]63 if (value != null) {64 if (typeof value.toJSON5 === 'function') {65 value = value.toJSON5(key)66 } else if (typeof value.toJSON === 'function') {67 value = value.toJSON(key)68 }69 }70 71 if (replacerFunc) {72 value = replacerFunc.call(holder, key, value)73 }74 75 if (value instanceof Number) {76 value = Number(value)77 } else if (value instanceof String) {78 value = String(value)79 } else if (value instanceof Boolean) {80 value = value.valueOf()81 }82 83 switch (value) {84 case null: return 'null'85 case true: return 'true'86 case false: return 'false'87 }88 89 if (typeof value === 'string') {90 return quoteString(value, false)91 }92 93 if (typeof value === 'number') {94 return String(value)95 }96 97 if (typeof value === 'object') {98 return Array.isArray(value) ? serializeArray(value) : serializeObject(value)99 }100 101 return undefined102 }103 104 function quoteString (value) {105 const quotes = {106 "'": 0.1,107 '"': 0.2,108 }109 110 const replacements = {111 "'": "\\'",112 '"': '\\"',113 '\\': '\\\\',114 '\b': '\\b',115 '\f': '\\f',116 '\n': '\\n',117 '\r': '\\r',118 '\t': '\\t',119 '\v': '\\v',120 '\0': '\\0',121 '\u2028': '\\u2028',122 '\u2029': '\\u2029',123 }124 125 let product = ''126 127 for (let i = 0; i < value.length; i++) {128 const c = value[i]129 switch (c) {130 case "'":131 case '"':132 quotes[c]++133 product += c134 continue135 136 case '\0':137 if (util.isDigit(value[i + 1])) {138 product += '\\x00'139 continue140 }141 }142 143 if (replacements[c]) {144 product += replacements[c]145 continue146 }147 148 if (c < ' ') {149 let hexString = c.charCodeAt(0).toString(16)150 product += '\\x' + ('00' + hexString).substring(hexString.length)151 continue152 }153 154 product += c155 }156 157 const quoteChar = quote || Object.keys(quotes).reduce((a, b) => (quotes[a] < quotes[b]) ? a : b)158 159 product = product.replace(new RegExp(quoteChar, 'g'), replacements[quoteChar])160 161 return quoteChar + product + quoteChar162 }163 164 function serializeObject (value) {165 if (stack.indexOf(value) >= 0) {166 throw TypeError('Converting circular structure to JSON5')167 }168 169 stack.push(value)170 171 let stepback = indent172 indent = indent + gap173 174 let keys = propertyList || Object.keys(value)175 let partial = []176 for (const key of keys) {177 const propertyString = serializeProperty(key, value)178 if (propertyString !== undefined) {179 let member = serializeKey(key) + ':'180 if (gap !== '') {181 member += ' '182 }183 member += propertyString184 partial.push(member)185 }186 }187 188 let final189 if (partial.length === 0) {190 final = '{}'191 } else {192 let properties193 if (gap === '') {194 properties = partial.join(',')195 final = '{' + properties + '}'196 } else {197 let separator = ',\n' + indent198 properties = partial.join(separator)199 final = '{\n' + indent + properties + ',\n' + stepback + '}'200 }201 }202 203 stack.pop()204 indent = stepback205 return final206 }207 208 function serializeKey (key) {209 if (key.length === 0) {210 return quoteString(key, true)211 }212 213 const firstChar = String.fromCodePoint(key.codePointAt(0))214 if (!util.isIdStartChar(firstChar)) {215 return quoteString(key, true)216 }217 218 for (let i = firstChar.length; i < key.length; i++) {219 if (!util.isIdContinueChar(String.fromCodePoint(key.codePointAt(i)))) {220 return quoteString(key, true)221 }222 }223 224 return key225 }226 227 function serializeArray (value) {228 if (stack.indexOf(value) >= 0) {229 throw TypeError('Converting circular structure to JSON5')230 }231 232 stack.push(value)233 234 let stepback = indent235 indent = indent + gap236 237 let partial = []238 for (let i = 0; i < value.length; i++) {239 const propertyString = serializeProperty(String(i), value)240 partial.push((propertyString !== undefined) ? propertyString : 'null')241 }242 243 let final244 if (partial.length === 0) {245 final = '[]'246 } else {247 if (gap === '') {248 let properties = partial.join(',')249 final = '[' + properties + ']'250 } else {251 let separator = ',\n' + indent252 let properties = partial.join(separator)253 final = '[\n' + indent + properties + ',\n' + stepback + ']'254 }255 }256 257 stack.pop()258 indent = stepback259 return final260 }261}262 