diff --git a/extension/src/json-viewer/check-if-json.js b/extension/src/json-viewer/check-if-json.js index 67398665..d9c009a4 100644 --- a/extension/src/json-viewer/check-if-json.js +++ b/extension/src/json-viewer/check-if-json.js @@ -55,7 +55,7 @@ function isJSON(jsonStr) { } function isJSONP(jsonStr) { - return isJSON(extractJSON(jsonStr)); + return isJSON(extractJSON.replaceWrapper(jsonStr)); } function checkIfJson(sucessCallback, element) { diff --git a/extension/src/json-viewer/content-extractor.js b/extension/src/json-viewer/content-extractor.js index 90db387b..d061c9d2 100644 --- a/extension/src/json-viewer/content-extractor.js +++ b/extension/src/json-viewer/content-extractor.js @@ -15,30 +15,41 @@ var REPLACE_WRAP_REGEX = new RegExp( "\"" + WRAP_START + "(-?\\d+\\.?[\\deE]*)" + WRAP_END + "\"", "g" ); -function contentExtractor(pre, options) { +function getJSON(pre, options) { return new Promise(function(resolve, reject) { try { var rawJsonText = pre.textContent; - var jsonExtracted = extractJSON(rawJsonText); + var jsonpWrapper = extractJSON.getWrapper(rawJsonText); + var jsonExtracted = extractJSON.replaceWrapper(rawJsonText); var wrappedText = wrapNumbers(jsonExtracted); var jsonParsed = JSON.parse(wrappedText); if (options.addons.sortKeys) jsonParsed = sortByKeys(jsonParsed); - // Validate and decode json - var decodedJson = JSON.stringify(jsonParsed); - decodedJson = decodedJson.replace(REPLACE_WRAP_REGEX, "$1"); - - var jsonFormatted = normalize(jsonFormater(decodedJson, options.structure)); - var jsonText = normalize(rawJsonText).replace(normalize(jsonExtracted), jsonFormatted); - resolve({jsonText: jsonText, jsonExtracted: decodedJson}); - + resolve({jsonObj: jsonParsed, jsonpWrapper: jsonpWrapper, options: options}); } catch(e) { reject(new Error('contentExtractor: ' + e.message)); } }); } +function formatJSON(data) { + return new Promise(function(resolve, reject) { + var decodedJson = JSON.stringify(data.jsonObj).replace(REPLACE_WRAP_REGEX, "$1"); + var jsonFormatted = normalize(jsonFormater(decodedJson, data.options.structure)); + var filterQuery = data.filterQuery + ? '/* FILTER: ' + data.filterQuery + ' */\n' + : '' + var jsonText = + filterQuery + + normalize(data.jsonpWrapper.header) + + jsonFormatted + + normalize(data.jsonpWrapper.footer); + + resolve({jsonText: jsonText, jsonObj: data.jsonObj}); + }) +} + function normalize(json) { return json.replace(/\$/g, '$$$$'); } @@ -131,4 +142,7 @@ function isCharInString(char, previous) { char != '-'; } -module.exports = contentExtractor; +module.exports = { + getJSON: getJSON, + formatJSON: formatJSON +}; diff --git a/extension/src/json-viewer/extract-json.js b/extension/src/json-viewer/extract-json.js index 58200399..f399dbf8 100644 --- a/extension/src/json-viewer/extract-json.js +++ b/extension/src/json-viewer/extract-json.js @@ -1,9 +1,30 @@ -function extractJSON(rawJson) { - return rawJson - .replace(/\s*while\((1|true)\)\s*;?/, '') - .replace(/\s*for\(;;\)\s*;?/, '') - .replace(/^[^{\[].+\({/, '{') - .replace(/}\);?\s*$/, '}'); +var JSONP_HEADER_REGEX = new RegExp([ + '(\\s*while\\((1|true)\\)\\s*;?)', + '(\\s*for\\(;;\\)\\s*;?)', + '(^[^{\\[].+?\\()' +].join('|')) + +var JSONP_FOOTER_REGEX = /\);?\s*$/ + +function replaceWrapper(rawJsonString) { + return rawJsonString + .replace(JSONP_HEADER_REGEX, '') + .replace(JSONP_FOOTER_REGEX, '') +} + +function getWrapper (rawJsonString) { + var wrapper = { header: '', footer: '' }; + + var header = rawJsonString.match(JSONP_HEADER_REGEX) + wrapper.header = header ? header[0] : '' + + var footer = rawJsonString.match(JSONP_FOOTER_REGEX) + wrapper.footer = footer ? footer[0] : '' + + return wrapper; } -module.exports = extractJSON; +module.exports = { + replaceWrapper: replaceWrapper, + getWrapper: getWrapper +}; diff --git a/extension/src/json-viewer/filter.js b/extension/src/json-viewer/filter.js new file mode 100644 index 00000000..3522e818 --- /dev/null +++ b/extension/src/json-viewer/filter.js @@ -0,0 +1,79 @@ +function applyQuery(query) { + return function (data) { + var fullQuery = typeof query === 'string' + ? query.toString().split('.') + : ''; + + if (!query) { + return data; + } + + var filteredJson = null; + + if (Array.isArray(data.jsonObj)) { + filteredJson = data.jsonObj.reduce(function(acc, next) { + acc.push(filter(next, fullQuery)); + return acc; + }, []) + } else { + filteredJson = filter(data.jsonObj, fullQuery); + } + + return { + jsonObj: filteredJson, + jsonpWrapper: data.jsonpWrapper, + options: data.options, + filterQuery: query + } + } +} + +function filter(input, query) { + var querySegment = query.length ? query[0] : null; + var nextQuery = query.slice(1); + + if (!querySegment) return input; + + var secondaryFilter = []; + var match = querySegment.match(/^(.*)\[(.*)\]$/); + if (match && match.length > 0) { + querySegment = match[1]; + secondaryFilter = (match[2] || '') + .split(',') + .map(function (key) { + return key.trim() + }); + } + + var result = {}; + + if (!querySegment || typeof input[querySegment] !== 'object') { + if (secondaryFilter.length) { + secondaryFilter.forEach(function(key) { + if (input.hasOwnProperty(key)) { + result[key] = input[key]; + } + }) + } else { + result[querySegment] = input[querySegment]; + } + return result; + } + + if (Array.isArray(input[querySegment])) { + result[querySegment] = input[querySegment].reduce((acc, next, i) => { + var indexInSecondaryFilter = secondaryFilter.indexOf(i.toString()) !== -1; + if (!secondaryFilter.length || (secondaryFilter.length && indexInSecondaryFilter)) { + acc.push(filter(next, nextQuery)); + } + return acc; + }, []) + } else { + result[querySegment] = filter(input[querySegment], nextQuery); + } + return result; +} + +module.exports = { + applyQuery: applyQuery +} diff --git a/extension/src/json-viewer/highlight-content.js b/extension/src/json-viewer/highlight-content.js index 48f53666..8aeeda46 100644 --- a/extension/src/json-viewer/highlight-content.js +++ b/extension/src/json-viewer/highlight-content.js @@ -1,4 +1,5 @@ var contentExtractor = require('./content-extractor'); +var jsonFilter = require('./filter'); var Highlighter = require('./highlighter'); var timestamp = require('./timestamp'); var exposeJson = require('./viewer/expose-json'); @@ -52,13 +53,21 @@ function highlightContent(pre, outsideViewer) { return pre.hidden = false; } - return contentExtractor(pre, options). - then(function(value) { - return loadRequiredCss(options).then(function() { return value; }); - }). - then(function(value) { - - var formatted = prependHeader(options, outsideViewer, value.jsonText); + var filterQuery = decodeURIComponent(document.location.hash.substring(1)) || '' + + return contentExtractor.getJSON(pre, options) + .then((data) => { + exposeJson(data.jsonObj, outsideViewer); + return data; + }) + .then(jsonFilter.applyQuery(filterQuery)) + .then(contentExtractor.formatJSON) + .then(function(data) { + return loadRequiredCss(options).then(function() { return data; }); + }) + .then(function(data) { + + var formatted = prependHeader(options, outsideViewer, data.jsonText); var highlighter = new Highlighter(formatted, options); if (options.addons.autoHighlight) { @@ -83,9 +92,7 @@ function highlightContent(pre, outsideViewer) { highlighter.fold(); } - exposeJson(value.jsonExtracted, outsideViewer); renderExtras(pre, options, highlighter); - }); }).catch(function(e) { diff --git a/extension/src/json-viewer/viewer/expose-json.js b/extension/src/json-viewer/viewer/expose-json.js index 713c8383..92abbaea 100644 --- a/extension/src/json-viewer/viewer/expose-json.js +++ b/extension/src/json-viewer/viewer/expose-json.js @@ -1,12 +1,12 @@ -function exposeJson(text, outsideViewer) { +function exposeJson(jsonObj, outsideViewer) { console.info("[JSONViewer] Your json was stored into 'window.json', enjoy!"); if (outsideViewer) { - window.json = JSON.parse(text); + window.json = jsonObj; } else { var script = document.createElement("script") ; - script.innerHTML = 'window.json = ' + text + ';'; + script.innerHTML = 'window.json = ' + JSON.stringify(jsonObj) + ';'; document.head.appendChild(script); } }