From c645975102cee8b57a298d15fcb03e389c316148 Mon Sep 17 00:00:00 2001 From: Boaz Leskes Date: Fri, 9 Dec 2016 17:28:26 +0100 Subject: [PATCH] Add console scripts --- .../console/api_server/es_5_0/query.js | 11 +- .../console/public/css/sense.light.less | 8 ++ .../console/public/src/autocomplete.js | 36 ++++-- src/core_plugins/console/public/src/input.js | 8 +- .../console/public/src/sense_editor/editor.js | 12 +- .../public/src/sense_editor/mode/input.js | 8 +- .../mode/input_highlight_rules.js | 95 ++------------- .../mode/output_highlight_rules.js | 11 +- .../public/src/sense_editor/mode/script.js | 66 +++++++++++ .../mode/script_highlight_rules.js | 66 +++++++++++ .../public/src/sense_editor/mode/worker.js | 59 +++++++--- .../mode/x_json_highlight_rules.js | 111 ++++++++++++++++++ src/core_plugins/console/public/src/utils.js | 16 ++- .../console/public/tests/src/editor_tests.js | 43 ++++++- .../public/tests/src/integration_tests.js | 8 +- .../public/tests/src/tokenization_tests.js | 95 ++++++++++++++- .../tests/src/utils_string_collapsing.txt | 26 ++++ .../tests/src/utils_string_expanding.txt | 21 ++++ .../console/public/tests/src/utils_tests.js | 36 ++++++ .../console/public/tests/tests.js | 1 + 20 files changed, 597 insertions(+), 140 deletions(-) create mode 100644 src/core_plugins/console/public/src/sense_editor/mode/script.js create mode 100644 src/core_plugins/console/public/src/sense_editor/mode/script_highlight_rules.js create mode 100644 src/core_plugins/console/public/src/sense_editor/mode/x_json_highlight_rules.js create mode 100644 src/core_plugins/console/public/tests/src/utils_string_collapsing.txt create mode 100644 src/core_plugins/console/public/tests/src/utils_string_expanding.txt create mode 100644 src/core_plugins/console/public/tests/src/utils_tests.js diff --git a/src/core_plugins/console/api_server/es_5_0/query.js b/src/core_plugins/console/api_server/es_5_0/query.js index 99e35f3a8110b1..3bf4d001495845 100644 --- a/src/core_plugins/console/api_server/es_5_0/query.js +++ b/src/core_plugins/console/api_server/es_5_0/query.js @@ -612,7 +612,16 @@ module.exports = function (api) { min_score: 1.0 }, SCORING_FUNCS - ) + ), + script: { + __template: { + "script": "_score * doc['f'].value" + }, + script: { + //populated by a global rule + } + }, + }); }; diff --git a/src/core_plugins/console/public/css/sense.light.less b/src/core_plugins/console/public/css/sense.light.less index cb6963043cb7be..9210a781c47e3b 100644 --- a/src/core_plugins/console/public/css/sense.light.less +++ b/src/core_plugins/console/public/css/sense.light.less @@ -18,6 +18,14 @@ border-left: 1px solid #CCC; } +.ace_multi_string { + color: #166555; +} + +.ace_start_triple_quote, .ace_end_triple_quote { + color: #40B0D3; +} + .ace_snippet-marker { background: rgba(194, 193, 208, 0.20); border-top: dotted 1px rgba(194, 193, 208, 0.80); diff --git a/src/core_plugins/console/public/src/autocomplete.js b/src/core_plugins/console/public/src/autocomplete.js index 9eb83f4ad65745..e8d159e8bd266f 100644 --- a/src/core_plugins/console/public/src/autocomplete.js +++ b/src/core_plugins/console/public/src/autocomplete.js @@ -8,7 +8,6 @@ let url_pattern_matcher = require('./autocomplete/url_pattern_matcher'); let _ = require('lodash'); let ext_lang_tools = require('ace/ext-language_tools'); - var AceRange = ace.require('ace/range').Range; var LAST_EVALUATED_TOKEN = null; @@ -226,7 +225,6 @@ module.exports = function (editor) { return null; } - if (!context.autoCompleteSet) { return null; // nothing to do.. } @@ -445,7 +443,6 @@ module.exports = function (editor) { break; // for now play safe and do nothing. May be made smarter. } - // go back to see whether we have one of ( : { & [ do not require a comma. All the rest do. tokenIter = editor.iterForCurrentLoc(); nonEmptyToken = tokenIter.getCurrentToken(); @@ -471,7 +468,6 @@ module.exports = function (editor) { nonEmptyToken = editor.parser.prevNonEmptyToken(tokenIter); } - switch (nonEmptyToken ? nonEmptyToken.type : "NOTOKEN") { case "NOTOKEN": case "paren.lparen": @@ -581,7 +577,6 @@ module.exports = function (editor) { return context; } - // needed for scope linking + global term resolving context.endpointComponentResolver = kb.getEndpointBodyCompleteComponents; context.globalComponentResolver = kb.getGlobalAutocompleteComponents; @@ -597,7 +592,6 @@ module.exports = function (editor) { return context; } - function getCurrentMethodAndTokenPaths(pos) { var tokenIter = editor.iterForPosition(pos.row, pos.column); var startPos = pos; @@ -645,7 +639,6 @@ module.exports = function (editor) { state = STATES.looking_for_scope_start; // skip everything until the beginning of this scope break; - case "paren.lparen": bodyTokenPath.unshift(t.value); if (state == STATES.looking_for_scope_start) { @@ -677,6 +670,29 @@ module.exports = function (editor) { return {}; } continue; + case "punctuation.end_triple_quote": + // reset the search for key + state = STATES.looking_for_scope_start; + for (t = tokenIter.stepBackward(); t; t = tokenIter.stepBackward()) { + if (t.type === "punctuation.start_tripple_qoute") { + t = tokenIter.stepBackward(); + break; + } + } + if (!t) // oops we run out.. we don't know what's up return null; + { + return {}; + } + continue; + case "punctuation.start_triple_quote": + if (state == STATES.start) { + state = STATES.looking_for_key; + } + else if (state == STATES.looking_for_key) { + state = STATES.looking_for_scope_start; + } + bodyTokenPath.unshift('"""'); + continue; case "string": case "constant.numeric": case "constant.language.boolean": @@ -761,7 +777,6 @@ module.exports = function (editor) { t = tokenIter.stepBackward(); } - curUrlPart = null; while (t && t.type.indexOf("url") != -1) { switch (t.type) { @@ -814,7 +829,6 @@ module.exports = function (editor) { return ret; } - var evaluateCurrentTokenAfterAChange = _.debounce(function evaluateCurrentTokenAfterAChange(pos) { var session = editor.getSession(); var currentToken = session.getTokenAt(pos.row, pos.column); @@ -843,7 +857,6 @@ module.exports = function (editor) { return; } - if (!LAST_EVALUATED_TOKEN) { LAST_EVALUATED_TOKEN = currentToken; return; // wait for the next typing. @@ -886,7 +899,6 @@ module.exports = function (editor) { editor.off("changeSelection", editorChangeListener) } - function getCompletions(aceEditor, session, pos, prefix, callback) { try { @@ -949,7 +961,6 @@ module.exports = function (editor) { } } - addChangeListener(); // Hook into Ace @@ -997,7 +1008,6 @@ module.exports = function (editor) { prefix = getAutoCompleteValueFromToken(token); } - var matches = []; aceUtils.parForEach(ace_editor.completers, function (completer, next) { completer.getCompletions(ace_editor, session, pos, prefix, function (err, results) { diff --git a/src/core_plugins/console/public/src/input.js b/src/core_plugins/console/public/src/input.js index efd8a22c2c906e..37860279d1d718 100644 --- a/src/core_plugins/console/public/src/input.js +++ b/src/core_plugins/console/public/src/input.js @@ -16,7 +16,11 @@ let input; export function initializeInput($el, $actionsEl, $copyAsCurlEl, output) { input = new SenseEditor($el); - uiModules.get('app/sense').setupResizeCheckerForRootEditors($el, input, output); + // this may not exist if running from tests + let appSense = uiModules.get('app/sense'); + if (appSense.setupResizeCheckerForRootEditors) { + appSense.setupResizeCheckerForRootEditors($el, input, output); + } input.autocomplete = new Autocomplete(input); @@ -167,7 +171,7 @@ export function initializeInput($el, $actionsEl, $copyAsCurlEl, output) { if (mode === null || mode === "application/json") { // assume json - auto pretty try { - value = JSON.stringify(JSON.parse(value), null, 2); + value = utils.expandScriptsToLiterals(JSON.stringify(JSON.parse(value), null, 2)); } catch (e) { diff --git a/src/core_plugins/console/public/src/sense_editor/editor.js b/src/core_plugins/console/public/src/sense_editor/editor.js index 184427fe335dcc..50e38704f2ef44 100644 --- a/src/core_plugins/console/public/src/sense_editor/editor.js +++ b/src/core_plugins/console/public/src/sense_editor/editor.js @@ -136,11 +136,12 @@ function SenseEditor($el) { var formatted_data = utils.reformatData(parsed_req.data, indent); if (!formatted_data.changed) { // toggle. - formatted_data = utils.reformatData(parsed_req.data, !indent); + indent = !indent; + formatted_data = utils.reformatData(parsed_req.data, indent); } parsed_req.data = formatted_data.data; - editor.replaceRequestRange(parsed_req, req_range); + editor.replaceRequestRange(parsed_req, req_range, indent); } }); }); @@ -164,8 +165,8 @@ function SenseEditor($el) { }; - editor.replaceRequestRange = function (newRequest, requestRange) { - var text = utils.textFromRequest(newRequest); + editor.replaceRequestRange = function (newRequest, requestRange, autoExpandScripts) { + var text = utils.textFromRequest(newRequest, autoExpandScripts); if (requestRange) { var pos = editor.getCursorPosition(); editor.getSession().replace(requestRange, text); @@ -317,7 +318,8 @@ function SenseEditor($el) { dataEndPos.row, dataEndPos.column ); var data = editor.getSession().getTextRange(bodyRange); - request.data.push(data.trim()); + data = utils.collapseLiteralStrings(data.trim()); + request.data.push(data); bodyStartRow = dataEndPos.row + 1; } diff --git a/src/core_plugins/console/public/src/sense_editor/mode/input.js b/src/core_plugins/console/public/src/sense_editor/mode/input.js index 9b197b96740c2f..1f3239a9d0a114 100644 --- a/src/core_plugins/console/public/src/sense_editor/mode/input.js +++ b/src/core_plugins/console/public/src/sense_editor/mode/input.js @@ -4,6 +4,7 @@ let mode_json = require('ace/mode-json'); var oop = acequire("ace/lib/oop"); var TextMode = acequire("ace/mode/text").Mode; +var ScriptMode = require("./script").ScriptMode; var MatchingBraceOutdent = acequire("ace/mode/matching_brace_outdent").MatchingBraceOutdent; var CstyleBehaviour = acequire("ace/mode/behaviour/cstyle").CstyleBehaviour; var CStyleFoldMode = acequire("ace/mode/folding/cstyle").FoldMode; @@ -20,6 +21,9 @@ var Mode = function () { this.$outdent = new MatchingBraceOutdent(); this.$behaviour = new CstyleBehaviour(); this.foldingRules = new CStyleFoldMode(); + this.createModeDelegates({ + "script-": ScriptMode + }); }; oop.inherits(Mode, TextMode); @@ -32,7 +36,9 @@ oop.inherits(Mode, TextMode); this.getNextLineIndent = function (state, line, tab) { var indent = this.$getIndent(line); - if (state != "double_q_string") { + if (state == "string_literal") { + // noop + } else { var match = line.match(/^.*[\{\(\[]\s*$/); if (match) { indent += tab; diff --git a/src/core_plugins/console/public/src/sense_editor/mode/input_highlight_rules.js b/src/core_plugins/console/public/src/sense_editor/mode/input_highlight_rules.js index da256594bfb456..537ffb3cdc5970 100644 --- a/src/core_plugins/console/public/src/sense_editor/mode/input_highlight_rules.js +++ b/src/core_plugins/console/public/src/sense_editor/mode/input_highlight_rules.js @@ -1,4 +1,6 @@ let ace = require('ace'); +let x_json = require('./x_json_highlight_rules'); +let _ = require('lodash'); var oop = ace.require("ace/lib/oop"); var TextHighlightRules = ace.require("ace/mode/text_highlight_rules").TextHighlightRules; @@ -55,101 +57,18 @@ var InputHighlightRules = function () { addEOL(["url.param", "url.equal", "url.value"], /([^&=]+)(=)([^&]*)/, "start"), addEOL(["url.param"], /([^&=]+)/, "start"), addEOL(["url.amp"], /(&)/, "start") - ), - - - "json": [ - { - token: "variable", // single line - regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)' - }, - { - token: "string", // single line - regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' - }, - { - token: "constant.numeric", // hex - regex: "0[xX][0-9a-fA-F]+\\b" - }, - { - token: "constant.numeric", // float - regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" - }, - { - token: "constant.language.boolean", - regex: "(?:true|false)\\b" - }, - { - token: "invalid.illegal", // single quoted strings are not allowed - regex: "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" - }, - { - token: "invalid.illegal", // comments are not allowed - regex: "\\/\\/.*$" - }, - { - token: "paren.lparen", - merge: false, - regex: "{", - next: "json", - push: true - }, - { - token: "paren.lparen", - merge: false, - regex: "[[(]" - }, - { - token: "paren.rparen", - merge: false, - regex: "[\\])]" - }, - { - token: "paren.rparen", - regex: "}", - merge: false, - next: "pop" - }, - { - token: "punctuation.comma", - regex: "," - }, - { - token: "punctuation.colon", - regex: ":" - }, - { - token: "whitespace", - regex: "\\s+" - }, - { - token: "text", - regex: ".+?" - } - ], - "double_q_string": [ - { - token: "string", - regex: '[^"]+' - }, - { - token: "punctuation.end_quote", - regex: '"', - next: "json" - }, - { - token: "string", - regex: "", - next: "json" - } - ] + ) }; + x_json.addToRules(this); + if (this.constructor === InputHighlightRules) { this.normalizeRules(); } + }; oop.inherits(InputHighlightRules, TextHighlightRules); + module.exports.InputHighlightRules = InputHighlightRules; diff --git a/src/core_plugins/console/public/src/sense_editor/mode/output_highlight_rules.js b/src/core_plugins/console/public/src/sense_editor/mode/output_highlight_rules.js index 97b76cf71aaf9b..236c980f95336f 100644 --- a/src/core_plugins/console/public/src/sense_editor/mode/output_highlight_rules.js +++ b/src/core_plugins/console/public/src/sense_editor/mode/output_highlight_rules.js @@ -1,14 +1,15 @@ let ace = require('ace'); let ace_mode_json = require('ace/mode-json'); +let x_json = require('./x_json_highlight_rules'); var oop = ace.require("ace/lib/oop"); var JsonHighlightRules = ace.require("ace/mode/json_highlight_rules").JsonHighlightRules; var OutputJsonHighlightRules = function () { - // regexp must not have capturing parentheses. Use (?:) instead. - // regexps are ordered -> the first match is used - this.$rules = new JsonHighlightRules().getRules(); + this.$rules = {}; + + x_json.addToRules(this, 'start'); this.$rules.start.unshift( { @@ -17,6 +18,10 @@ var OutputJsonHighlightRules = function () { } ); + if (this.constructor === OutputJsonHighlightRules) { + this.normalizeRules(); + } + }; oop.inherits(OutputJsonHighlightRules, JsonHighlightRules); diff --git a/src/core_plugins/console/public/src/sense_editor/mode/script.js b/src/core_plugins/console/public/src/sense_editor/mode/script.js new file mode 100644 index 00000000000000..8ec866ee0dc390 --- /dev/null +++ b/src/core_plugins/console/public/src/sense_editor/mode/script.js @@ -0,0 +1,66 @@ +let ace = require('ace'); +let acequire = require('acequire'); +let mode_json = require('ace/mode-json'); + +var oop = acequire("ace/lib/oop"); +var TextMode = acequire("ace/mode/text").Mode; +var MatchingBraceOutdent = acequire("ace/mode/matching_brace_outdent").MatchingBraceOutdent; +var CstyleBehaviour = acequire("ace/mode/behaviour/cstyle").CstyleBehaviour; +var CStyleFoldMode = acequire("ace/mode/folding/cstyle").FoldMode; +var AceTokenizer = acequire("ace/tokenizer").Tokenizer; + +var ScriptHighlightRules = require("./script_highlight_rules").ScriptHighlightRules; + + +var ScriptMode = function () { + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = new CstyleBehaviour(); + this.foldingRules = new CStyleFoldMode(); +}; +oop.inherits(ScriptMode, TextMode); + +(function () { + // this.getCompletions = function (editor, session, pos, prefix) { + // return []; + // }; + + this.HighlightRules = ScriptHighlightRules; + + this.getNextLineIndent = function (state, line, tab) { + var indent = this.$getIndent(line); + var match = line.match(/^.*[\{\[]\s*$/); + if (match) { + indent += tab; + } + + return indent; + }; + + this.checkOutdent = function (state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function (state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + + // this.createWorker = function (session) { + // var worker = new WorkerClient(["ace", "sense_editor"], "sense_editor/mode/worker", "SenseWorker"); + // worker.attachToDocument(session.getDocument()); + + + // worker.on("error", function (e) { + // session.setAnnotations([e.data]); + // }); + + // worker.on("ok", function (anno) { + // session.setAnnotations(anno.data); + // }); + + // return worker; + // }; + + +}).call(ScriptMode.prototype); + +module.exports.ScriptMode = ScriptMode; diff --git a/src/core_plugins/console/public/src/sense_editor/mode/script_highlight_rules.js b/src/core_plugins/console/public/src/sense_editor/mode/script_highlight_rules.js new file mode 100644 index 00000000000000..645b948808e484 --- /dev/null +++ b/src/core_plugins/console/public/src/sense_editor/mode/script_highlight_rules.js @@ -0,0 +1,66 @@ + +let ace = require('ace'); +let oop = ace.require("ace/lib/oop"); +let TextHighlightRules = ace.require("ace/mode/text_highlight_rules").TextHighlightRules; + +let painlessKeywords = ( + "def|int|long|byte|String|new|null|for|if|return|ctx" +); + +var ScriptHighlightRules = function () { + this.name = "ScriptHighlightRules"; + this.$rules = { + "start": [ + { + token: "script.comment", + regex: "\\/\\/.*$" + }, + { + token : "script.string.regexp", + regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)" + }, + { + token : "script.string", // single line + regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" + }, + { + token : "script.constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+\\b" + }, + { + token : "script.constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, + { + token : "script.constant.language.boolean", + regex : "(?:true|false)\\b" + }, + { + token: "script.keyword", + regex: painlessKeywords + }, + { + token : "script.text", + regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b" + }, + { + token : "script.keyword.operator", + regex : "\\?\\.|\\*\\.|=~|==~|!|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|->|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|typeof|void)" + }, + { + token : "script.lparen", + regex : "[[({]" + }, + { + token : "script.rparen", + regex : "[\\])}]" + }, + { + token : "script.text", + regex : "\\s+" + } + ] + } +}; +oop.inherits(ScriptHighlightRules, TextHighlightRules); +module.exports.ScriptHighlightRules = ScriptHighlightRules; \ No newline at end of file diff --git a/src/core_plugins/console/public/src/sense_editor/mode/worker.js b/src/core_plugins/console/public/src/sense_editor/mode/worker.js index 4371f7ff14b8d7..ac445620b65d6d 100644 --- a/src/core_plugins/console/public/src/sense_editor/mode/worker.js +++ b/src/core_plugins/console/public/src/sense_editor/mode/worker.js @@ -1367,6 +1367,20 @@ define("sense_editor/mode/worker_parser", ['require', 'exports', 'module' ], fun return ch; }, + nextUpTo = function (upTo, errorMessage) { + var currentAt = at, + i = text.indexOf(upTo, currentAt); + if (i < 0) { + error(errorMessage || "Expected '" + upTo + "'"); + } + reset(i + upTo.length); + return text.substring(currentAt, i); + }, + + peek = function (c) { + return text.substr(at, c.length) === c; // nocommit - double check + }, + number = function () { var number, @@ -1414,29 +1428,36 @@ define("sense_editor/mode/worker_parser", ['require', 'exports', 'module' ], fun uffff; if (ch === '"') { - while (next()) { - if (ch === '"') { - next(); - return string; - } else if (ch === '\\') { - next(); - if (ch === 'u') { - uffff = 0; - for (i = 0; i < 4; i += 1) { - hex = parseInt(next(), 16); - if (!isFinite(hex)) { - break; + if (peek('""')) { + // literal + next('"'); + next('"'); + return nextUpTo('"""', "failed to find closing '\"\"\"'"); + } else { + while (next()) { + if (ch === '"') { + next(); + return string; + } else if (ch === '\\') { + next(); + if (ch === 'u') { + uffff = 0; + for (i = 0; i < 4; i += 1) { + hex = parseInt(next(), 16); + if (!isFinite(hex)) { + break; + } + uffff = uffff * 16 + hex; } - uffff = uffff * 16 + hex; + string += String.fromCharCode(uffff); + } else if (typeof escapee[ch] === 'string') { + string += escapee[ch]; + } else { + break; } - string += String.fromCharCode(uffff); - } else if (typeof escapee[ch] === 'string') { - string += escapee[ch]; } else { - break; + string += ch; } - } else { - string += ch; } } } diff --git a/src/core_plugins/console/public/src/sense_editor/mode/x_json_highlight_rules.js b/src/core_plugins/console/public/src/sense_editor/mode/x_json_highlight_rules.js new file mode 100644 index 00000000000000..0be9de94158eb6 --- /dev/null +++ b/src/core_plugins/console/public/src/sense_editor/mode/x_json_highlight_rules.js @@ -0,0 +1,111 @@ +let _ = require("lodash"); +let ScriptHighlightRules = require("./script_highlight_rules").ScriptHighlightRules; + +var jsonRules = function (root) { + root = root ? root : "json"; + var rules = {}; + rules[root] = [ + { + token: ["variable", "whitespace", "ace.punctuation.colon", "whitespace", "punctuation.start_triple_quote"], + regex: '("script"|"inline")(\\s*?)(:)(\\s*?)(""")', + next: "script-start", + merge: false, + push: true + }, + { + token: "variable", // single line + regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)' + }, + { + token: "punctuation.start_triple_quote", + regex: '"""', + next: "string_literal", + merge: false, + push: true + }, + { + token: "string", // single line + regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' + }, + { + token: "constant.numeric", // hex + regex: "0[xX][0-9a-fA-F]+\\b" + }, + { + token: "constant.numeric", // float + regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, + { + token: "constant.language.boolean", + regex: "(?:true|false)\\b" + }, + { + token: "invalid.illegal", // single quoted strings are not allowed + regex: "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" + }, + { + token: "invalid.illegal", // comments are not allowed + regex: "\\/\\/.*$" + }, + { + token: "paren.lparen", + merge: false, + regex: "{", + next: root, + push: true + }, + { + token: "paren.lparen", + merge: false, + regex: "[[(]" + }, + { + token: "paren.rparen", + merge: false, + regex: "[\\])]" + }, + { + token: "paren.rparen", + regex: "}", + merge: false, + next: "pop" + }, + { + token: "punctuation.comma", + regex: "," + }, + { + token: "punctuation.colon", + regex: ":" + }, + { + token: "whitespace", + regex: "\\s+" + }, + { + token: "text", + regex: ".+?" + } + ]; + rules["string_literal"] = [ + { + token: "punctuation.end_triple_quote", + regex: '"""', + next: "pop" + }, + { + token: "multi_string", + regex: "." + } + ]; + return rules; +}; + +module.exports.addToRules = function (otherRules, embedUnder) { + otherRules.$rules = _.defaultsDeep(otherRules.$rules, jsonRules(embedUnder)); + otherRules.embedRules(ScriptHighlightRules, "script-", [{ + token: "punctuation.end_triple_quote", + regex: '"""', + next : "pop", + }]); +} diff --git a/src/core_plugins/console/public/src/utils.js b/src/core_plugins/console/public/src/utils.js index fc53522d23b15f..f7882c80b152d4 100644 --- a/src/core_plugins/console/public/src/utils.js +++ b/src/core_plugins/console/public/src/utils.js @@ -1,10 +1,13 @@ var utils = {}; -utils.textFromRequest = function (request) { +utils.textFromRequest = function (request, autoExpandScripts) { var data = request.data; if (typeof data != "string") { data = data.join("\n"); } + if (autoExpandScripts || typeof autoExpandScripts === "undefined" ) { + data = utils.expandScriptsToLiterals(data); + } return request.method + " " + request.url + "\n" + data; }; @@ -34,5 +37,16 @@ utils.reformatData = function (data, indent) { }; }; +utils.collapseLiteralStrings = function (data) { + return data.replace(/"""\n?((?:.|\n)*?)"""/g,function (match, literal) { + return JSON.stringify(literal.trim()); + }); +} + +utils.expandScriptsToLiterals = function (data) { + return data.replace(/("(?:script|inline)"\s*?:)[\s\n\r]*?(".+?\\.+?[^\\]")/g, function (match, tag, string) { + return tag + ' """\n' + JSON.parse(string).trim() + '\n"""'; + }); +} module.exports = utils; diff --git a/src/core_plugins/console/public/tests/src/editor_tests.js b/src/core_plugins/console/public/tests/src/editor_tests.js index f73d1e5038c14c..fd3e5afe5a421c 100644 --- a/src/core_plugins/console/public/tests/src/editor_tests.js +++ b/src/core_plugins/console/public/tests/src/editor_tests.js @@ -1,17 +1,19 @@ let ace = require('ace'); let es = require('../../src/es'); -let input = require('../../src/input'); +import { initializeInput } from '../../src/input'; let editor_input1 = require('raw!./editor_input1.txt'); +let utils = require('../../src/utils'); var aceRange = ace.require("ace/range"); var {test, module, ok, fail, asyncTest, deepEqual, equal, start} = QUnit; +let input; module("Editor", { setup: function () { + input = initializeInput($('#editor'), $('#editor_actions'), $('#copy_as_curl'), null); input.$el.show(); input.autocomplete._test.removeChangeListener(); - }, teardown: function () { input.$el.hide(); @@ -86,7 +88,6 @@ var multi_doc_request = { }; multi_doc_request.data = multi_doc_request.data_as_array.join("\n"); - utils_test("simple request range", simple_request.prefix, simple_request.data, function () { input.getRequestRange(function (range) { var expected = new aceRange.Range( @@ -257,6 +258,42 @@ utils_test("multi doc request data", multi_doc_request.prefix, multi_doc_request }); }); +var script_request = { + prefix: 'POST _search', + data: [ + '{', + ' "query": { "script": """', + ' some script ', + ' """}', + '}' + ].join('\n') +}; + +utils_test("script request range", script_request.prefix, script_request.data, function () { + input.getRequestRange(function (range) { + var expected = new aceRange.Range( + 0, 0, + 5, 1 + ); + compareRequest(range, expected); + start(); + }); +}); + +utils_test("simple request data", simple_request.prefix, simple_request.data, function () { + input.getRequest(function (request) { + var expected = { + method: "POST", + url: "_search", + data: [utils.collapseLiteralStrings(simple_request.data)] + }; + + compareRequest(request, expected); + start(); + }); +}); + + function multi_req_test(name, editor_input, range, expected) { utils_test("multi request select - " + name, editor_input, function () { input.getRequestsInRange(range, function (requests) { diff --git a/src/core_plugins/console/public/tests/src/integration_tests.js b/src/core_plugins/console/public/tests/src/integration_tests.js index aea330f7371d3e..eb77209a3c5e44 100644 --- a/src/core_plugins/console/public/tests/src/integration_tests.js +++ b/src/core_plugins/console/public/tests/src/integration_tests.js @@ -1,4 +1,5 @@ -let input = require('../../src/input'); +import { initializeInput } from '../../src/input'; +let input; let kb = require('../../src/kb'); let mappings = require('../../src/mappings'); let $ = require('jquery'); @@ -7,11 +8,12 @@ var {test, module, ok, fail, asyncTest, deepEqual, equal, start} = QUnit; module("Integration", { setup: function () { - $("#editor_container").show(); + input = initializeInput($('#editor'), $('#editor_actions'), $('#copy_as_curl'), null); + input.$el.show(); input.autocomplete._test.removeChangeListener(); }, teardown: function () { - $("#editor_container").hide(); + input.$el.hide(); input.autocomplete._test.addChangeListener(); } }); diff --git a/src/core_plugins/console/public/tests/src/tokenization_tests.js b/src/core_plugins/console/public/tests/src/tokenization_tests.js index 5162609d9dd9a7..c69149d0fccc4f 100644 --- a/src/core_plugins/console/public/tests/src/tokenization_tests.js +++ b/src/core_plugins/console/public/tests/src/tokenization_tests.js @@ -1,12 +1,15 @@ let ace = require('ace'); let $ = require('jquery'); -let input = require('../../src/input'); +import { initializeInput } from '../../src/input'; +let input; var token_iterator = ace.require("ace/token_iterator"); var {test, module, ok, fail, asyncTest, deepEqual, equal, start} = QUnit; + module("Tokenization", { setup: function () { + input = initializeInput($('#editor'), $('#editor_actions'), $('#copy_as_curl'), null); input.$el.show(); input.autocomplete._test.removeChangeListener(); }, @@ -282,3 +285,93 @@ states_test( ' }\n' + '}' ); + +states_test( + ["start", "json", "json", "start"], + 'POST _search\n' + + '{\n' + + ' "script": { "inline": "" }\n' + + '}' +); + +states_test( + ["start", "json", "json", "start"], + 'POST _search\n' + + '{\n' + + ' "script": ""\n' + + '}' +); + +states_test( + ["start", "json", ["json", "json"], "json", "start"], + 'POST _search\n' + + '{\n' + + ' "script": {\n' + + ' }\n' + + '}' +); + + +states_test( + ["start", "json", ["script-start", "json", "json", "json"], ["script-start", "json", "json", "json"], + ["json", "json"], "json", "start"], + 'POST _search\n' + + '{\n' + + ' "test": { "script": """\n' + + ' test script\n' + + ' """\n' + + ' }\n' + + '}' +); + +states_test( + ["start", "json", ["script-start", "json"], ["script-start", "json"], "json", "start"], + 'POST _search\n' + + '{\n' + + ' "script": """\n' + + ' test script\n' + + ' """,\n' + + '}' +); + +states_test( + ["start", "json", "json", "start"], + 'POST _search\n' + + '{\n' + + ' "script": """test script""",\n' + + '}' +); + + +states_test( + ["start", "json", ["string_literal", "json"], ["string_literal", "json"], "json", "start"], + 'POST _search\n' + + '{\n' + + ' "somthing": """\n' + + ' test script\n' + + ' """,\n' + + '}' +); + +states_test( + ["start", "json", ["string_literal", "json", "json", "json"], ["string_literal", "json", "json", "json"], + ["json", "json"], ["json", "json"], + "json", "start"], + 'POST _search\n' + + '{\n' + + ' "somthing": { "f" : """\n' + + ' test script\n' + + ' """,\n' + + ' "g": 1\n' + + ' }\n' + + '}' +); + +states_test( + ["start", "json", "json", "start"], + 'POST _search\n' + + '{\n' + + ' "something": """test script""",\n' + + '}' +); + diff --git a/src/core_plugins/console/public/tests/src/utils_string_collapsing.txt b/src/core_plugins/console/public/tests/src/utils_string_collapsing.txt new file mode 100644 index 00000000000000..4ca095590c266e --- /dev/null +++ b/src/core_plugins/console/public/tests/src/utils_string_collapsing.txt @@ -0,0 +1,26 @@ +========== +String only 1 +------------------------------------- +""" hello +to you """ +------------------------------------- +"hello\nto you" +========== +Strings in requests +------------------------------------- +{ + "f": { "somefield" : """ +test +test2 +""" }, + "g": { "script" : """second + "\"; """ }, + "h": 1, + "script": "a + 2" +} +------------------------------------- +{ + "f": { "somefield" : "test\ntest2" }, + "g": { "script" : "second + \"\\\";" }, + "h": 1, + "script": "a + 2" +} \ No newline at end of file diff --git a/src/core_plugins/console/public/tests/src/utils_string_expanding.txt b/src/core_plugins/console/public/tests/src/utils_string_expanding.txt new file mode 100644 index 00000000000000..e46b1c40fd9141 --- /dev/null +++ b/src/core_plugins/console/public/tests/src/utils_string_expanding.txt @@ -0,0 +1,21 @@ +========== +Scripts in requests +------------------------------------- +{ + "f": { "script" : { "inline": "test\ntest2" } }, + "g": { "script" : "second + \"\\\";" }, + "h": 1, + "script": "a + 2" +} +------------------------------------- +{ + "f": { "script" : { "inline": """ +test +test2 +""" } }, + "g": { "script" : """ +second + "\"; +""" }, + "h": 1, + "script": "a + 2" +} diff --git a/src/core_plugins/console/public/tests/src/utils_tests.js b/src/core_plugins/console/public/tests/src/utils_tests.js new file mode 100644 index 00000000000000..cdc1b3a16e75b6 --- /dev/null +++ b/src/core_plugins/console/public/tests/src/utils_tests.js @@ -0,0 +1,36 @@ +let _ = require('lodash'); +let utils = require('../../src/utils'); +let collapsingTests = require('raw!./utils_string_collapsing.txt'); +let expandingTests = require('raw!./utils_string_expanding.txt'); + +var {test, module, ok, fail, asyncTest, deepEqual, equal, start} = QUnit; + +module("Utils class"); + +_.each(collapsingTests.split(/^=+$/m), function (fixture) { + if (fixture.trim() == "") { + return; + } + fixture = fixture.split(/^-+$/m); + var name = fixture[0].trim(), + expanded = fixture[1].trim(), + collapsed = fixture[2].trim(); + + test("Literal collapse - " + name, function () { + deepEqual(utils.collapseLiteralStrings(expanded), collapsed); + }); +}); + +_.each(expandingTests.split(/^=+$/m), function (fixture) { + if (fixture.trim() == "") { + return; + } + fixture = fixture.split(/^-+$/m); + var name = fixture[0].trim(), + collapsed = fixture[1].trim(), + expanded = fixture[2].trim(); + + test("Literal expand - " + name, function () { + deepEqual(utils.expandScriptsToLiterals(collapsed), expanded); + }); +}); diff --git a/src/core_plugins/console/public/tests/tests.js b/src/core_plugins/console/public/tests/tests.js index 449677915683d3..76ecc6ecba542c 100644 --- a/src/core_plugins/console/public/tests/tests.js +++ b/src/core_plugins/console/public/tests/tests.js @@ -11,6 +11,7 @@ require('ui/chrome') QUnit.config.autostart = false; QUnit.init(); + require('./src/utils_tests.js'); require('./src/url_autocomplete_tests.js'); require('./src/url_params_tests.js'); require('./src/curl_parsing_tests.js');