UNPKG

format-to-json

Version:

Format string to a json like template.

676 lines (669 loc) 20.5 kB
/** * @license * format-to-json v4.0.0 * GitHub Repository <https://github.com/CN-Tower/format-to-json> * Released under MIT license <https://github.com/CN-Tower/format-to-json/blob/master/LICENSE> */ 'use strict'; (function (root) { var BREAK = '\r\n'; var SPACE = ' '; var OPTIONS = { indent: 2, isExpand: true, isStrict: false, isEscape: false, isUnscape: false, keyQtMark: '"', // '\'' | '\"' | ''; valQtMark: '"' // '\'' | '\"'; }; var ESCAPES_MAP = [{ ptn: /\r\n/gm, str: '' }, { ptn: /\n\r/gm, str: '' }, { ptn: /\n/gm, str: '\\n' }, { ptn: /\r/gm, str: '\\r' }, { ptn: //gm, str: '\\b' }, { ptn: / /gm, str: '\\v' }, { ptn: /\f/gm, str: '\\f' }, { ptn: /\t/gm, str: '\\t' }]; var MESSAGES_MAP = { err: function err() { return "Parse Error, an excessive abnormal Json!"; }, war: function war(rowIdx) { return "Formated ".concat(rowIdx, " lines, abnormal JSON source!"); }, scc: function scc(rowIdx) { return "Success formated ".concat(rowIdx, " lines!"); }, val: function val(rowIdx) { return "Invalid value in line: ".concat(rowIdx); }, ost: function ost(rowIdx) { return "Expect a string in line: ".concat(rowIdx); }, col: function col(rowIdx) { return "Expect a colon in line: ".concat(rowIdx); }, end: function end(rowIdx, brc) { return "Expect a comma or a \"".concat(brc, "\" in line: ").concat(rowIdx); } }; /** * ================================================================= * The main function of `format-to-json` util. * @param { string } source * @param { Object } options * ================================================================= */ function fmt2json(source, options) { /** * The variables. * Should be initialized at the beginning of the format. * { fmtSign } Possibal value: 'ost' | 'col' | 'val' | 'end' | 'war' | 'scc' | 'err'; * { fmtType } Possibal value: 'info' | 'success' | 'warning' | 'danger'; */ var fmtSource = source, curLevel = 0, curIndex = 1, exceptType = '', exceptSign = '', signsQueue = '', baseIndent = '', isSrcValid = true, isFmtError = false, withDetails = false, fmtResult = '', fmtType = 'info', fmtSign = '', fmtLines = 0, message = '', errFormat = false, errNear = '', errIndex = NaN, errExpect = ''; var fmtOptions = Object.assign({}, OPTIONS); if (options) { if (typeof options.withDetails === 'boolean') { withDetails = options.withDetails; } if (typeof options.expand === 'boolean') { fmtOptions.isExpand = options.expand; } if (typeof options.strict === 'boolean') { fmtOptions.isStrict = options.strict; } if (typeof options.escape === 'boolean') { fmtOptions.isEscape = options.escape; } if (typeof options.unscape === 'boolean') { fmtOptions.isUnscape = options.unscape; } if (typeof options.indent === 'number' && options.indent > 0) { fmtOptions.indent = options.indent; } if (["'", '"', ''].indexOf(options.keyQtMark) > -1) { fmtOptions.keyQtMark = options.keyQtMark; } if (["'", '"'].indexOf(options.valQtMark) > -1) { fmtOptions.valQtMark = options.valQtMark; } } baseIndent = getBaseIndent(); try { try { if (fmtSource !== '') eval("fmtSource = ".concat(fmtSource)); if (fmtSource === '' || ['object', 'boolean'].indexOf(typeof fmtSource) > -1) { doNormalFormat(fmtSource); } else { if (fmtOptions.isUnscape) { fmtSource = fmtSource.replace(/\\"/gm, '"').replace(/\\\\/gm, '\\'); } doSpecialFormat(); } } catch (err) { // console.log(err); if (fmtOptions.isUnscape) { fmtSource = fmtSource.replace(/\\"/gm, '"').replace(/\\\\/gm, '\\'); } doSpecialFormat(); } } catch (err) { // console.log(err); isFmtError = true; } finally { setFmtStatus(); return withDetails ? { result: fmtResult, fmtType: fmtType, fmtSign: fmtSign, fmtLines: fmtLines, message: message, errFormat: errFormat, errIndex: errIndex, errNear: errNear, errExpect: errExpect } : fmtResult; } /** * ================================================================= * Format the Normal JSON source * @param {*} src * ================================================================= */ function doNormalFormat(src) { if ([true, false, null, ''].indexOf(src) > -1) { return fmtResult += String(src); } if (fmtOptions.isStrict) { src = JSON.parse(JSON.stringify(src)); } src instanceof Array ? arrayHandler(src) : objectHandler(src); } function arrayHandler(srcArr) { var curIndent; if (srcArr.length > 0) { fmtResult += brkLine4Normal('['); curLevel++; for (var i = 0; i < srcArr.length; i++) { curIndent = fmtOptions.isExpand ? getCurIndent() : ''; fmtResult += curIndent; valueHandler(srcArr[i]); fmtResult += brkLine4Normal(i < srcArr.length - 1 ? ',' : ''); } curLevel--; curIndent = fmtOptions.isExpand ? getCurIndent() : ''; fmtResult += curIndent + ']'; } else { fmtResult += '[]'; } } function objectHandler(srcObj) { var objKeys = Object.keys(srcObj); if (objKeys.length > 0) { var curIndent, index = 0; fmtResult += brkLine4Normal('{'); curLevel++; for (var key in srcObj) { index++; var prop = quoteNormalStr(key, fmtOptions.keyQtMark); curIndent = fmtOptions.isExpand ? getCurIndent() : ''; fmtResult += curIndent; fmtResult += prop; fmtResult += fmtOptions.isExpand ? ': ' : ':'; valueHandler(srcObj[key]); fmtResult += brkLine4Normal(index < objKeys.length ? ',' : ''); } curLevel--; curIndent = fmtOptions.isExpand ? getCurIndent() : ''; fmtResult += curIndent + '}'; } else { fmtResult += '{}'; } } function valueHandler(value) { switch (typeof value) { case 'undefined': case 'function': return fmtResult += String(value); case 'number': case 'boolean': return fmtResult += value; case 'object': return doNormalFormat(value); case 'string': return fmtResult += quoteNormalStr(value, fmtOptions.valQtMark); } } /** * ================================================================= * Format the Abnormal JSON source * ================================================================= */ function doSpecialFormat() { fmtSource = fmtSource.replace(/^\s*/, ''); if (fmtSource.length === 0) return; var isMatched = false; switch (fmtSource[0]) { case "'": case '"': isMatched = true; quotaHandler(); break; case ':': isMatched = true; colonHandler(); break; case ',': isMatched = true; commaHandler(); break; case '{': isMatched = true; objPreHandler(); break; case '}': isMatched = true; objEndHandler(); break; case '[': isMatched = true; arrPreHandler(); break; case ']': isMatched = true; arrEndHandler(); break; case '(': isMatched = true; tupPreHandler(); break; case ')': isMatched = true; tupEndHandler(); break; } if (!isMatched) { var unicMt = fmtSource.match(/^u(\s)?'|^u(\s)?"/); if (unicMt) { isMatched = true; unicHandler(unicMt[0]); } } if (!isMatched) { var numbMt = fmtSource.match(/^(-?[0-9]+\.?[0-9]*|0[xX][0-9a-fA-F]+)/); if (numbMt) { isMatched = true; numbHandler(numbMt[0]); } } if (!isMatched) { var boolMt = fmtSource.match(/^(true|false|True|False)/); if (boolMt) { isMatched = true; boolHandler(boolMt[0]); } } if (!isMatched) { var nullMt = fmtSource.match(/^(null|undefined|None|NaN)/); if (nullMt) { isMatched = true; nullHandler(nullMt[0]); } } if (!isMatched) otheHandler(); return doSpecialFormat(); } function quotaHandler() { var rest = getSrcRest(); var restIdx = getNextQuotaIndex(fmtSource[0], rest); chkFmtExpect(fmtSource[0]); var quoteMt = fmtSource.substr(0, 1); var isProperty = exceptType === 'ost'; var strInQuote = ''; if (restIdx > -1) { strInQuote = fmtSource.substr(1, restIdx); fmtResult += quoteSpecialStr(strInQuote, quoteMt, isProperty); setFmtExpect(fmtSource[0]); fmtSource = getSrcRest(restIdx + 2); } else { strInQuote = fmtSource.substr(1); fmtResult += quoteSpecialStr(strInQuote, quoteMt, isProperty); setFmtExpect('!'); fmtSource = ''; } } function colonHandler() { fmtResult += fmtOptions.isExpand ? ': ' : ':'; chkFmtExpect(fmtSource[0]); setFmtExpect(fmtSource[0]); fmtSource = getSrcRest(); } function commaHandler() { var curIndent = getCurIndent(); if (fmtOptions.isExpand) curIndex++; fmtResult += fmtOptions.isExpand ? ",".concat(BREAK + curIndent) : ','; chkFmtExpect(fmtSource[0]); setFmtExpect(fmtSource[0]); fmtSource = getSrcRest(); if (fmtSource.replace(/(\r)?\n|\s/gm, '') === '') setFmtError('val'); } function objPreHandler() { chkFmtExpect(fmtSource[0]); setFmtExpect(fmtSource[0]); if (fmtSource[1] && fmtSource[1] === '}') { fmtResult += '{}'; setFmtExpect('}'); fmtSource = getSrcRest(2); } else { curLevel++; fmtResult += '{'; brkLine4Special(); fmtSource = getSrcRest(); } } function objEndHandler() { curLevel--; brkLine4Special('}'); chkFmtExpect(fmtSource[0]); setFmtExpect(fmtSource[0]); fmtSource = getSrcRest(); } function arrPreHandler() { chkFmtExpect(fmtSource[0]); setFmtExpect(fmtSource[0]); if (fmtSource[1] && fmtSource[1] === ']') { fmtResult += '[]'; setFmtExpect(']'); fmtSource = getSrcRest(2); } else { curLevel++; fmtResult += '['; brkLine4Special(); fmtSource = getSrcRest(); } } function arrEndHandler() { curLevel--; brkLine4Special(']'); chkFmtExpect(fmtSource[0]); setFmtExpect(fmtSource[0]); fmtSource = getSrcRest(); } function tupPreHandler() { chkFmtExpect(fmtSource[0]); setFmtExpect(fmtSource[0]); if (fmtSource[1] && fmtSource[1] === ')') { fmtResult += fmtOptions.isStrict ? '[]' : '()'; setFmtExpect(')'); fmtSource = getSrcRest(2); } else { curLevel++; fmtResult += fmtOptions.isStrict ? '[' : '('; brkLine4Special(); fmtSource = getSrcRest(); } } function tupEndHandler() { curLevel--; brkLine4Special(fmtOptions.isStrict ? ']' : ')'); chkFmtExpect(fmtSource[0]); setFmtExpect(fmtSource[0]); fmtSource = getSrcRest(); } function unicHandler(unicMt) { var rest = getSrcRest(unicMt.length); var restIdx = unicMt.indexOf("'") > -1 ? getNextQuotaIndex("'", rest) : getNextQuotaIndex('"', rest); chkFmtExpect('u'); var isProperty = exceptType === 'ost'; var uniqStr = ''; if (restIdx > -1) { var cutIdx = restIdx + unicMt.length + 1; uniqStr = fmtSource.substr(unicMt.length, cutIdx - unicMt.length - 1); fmtResult += quoteSpecialStr(uniqStr, unicMt, isProperty); setFmtExpect('u'); fmtSource = getSrcRest(cutIdx); } else { uniqStr = fmtSource.substr(unicMt.length); fmtResult += quoteSpecialStr(uniqStr, unicMt, isProperty); setFmtExpect('!'); fmtSource = ''; } } function numbHandler(numbMt) { fmtResult += numbMt; chkFmtExpect('n'); setFmtExpect('n'); fmtSource = getSrcRest(numbMt.length); } function boolHandler(boolMt) { fmtResult += fmtOptions.isStrict ? boolMt.toLowerCase() : boolMt; chkFmtExpect('b'); setFmtExpect('b'); fmtSource = getSrcRest(boolMt.length); } function nullHandler(nullMt) { fmtResult += fmtOptions.isStrict ? 'null' : nullMt; chkFmtExpect('N'); setFmtExpect('N'); fmtSource = getSrcRest(nullMt.length); } function otheHandler() { var strMatch = fmtSource.match(/^[^\{\}\[\]\(\):,]*/); var strMated = strMatch && strMatch[0] || ''; if (strMated) { fmtResult += strMated; chkFmtExpect('!'); fmtSource = getSrcRest(strMated.length); } } function chkFmtExpect(sign) { if (isSrcValid) { switch (exceptType) { case 'val': if (':,}])!'.indexOf(sign) > -1) { setFmtError('val'); } break; case 'ost': if ('\'"unbN'.indexOf(sign) === -1) { setFmtError('ost'); } break; case 'end': var endBracket = getBracketPair(exceptSign); if ([',', endBracket].indexOf(sign) === -1) { setFmtError('end', endBracket); } break; case 'col': if (sign !== ':') { setFmtError('col'); } break; } } } function setFmtExpect(sign) { switch (sign) { case ':': exceptType = 'val'; break; case ',': exceptSign === '{' ? exceptType = 'ost' : exceptType = 'val'; break; case '{': exceptSign = sign; signsQueue += sign; exceptType = 'ost'; break; case '}': signsQueue = signsQueue.substr(0, signsQueue.length - 1); exceptSign = signsQueue.substr(-1); exceptType = 'end'; break; case '[': exceptSign = sign; signsQueue += sign; exceptType = 'val'; break; case ']': signsQueue = signsQueue.substr(0, signsQueue.length - 1); exceptSign = signsQueue.substr(-1); exceptType = 'end'; break; case '(': exceptSign = sign; signsQueue += sign; exceptType = 'val'; break; case ')': signsQueue = signsQueue.substr(0, signsQueue.length - 1); exceptSign = signsQueue.substr(-1); exceptType = 'end'; break; case 'u': case 'n': case 'b': case 'N': case '"': case "'": exceptType === 'ost' ? exceptType = 'col' : exceptType = 'end'; break; } } function setFmtError(sign) { var brc = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; switch (sign) { case 'war': fmtType = 'warning'; break; case 'scc': fmtType = 'success'; break; default: fmtType = 'danger'; break; } if (['ost', 'col', 'val', 'end'].indexOf(sign) > -1) { errFormat = true; isSrcValid = false; errExpect = brc; errIndex = curIndex; var rstTrailing = fmtResult.substr(-20).replace(/^(\s|\n|\r\n)*/, '').replace(/(\n|\r\n)/gm, '\\n'); var srcLeading = fmtSource.substr(0, 10).replace(/(\s|\n|\r\n)*$/, '').replace(/(\n|\r\n)/gm, '\\n'); errNear = "...".concat(rstTrailing, ">>>>>>").concat(srcLeading); } fmtSign = sign; message = MESSAGES_MAP[sign](curIndex, brc); } function setFmtStatus() { if (isFmtError && !errIndex) { setFmtError('err'); errFormat = true; } else if (isSrcValid) { if (signsQueue) { var expBracket = getBracketPair(signsQueue.substr(-1)); setFmtError('end', expBracket); } else { setFmtError('scc'); } } fmtLines = curIndex; } /** * ================================================================= * Util functions for the format. * ================================================================= */ function brkLine4Normal(str) { if (!fmtOptions.isExpand) return str; curIndex++; return str + BREAK; } function brkLine4Special() { var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; if (!fmtOptions.isExpand) return fmtResult += str; curIndex++; fmtResult += BREAK + getCurIndent() + str; } function quoteNormalStr(qtStr, quote) { var isFromAbnormal = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var isEscape = fmtOptions.isEscape && fmtOptions.keyQtMark === '"' && quote === '"' && (!isFromAbnormal || fmtOptions.isStrict); qtStr = isFromAbnormal ? qtStr.replace(/(?!\\[b|f|n|\\|r|t|x|v|'|"|0])\\/gm, '\\\\') : qtStr.replace(/\\/gm, '\\\\'); ESCAPES_MAP.forEach(function (esp) { return qtStr = qtStr.replace(esp.ptn, esp.str); }); var quote_ = isEscape ? "\\".concat(quote) : quote; if (isEscape) qtStr = qtStr.replace(/\\/gm, '\\\\'); switch (quote) { case '"': qtStr = isEscape ? qtStr.replace(/"/gm, '\\\\\\"') : qtStr.replace(/"/gm, '\\"'); return quote_ + qtStr + quote_; case "'": qtStr = qtStr.replace(/'/gm, "\\'"); return quote_ + qtStr + quote_; default: return qtStr; } } function quoteSpecialStr(qtStr, quoteMt, isProperty) { var quote = isProperty ? fmtOptions.keyQtMark : fmtOptions.valQtMark; qtStr = qtStr.replace(/(?!\\[b|f|n|\\|r|t|x|v|'|"|0])\\/gm, ''); qtStr = qtStr.replace(/\\\"/gm, '"'); qtStr = qtStr.replace(/\\\'/gm, "'"); qtStr = quoteNormalStr(qtStr, quote, true); if (!fmtOptions.isStrict && quoteMt.length > 1) { qtStr = quoteMt.substr(0, quoteMt.length - 1) + qtStr; } return qtStr; } function getSrcRest() { var len = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; return fmtSource.length > len ? fmtSource.substr(len) : ''; } function getNextQuotaIndex(quo, rest) { for (var i = 0; i < rest.length; i++) { if (rest[i] === quo) { if (i === 0 || rest[i - 1] !== '\\' || rest[i - 1] === '\\' && rest[i - 2] === '\\' && rest[i - 3] !== '\\') { return i; } } } return -1; } function getBaseIndent() { var indent = ''; for (var i = 0; i < fmtOptions.indent; i++) { indent += SPACE; } return indent; } function getCurIndent() { var indent = ''; for (var i = 0; i < curLevel; i++) { indent += baseIndent; } return indent; } function getBracketPair(braSign) { var pre = ['{', '[', '(']; var end = ['}', ']', ')']; var preIdx = pre.indexOf(braSign); var endIdx = end.indexOf(braSign); return preIdx > -1 ? end[preIdx] : pre[endIdx]; } } /** * ================================================================= * UMD modules define. * ================================================================= */ if (typeof define === 'function' && define.amd) { define(function () { return fmt2json; }); } else if (typeof exports === 'object') { module.exports = fmt2json; } else { root.fmt2json = fmt2json; } })(this);