From d9cf996269bb86c1f30787992a1fe6288859b30c Mon Sep 17 00:00:00 2001 From: mparnisari Date: Fri, 2 Nov 2018 22:16:27 -0700 Subject: [PATCH 1/9] JSON rewrite --- lib/rouge/lexers/json.rb | 56 +++++++++++++++++++++++++++++------- spec/visual/samples/json | 62 +++++++++++++++++++++++++--------------- 2 files changed, 85 insertions(+), 33 deletions(-) diff --git a/lib/rouge/lexers/json.rb b/lib/rouge/lexers/json.rb index 243be62148..63db60cfbb 100644 --- a/lib/rouge/lexers/json.rb +++ b/lib/rouge/lexers/json.rb @@ -13,18 +13,54 @@ class JSON < RegexLexer 'application/schema+json' state :root do - rule %r/\s+/m, Text::Whitespace - rule %r/"/, Str::Double, :string - rule %r/(?:true|false|null)\b/, Keyword::Constant - rule %r/[{},:\[\]]/, Punctuation - rule %r/-?(?:0|[1-9]\d*)\.\d+(?:e[+-]?\d+)?/i, Num::Float - rule %r/-?(?:0|[1-9]\d*)(?:e[+-]?\d+)?/i, Num::Integer + rule /\s+/, Text::Whitespace + rule /{/, Punctuation, :object + rule /\[/, Punctuation, :array end - state :string do - rule %r/[^\\"]+/, Str::Double - rule %r/\\./, Str::Escape - rule %r/"/, Str::Double, :pop! + state :object do + rule /\s+/, Text::Whitespace + rule /"/, Str::Double, :key + rule /:/, Punctuation, :value + rule /,/, Punctuation + rule /}/, Punctuation, :pop! + end + + state :value do + rule /"/, Str::Char, :stringvalue + mixin :constants + rule /\s*?(?=})/, Text::Whitespace, :pop! + rule /\[/, Punctuation, :array + rule /{/, Punctuation, :object + rule /}/, Punctuation, :pop! + rule /,/, Punctuation, :pop! + rule /\s+/, Text::Whitespace + end + + state :key do + rule /[^\\"]+/, Str::Double + rule /\\./, Str::Escape + rule /"/, Str::Double, :pop! + end + + state :stringvalue do + rule /[^\\"]+/, Str::Char + rule /\\./, Str::Escape + rule /"/, Str::Char, :pop! + end + + state :array do + rule /\]/, Punctuation, :pop! + rule /"/, Str::Char, :stringvalue + rule /,/, Punctuation + mixin :constants + mixin :root + end + + state :constants do + rule /(?:true|false|null)/, Keyword::Constant + rule /-?(?:0|[1-9]\d*)\.\d+(?:e[+-]?\d+)?/i, Num::Float + rule /-?(?:0|[1-9]\d*)(?:e[+-]?\d+)?/i, Num::Integer end end end diff --git a/spec/visual/samples/json b/spec/visual/samples/json index 9c847f1b1e..dbe390eabd 100644 --- a/spec/visual/samples/json +++ b/spec/visual/samples/json @@ -1,25 +1,41 @@ { - "firstName": "John", - "lastName": "Smith", - "age": 25, - "address": { - "streetAddress": "21 2nd Street", - "city": "New York", - "state": "NY", - "postalCode": "10021" - }, - "phoneNumber": [ - { - "type": "home", - "number": "212 555-1234" - }, - { - "type": "fax", - "number": "646 555-4567" - } - ], - "errors": { - "object": { "a", "b" } - }, - "emptyObject": {} + "problems": [ + {"question": "how many miles?", "answer": "6"}, + {"question": "how many kilometers?", "answer": "10"} + ], + "testing \" something \"": 1, + "firstName": "John", + "lastName": "Smith", + "age": 25, + "address": { + "streetAddress": "21 2nd Street", + "city": "New York", + "state": "NY", + "postalCode": "10021" + }, + "strings": ["one", "two", "three", "four"], + "nested1": [[1], [2], [3]], + "numbers": [1, 2, 3, 4], + "phoneNumber": [ + { + "type": "home", + "number": "212 555-1234" + }, + { + "type": "fax", + "number": "646 555-4567" + } + ], + "life_is_good": true, + "life_is_bad": 10e-4, + "errors": { + "object": { "a": 1, "b": 2, + "c": "some string" } + }, + "emptyObject": {}, + "color": { + "rgba": [0,255,0,1], + "string": "black", + "hex": "#0F0" + } } From ecc25e4f697c567a024836301b7f802469181941 Mon Sep 17 00:00:00 2001 From: mparnisari Date: Wed, 29 May 2019 21:14:50 -0700 Subject: [PATCH 2/9] JSON: add test, minor fixes --- lib/rouge/lexers/json.rb | 22 ++++++++++++++-------- spec/lexers/json_spec.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 spec/lexers/json_spec.rb diff --git a/lib/rouge/lexers/json.rb b/lib/rouge/lexers/json.rb index 63db60cfbb..97f5013329 100644 --- a/lib/rouge/lexers/json.rb +++ b/lib/rouge/lexers/json.rb @@ -20,38 +20,44 @@ class JSON < RegexLexer state :object do rule /\s+/, Text::Whitespace - rule /"/, Str::Double, :key + rule /"/, Str::Double, :name rule /:/, Punctuation, :value rule /,/, Punctuation rule /}/, Punctuation, :pop! end state :value do - rule /"/, Str::Char, :stringvalue + rule /"/, Name::Tag, :stringvalue mixin :constants - rule /\s*?(?=})/, Text::Whitespace, :pop! + rule /}/ do + token Punctuation + pop! 2 # pop both this state and the :object one below it + end rule /\[/, Punctuation, :array rule /{/, Punctuation, :object - rule /}/, Punctuation, :pop! + rule /}/ do + token Punctuation + pop! 2 # pop both this state and the :object one below it + end rule /,/, Punctuation, :pop! rule /\s+/, Text::Whitespace end - state :key do + state :name do rule /[^\\"]+/, Str::Double rule /\\./, Str::Escape rule /"/, Str::Double, :pop! end state :stringvalue do - rule /[^\\"]+/, Str::Char + rule /[^\\"]+/, Name::Tag rule /\\./, Str::Escape - rule /"/, Str::Char, :pop! + rule /"/, Name::Tag, :pop! end state :array do rule /\]/, Punctuation, :pop! - rule /"/, Str::Char, :stringvalue + rule /"/, Name::Tag, :stringvalue rule /,/, Punctuation mixin :constants mixin :root diff --git a/spec/lexers/json_spec.rb b/spec/lexers/json_spec.rb new file mode 100644 index 0000000000..a69866bac1 --- /dev/null +++ b/spec/lexers/json_spec.rb @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- # +# frozen_string_literal: true + +describe Rouge::Lexers::Jsonnet do + let(:subject) { Rouge::Lexers::JSON.new } + + describe 'guessing' do + include Support::Guessing + + it 'guesses by filename' do + assert_guess :filename => 'foo.json' + end + + it 'guesses by mimetype' do + assert_guess :mimetype => 'application/json' + assert_guess :mimetype => 'application/vnd.api+json' + assert_guess :mimetype => 'application/hal+json' + end + + it 'guesses by source' do + assert_guess :mimetype => 'application/json', :source => <<-eos + + {"name": "value"} + +eos + assert_guess :mimetype => 'application/json',:source => <<-eos + { + "statement": "SELECT (CASE\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=0 THEN NULL\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'skipped'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'success')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"allow_failure\" = 't' AND \"ci_builds\".\"status\" IN ('failed', 'canceled'))+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'success'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'pending')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'pending'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'canceled')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'success')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"allow_failure\" = 't' AND \"ci_builds\".\"status\" IN ('failed', 'canceled'))+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'canceled'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'running')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'pending')>0 THEN 'running'\n ELSE 'failed'\n END) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = $1 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = $2 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\")" + } +eos + end + end +end From 22eb1924aa658cfc2760bc6268d2fa797eb25954 Mon Sep 17 00:00:00 2001 From: mparnisari Date: Mon, 8 Jul 2019 20:13:28 -0700 Subject: [PATCH 3/9] Fix rubocop warnings "Ambiguous regexp literal." --- lib/rouge/lexers/json.rb | 54 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/rouge/lexers/json.rb b/lib/rouge/lexers/json.rb index 97f5013329..83e51e3cdf 100644 --- a/lib/rouge/lexers/json.rb +++ b/lib/rouge/lexers/json.rb @@ -13,60 +13,60 @@ class JSON < RegexLexer 'application/schema+json' state :root do - rule /\s+/, Text::Whitespace - rule /{/, Punctuation, :object - rule /\[/, Punctuation, :array + rule %r/\s+/, Text::Whitespace + rule %r/{/, Punctuation, :object + rule %r/\[/, Punctuation, :array end state :object do - rule /\s+/, Text::Whitespace - rule /"/, Str::Double, :name - rule /:/, Punctuation, :value - rule /,/, Punctuation - rule /}/, Punctuation, :pop! + rule %r/\s+/, Text::Whitespace + rule %r/"/, Str::Double, :name + rule %r/:/, Punctuation, :value + rule %r/,/, Punctuation + rule %r/}/, Punctuation, :pop! end state :value do - rule /"/, Name::Tag, :stringvalue + rule %r/"/, Name::Tag, :stringvalue mixin :constants - rule /}/ do + rule %r/}/ do token Punctuation pop! 2 # pop both this state and the :object one below it end - rule /\[/, Punctuation, :array - rule /{/, Punctuation, :object - rule /}/ do + rule %r/\[/, Punctuation, :array + rule %r/{/, Punctuation, :object + rule %r/}/ do token Punctuation pop! 2 # pop both this state and the :object one below it end - rule /,/, Punctuation, :pop! - rule /\s+/, Text::Whitespace + rule %r/,/, Punctuation, :pop! + rule %r/\s+/, Text::Whitespace end state :name do - rule /[^\\"]+/, Str::Double - rule /\\./, Str::Escape - rule /"/, Str::Double, :pop! + rule %r/[^\\"]+/, Str::Double + rule %r/\\./, Str::Escape + rule %r/"/, Str::Double, :pop! end state :stringvalue do - rule /[^\\"]+/, Name::Tag - rule /\\./, Str::Escape - rule /"/, Name::Tag, :pop! + rule %r/[^\\"]+/, Name::Tag + rule %r/\\./, Str::Escape + rule %r/"/, Name::Tag, :pop! end state :array do - rule /\]/, Punctuation, :pop! - rule /"/, Name::Tag, :stringvalue - rule /,/, Punctuation + rule %r/\]/, Punctuation, :pop! + rule %r/"/, Name::Tag, :stringvalue + rule %r/,/, Punctuation mixin :constants mixin :root end state :constants do - rule /(?:true|false|null)/, Keyword::Constant - rule /-?(?:0|[1-9]\d*)\.\d+(?:e[+-]?\d+)?/i, Num::Float - rule /-?(?:0|[1-9]\d*)(?:e[+-]?\d+)?/i, Num::Integer + rule %r/(?:true|false|null)/, Keyword::Constant + rule %r/-?(?:0|[1-9]\d*)\.\d+(?:e[+-]?\d+)?/i, Num::Float + rule %r/-?(?:0|[1-9]\d*)(?:e[+-]?\d+)?/i, Num::Integer end end end From fc8223caca8e1af2311bf3226f2a0b58181235da Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Wed, 10 Jul 2019 16:25:13 +0900 Subject: [PATCH 4/9] Change object tokens, support bare key-values This commit makes several changes to the proposed lexer. First, it changes the tokens used in JavaScript objects. It was proposed that keys be tokenised as `Str::Double` and that string values be tokenised as `Name::Tag`. The token `Name::Label` seems a more appropriate token for keys while `Str::Double` should be used for string values. Second, it remoeves the tokenisation of escape sequences inside object keys. While this is correct insofar as the keys are merely strings, it fits awkwardly with the tokenisation of keys with a non-string token. This commit tokenises all characters within the key as `Name::Label`. Third, it adds support for 'bare' key-value pairs, that is text of the form : . These 'bare' key-value pairs are not tokenised the same way as they would be within objects. Rather, keys are tokenised as ordinary strings. This preserves backwards compatability with how the JSON lexer previously worked. --- lib/rouge/lexers/json.rb | 48 +++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/rouge/lexers/json.rb b/lib/rouge/lexers/json.rb index 83e51e3cdf..155dbd8723 100644 --- a/lib/rouge/lexers/json.rb +++ b/lib/rouge/lexers/json.rb @@ -12,58 +12,66 @@ class JSON < RegexLexer 'application/hal+json', 'application/problem+json', 'application/schema+json' - state :root do + state :whitespace do rule %r/\s+/, Text::Whitespace + end + + state :root do + mixin :whitespace rule %r/{/, Punctuation, :object rule %r/\[/, Punctuation, :array + + rule(%r//) { push :value } end state :object do - rule %r/\s+/, Text::Whitespace - rule %r/"/, Str::Double, :name + mixin :whitespace + rule %r/"/, Name::Label, :name rule %r/:/, Punctuation, :value rule %r/,/, Punctuation rule %r/}/, Punctuation, :pop! end - + state :value do - rule %r/"/, Name::Tag, :stringvalue + mixin :whitespace + rule %r/"/, Str::Double, :string_value mixin :constants - rule %r/}/ do - token Punctuation - pop! 2 # pop both this state and the :object one below it - end rule %r/\[/, Punctuation, :array rule %r/{/, Punctuation, :object rule %r/}/ do - token Punctuation - pop! 2 # pop both this state and the :object one below it + if stack[-2].name == :object + token Punctuation + pop! 2 # pop both this state and the :object one below it + else + token Error + pop! + end end rule %r/,/, Punctuation, :pop! - rule %r/\s+/, Text::Whitespace + rule %r/:/, Punctuation end state :name do - rule %r/[^\\"]+/, Str::Double - rule %r/\\./, Str::Escape - rule %r/"/, Str::Double, :pop! + rule %r/[^\\"]+/, Name::Label + rule %r/\\./, Name::Label + rule %r/"/, Name::Label, :pop! end - state :stringvalue do - rule %r/[^\\"]+/, Name::Tag + state :string_value do + rule %r/[^\\"]+/, Str::Double rule %r/\\./, Str::Escape - rule %r/"/, Name::Tag, :pop! + rule %r/"/, Str::Double, :pop! end state :array do rule %r/\]/, Punctuation, :pop! - rule %r/"/, Name::Tag, :stringvalue + rule %r/"/, Str::Double, :string_value rule %r/,/, Punctuation mixin :constants mixin :root end - state :constants do + state :constants do rule %r/(?:true|false|null)/, Keyword::Constant rule %r/-?(?:0|[1-9]\d*)\.\d+(?:e[+-]?\d+)?/i, Num::Float rule %r/-?(?:0|[1-9]\d*)(?:e[+-]?\d+)?/i, Num::Integer From abe2d922e5530d239b98f34fd76bd1fc7d4b08fe Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Wed, 10 Jul 2019 16:38:38 +0900 Subject: [PATCH 5/9] Improve bare key-value pair lexing This commit provides support for tokenising bare keys as `Name::Label` without introducing backtracking for non-key strings. --- lib/rouge/lexers/json.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/rouge/lexers/json.rb b/lib/rouge/lexers/json.rb index 155dbd8723..1aac9e3cc7 100644 --- a/lib/rouge/lexers/json.rb +++ b/lib/rouge/lexers/json.rb @@ -20,6 +20,15 @@ class JSON < RegexLexer mixin :whitespace rule %r/{/, Punctuation, :object rule %r/\[/, Punctuation, :array + + rule %r/("[^"]*")(:?)/ do |m| + if m[2] == ":" + groups Name::Label, Punctuation + push :value + else + token Str::Double + end + end rule(%r//) { push :value } end From 5a6295ba968a16665b319d32771044268ee952bb Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Fri, 12 Jul 2019 09:52:45 +0900 Subject: [PATCH 6/9] Simplify rules --- lib/rouge/lexers/json.rb | 49 ++++++++++++---------------------------- spec/visual/samples/json | 7 ++++++ 2 files changed, 21 insertions(+), 35 deletions(-) diff --git a/lib/rouge/lexers/json.rb b/lib/rouge/lexers/json.rb index 1aac9e3cc7..2b7ecf2ab1 100644 --- a/lib/rouge/lexers/json.rb +++ b/lib/rouge/lexers/json.rb @@ -21,49 +21,30 @@ class JSON < RegexLexer rule %r/{/, Punctuation, :object rule %r/\[/, Punctuation, :array - rule %r/("[^"]*")(:?)/ do |m| - if m[2] == ":" - groups Name::Label, Punctuation - push :value - else - token Str::Double - end - end - - rule(%r//) { push :value } + mixin :name + mixin :value end state :object do mixin :whitespace - rule %r/"/, Name::Label, :name - rule %r/:/, Punctuation, :value - rule %r/,/, Punctuation + mixin :name + mixin :value rule %r/}/, Punctuation, :pop! + rule %r/,/, Punctuation end - + + state :name do + rule %r/("(?:\"|[^"\n])*?")(:)/ do + groups Name::Label, Punctuation + end + end + state :value do mixin :whitespace - rule %r/"/, Str::Double, :string_value mixin :constants + rule %r/"/, Str::Double, :string_value rule %r/\[/, Punctuation, :array rule %r/{/, Punctuation, :object - rule %r/}/ do - if stack[-2].name == :object - token Punctuation - pop! 2 # pop both this state and the :object one below it - else - token Error - pop! - end - end - rule %r/,/, Punctuation, :pop! - rule %r/:/, Punctuation - end - - state :name do - rule %r/[^\\"]+/, Name::Label - rule %r/\\./, Name::Label - rule %r/"/, Name::Label, :pop! end state :string_value do @@ -73,11 +54,9 @@ class JSON < RegexLexer end state :array do + mixin :value rule %r/\]/, Punctuation, :pop! - rule %r/"/, Str::Double, :string_value rule %r/,/, Punctuation - mixin :constants - mixin :root end state :constants do diff --git a/spec/visual/samples/json b/spec/visual/samples/json index dbe390eabd..6a6d9901c5 100644 --- a/spec/visual/samples/json +++ b/spec/visual/samples/json @@ -39,3 +39,10 @@ "hex": "#0F0" } } + +"this": { "is": "not syntactically correct JSON but is here for backwards compatibility" } +true +100 +null +"a": "test" +"string" From 6b3de9a3395c99785e976bba7eb6d916dc899d02 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Fri, 12 Jul 2019 18:19:01 +0900 Subject: [PATCH 7/9] Update HOCON lexer to work with new JSON lexer --- lib/rouge/lexers/hocon.rb | 56 +++++++++++++++++++++++++--------- lib/rouge/lexers/json.rb | 10 +++--- spec/lexers/javascript_spec.rb | 7 ----- spec/lexers/json_spec.rb | 13 ++++---- spec/visual/samples/json | 2 +- 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/lib/rouge/lexers/hocon.rb b/lib/rouge/lexers/hocon.rb index 8778a34f7a..455067fa63 100644 --- a/lib/rouge/lexers/hocon.rb +++ b/lib/rouge/lexers/hocon.rb @@ -11,33 +11,59 @@ class HOCON < JSON tag 'hocon' filenames '*.hocon' - prepend :root do + state :comments do # Comments rule %r(//.*?$), Comment::Single rule %r(#.*?$), Comment::Single + end + + prepend :root do + mixin :comments + end + + prepend :object do + # Keywords + rule %r/\b(?:include|url|file|classpath)\b/, Keyword + end + + state :name do + rule %r/("(?:\"|[^"\n])*?")(\s*)([:=]|(?={))/ do + groups Name::Label, Text::Whitespace, Punctuation + end + + rule %r/([-\w.]+)(\s*)([:=]|(?={))/ do + groups Name::Label, Text::Whitespace, Punctuation + end + end + + state :value do + mixin :comments + + rule %r/\n/, Text::Whitespace + rule %r/\s+/, Text::Whitespace + + mixin :constants # Interpolation rule %r/[$][{][?]?/, Literal::String::Interpol, :interpolation # Strings rule %r/"""/, Literal::String::Double, :multiline_string + rule %r/"/, Str::Double, :string - # Keywords - rule %r/\b(?:include|url|file|classpath)\b/, Keyword + rule %r/\[/, Punctuation, :array + rule %r/{/, Punctuation, :object # Symbols (only those not handled by JSON) rule %r/[()=]/, Punctuation - # Keys - rule %r/([\w\-\.]+? *)([{:=]|\+=)/ do - groups Name::Attribute, Punctuation::Indicator - end - - # Numbers (handle the case where we have multiple periods, ie. IP addresses) - rule %r/\d+\.(\d+\.?){3,}/, Literal # - # Values - rule %r/[^\$\"{}\[\]:=,\+#`\^\?!@\*&]+?/, Literal + rule %r/[^$"{}\[\]:=,\+#`^?!@*&]+?/, Literal + end + + state :interpolation do + rule %r/[\w\-\.]+?/, Name::Variable + rule %r/}/, Literal::String::Interpol, :pop! end prepend :string do @@ -51,9 +77,9 @@ class HOCON < JSON rule %r/"""/, Literal::String::Double, :pop! end - state :interpolation do - rule %r/[\w\-\.]+?/, Name::Variable - rule %r/}/, Literal::String::Interpol, :pop! + prepend :constants do + # Numbers (handle the case where we have multiple periods, ie. IP addresses) + rule %r/\d+\.(\d+\.?){3,}/, Literal # end end end diff --git a/lib/rouge/lexers/json.rb b/lib/rouge/lexers/json.rb index 2b7ecf2ab1..9eb6d2a785 100644 --- a/lib/rouge/lexers/json.rb +++ b/lib/rouge/lexers/json.rb @@ -20,7 +20,7 @@ class JSON < RegexLexer mixin :whitespace rule %r/{/, Punctuation, :object rule %r/\[/, Punctuation, :array - + mixin :name mixin :value end @@ -34,20 +34,20 @@ class JSON < RegexLexer end state :name do - rule %r/("(?:\"|[^"\n])*?")(:)/ do - groups Name::Label, Punctuation + rule %r/("(?:\"|[^"\n])*?")(\s*)(:)/ do + groups Name::Label, Text::Whitespace, Punctuation end end state :value do mixin :whitespace mixin :constants - rule %r/"/, Str::Double, :string_value + rule %r/"/, Str::Double, :string rule %r/\[/, Punctuation, :array rule %r/{/, Punctuation, :object end - state :string_value do + state :string do rule %r/[^\\"]+/, Str::Double rule %r/\\./, Str::Escape rule %r/"/, Str::Double, :pop! diff --git a/spec/lexers/javascript_spec.rb b/spec/lexers/javascript_spec.rb index 66085a7094..db059a8024 100644 --- a/spec/lexers/javascript_spec.rb +++ b/spec/lexers/javascript_spec.rb @@ -18,17 +18,10 @@ it 'guesses by filename' do assert_guess :filename => 'foo.js' - assert_guess Rouge::Lexers::JSON, :filename => 'foo.json' - assert_guess Rouge::Lexers::JSON, :filename => 'Pipfile.lock' end it 'guesses by mimetype' do assert_guess :mimetype => 'text/javascript' - assert_guess Rouge::Lexers::JSON, :mimetype => 'application/json' - assert_guess Rouge::Lexers::JSON, :mimetype => 'application/vnd.api+json' - assert_guess Rouge::Lexers::JSON, :mimetype => 'application/hal+json' - assert_guess Rouge::Lexers::JSON, :mimetype => 'application/problem+json' - assert_guess Rouge::Lexers::JSON, :mimetype => 'application/schema+json' end it 'guesses by source' do diff --git a/spec/lexers/json_spec.rb b/spec/lexers/json_spec.rb index a69866bac1..cb6ce64315 100644 --- a/spec/lexers/json_spec.rb +++ b/spec/lexers/json_spec.rb @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # frozen_string_literal: true -describe Rouge::Lexers::Jsonnet do +describe Rouge::Lexers::JSON do let(:subject) { Rouge::Lexers::JSON.new } describe 'guessing' do @@ -9,25 +9,24 @@ it 'guesses by filename' do assert_guess :filename => 'foo.json' + assert_guess :filename => 'Pipfile.lock' end it 'guesses by mimetype' do assert_guess :mimetype => 'application/json' assert_guess :mimetype => 'application/vnd.api+json' assert_guess :mimetype => 'application/hal+json' + assert_guess :mimetype => 'application/problem+json' + assert_guess :mimetype => 'application/schema+json' end it 'guesses by source' do + assert_guess :mimetype => 'application/json', :source => '{"name": "value"}' assert_guess :mimetype => 'application/json', :source => <<-eos - - {"name": "value"} - -eos - assert_guess :mimetype => 'application/json',:source => <<-eos { "statement": "SELECT (CASE\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=0 THEN NULL\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'skipped'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'success')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"allow_failure\" = 't' AND \"ci_builds\".\"status\" IN ('failed', 'canceled'))+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'success'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'pending')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'pending'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'canceled')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'success')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"allow_failure\" = 't' AND \"ci_builds\".\"status\" IN ('failed', 'canceled'))+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'canceled'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'running')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'pending')>0 THEN 'running'\n ELSE 'failed'\n END) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = $1 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = $2 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\")" } -eos + eos end end end diff --git a/spec/visual/samples/json b/spec/visual/samples/json index 6a6d9901c5..3cb63a4ca5 100644 --- a/spec/visual/samples/json +++ b/spec/visual/samples/json @@ -29,7 +29,7 @@ "life_is_good": true, "life_is_bad": 10e-4, "errors": { - "object": { "a": 1, "b": 2, + "object": { "a": 1, "b": 2, "c": "some string" } }, "emptyObject": {}, From 578cb56ae20e978b3959d5a926434d761d8eedb9 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sat, 13 Jul 2019 00:34:01 +0900 Subject: [PATCH 8/9] Fix typo in HOCON lexer --- lib/rouge/lexers/hocon.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rouge/lexers/hocon.rb b/lib/rouge/lexers/hocon.rb index 455067fa63..881a969a00 100644 --- a/lib/rouge/lexers/hocon.rb +++ b/lib/rouge/lexers/hocon.rb @@ -79,7 +79,7 @@ class HOCON < JSON prepend :constants do # Numbers (handle the case where we have multiple periods, ie. IP addresses) - rule %r/\d+\.(\d+\.?){3,}/, Literal # + rule %r/\d+\.(\d+\.?){3,}/, Literal end end end From 94a024d62a157b32e98f07ff51f62721295df9b4 Mon Sep 17 00:00:00 2001 From: Michael Camilleri Date: Sat, 20 Jul 2019 04:25:19 +0900 Subject: [PATCH 9/9] Move pathological case to visual sample --- spec/lexers/json_spec.rb | 5 --- spec/visual/samples/json | 94 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/spec/lexers/json_spec.rb b/spec/lexers/json_spec.rb index cb6ce64315..d5d57788de 100644 --- a/spec/lexers/json_spec.rb +++ b/spec/lexers/json_spec.rb @@ -22,11 +22,6 @@ it 'guesses by source' do assert_guess :mimetype => 'application/json', :source => '{"name": "value"}' - assert_guess :mimetype => 'application/json', :source => <<-eos - { - "statement": "SELECT (CASE\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=0 THEN NULL\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'skipped'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'success')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"allow_failure\" = 't' AND \"ci_builds\".\"status\" IN ('failed', 'canceled'))+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'success'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'pending')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'pending'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'canceled')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'success')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"allow_failure\" = 't' AND \"ci_builds\".\"status\" IN ('failed', 'canceled'))+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'skipped') THEN 'canceled'\n WHEN (SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'running')+(SELECT count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND \"ci_builds\".\"status\" = 'pending')>0 THEN 'running'\n ELSE 'failed'\n END) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = $1 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = $2 GROUP BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\")" - } - eos end end end diff --git a/spec/visual/samples/json b/spec/visual/samples/json index 3cb63a4ca5..8ab0701731 100644 --- a/spec/visual/samples/json +++ b/spec/visual/samples/json @@ -46,3 +46,97 @@ true null "a": "test" "string" + +{ "statement": "SELECT (CASE WHEN (SELECT count(*) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN + (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=0 THEN + NULL WHEN (SELECT count(*) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN + (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT + count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = + 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) + FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP + BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'skipped') THEN 'skipped' WHEN + (SELECT count(*) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN + (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT + count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = + 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) + FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP + BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'success')+(SELECT count(*) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND + \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"allow_failure\" = 't' AND + \"ci_builds\".\"status\" IN ('failed', 'canceled'))+(SELECT + count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = + 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) + FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP + BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'skipped') THEN 'success' WHEN + (SELECT count(*) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN + (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT + count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = + 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) + FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP + BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'pending')+(SELECT count(*) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND + \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'skipped') THEN 'pending' WHEN + (SELECT count(*) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN + (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\"))=(SELECT + count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = + 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) + FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP + BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'canceled')+(SELECT count(*) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND + \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'success')+(SELECT count(*) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND + \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"allow_failure\" = 't' AND + \"ci_builds\".\"status\" IN ('failed', 'canceled'))+(SELECT + count(*) FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = + 77 AND \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) + FROM \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP + BY \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'skipped') THEN 'canceled' WHEN + (SELECT count(*) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 AND \"ci_builds\".\"id\" IN + (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'running')+(SELECT count(*) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 AND + \"ci_builds\".\"id\" IN (SELECT max(\"ci_builds\".id) FROM + \"ci_builds\" WHERE \"ci_builds\".\"commit_id\" = 77 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\") AND + \"ci_builds\".\"status\" = 'pending')>0 THEN 'running' ELSE + 'failed' END) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = $1 AND \"ci_builds\".\"id\" IN + (SELECT max(\"ci_builds\".id) FROM \"ci_builds\" WHERE + \"ci_builds\".\"commit_id\" = $2 GROUP BY + \"ci_builds\".\"name\", \"ci_builds\".\"commit_id\")" }