hocon 0.0.7 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +4 -2
- data/lib/hocon.rb +2 -0
- data/lib/hocon/config.rb +1010 -0
- data/lib/hocon/config_error.rb +32 -2
- data/lib/hocon/config_factory.rb +46 -0
- data/lib/hocon/config_include_context.rb +49 -0
- data/lib/hocon/config_includer_file.rb +27 -0
- data/lib/hocon/config_list.rb +49 -0
- data/lib/hocon/config_mergeable.rb +74 -0
- data/lib/hocon/config_object.rb +144 -1
- data/lib/hocon/config_parse_options.rb +33 -9
- data/lib/hocon/config_parseable.rb +51 -0
- data/lib/hocon/config_render_options.rb +4 -2
- data/lib/hocon/config_resolve_options.rb +31 -0
- data/lib/hocon/config_syntax.rb +5 -2
- data/lib/hocon/config_util.rb +73 -0
- data/lib/hocon/config_value.rb +122 -0
- data/lib/hocon/config_value_factory.rb +66 -2
- data/lib/hocon/config_value_type.rb +5 -2
- data/lib/hocon/impl.rb +2 -0
- data/lib/hocon/impl/abstract_config_node.rb +29 -0
- data/lib/hocon/impl/abstract_config_node_value.rb +11 -0
- data/lib/hocon/impl/abstract_config_object.rb +148 -42
- data/lib/hocon/impl/abstract_config_value.rb +251 -11
- data/lib/hocon/impl/array_iterator.rb +19 -0
- data/lib/hocon/impl/config_boolean.rb +7 -1
- data/lib/hocon/impl/config_concatenation.rb +177 -28
- data/lib/hocon/impl/config_delayed_merge.rb +329 -0
- data/lib/hocon/impl/config_delayed_merge_object.rb +274 -0
- data/lib/hocon/impl/config_document_parser.rb +647 -0
- data/lib/hocon/impl/config_double.rb +44 -0
- data/lib/hocon/impl/config_impl.rb +143 -19
- data/lib/hocon/impl/config_impl_util.rb +18 -0
- data/lib/hocon/impl/config_include_kind.rb +10 -0
- data/lib/hocon/impl/config_int.rb +13 -1
- data/lib/hocon/impl/config_node_array.rb +11 -0
- data/lib/hocon/impl/config_node_comment.rb +19 -0
- data/lib/hocon/impl/config_node_complex_value.rb +54 -0
- data/lib/hocon/impl/config_node_concatenation.rb +11 -0
- data/lib/hocon/impl/config_node_field.rb +81 -0
- data/lib/hocon/impl/config_node_include.rb +33 -0
- data/lib/hocon/impl/config_node_object.rb +276 -0
- data/lib/hocon/impl/config_node_path.rb +48 -0
- data/lib/hocon/impl/config_node_root.rb +60 -0
- data/lib/hocon/impl/config_node_simple_value.rb +42 -0
- data/lib/hocon/impl/config_node_single_token.rb +17 -0
- data/lib/hocon/impl/config_null.rb +15 -7
- data/lib/hocon/impl/config_number.rb +43 -4
- data/lib/hocon/impl/config_parser.rb +403 -0
- data/lib/hocon/impl/config_reference.rb +142 -0
- data/lib/hocon/impl/config_string.rb +55 -7
- data/lib/hocon/impl/container.rb +29 -0
- data/lib/hocon/impl/default_transformer.rb +24 -15
- data/lib/hocon/impl/from_map_mode.rb +3 -1
- data/lib/hocon/impl/full_includer.rb +2 -0
- data/lib/hocon/impl/memo_key.rb +42 -0
- data/lib/hocon/impl/mergeable_value.rb +8 -0
- data/lib/hocon/impl/origin_type.rb +8 -2
- data/lib/hocon/impl/parseable.rb +455 -91
- data/lib/hocon/impl/path.rb +181 -59
- data/lib/hocon/impl/path_builder.rb +24 -3
- data/lib/hocon/impl/path_parser.rb +280 -0
- data/lib/hocon/impl/replaceable_merge_stack.rb +22 -0
- data/lib/hocon/impl/resolve_context.rb +254 -0
- data/lib/hocon/impl/resolve_memos.rb +21 -0
- data/lib/hocon/impl/resolve_result.rb +39 -0
- data/lib/hocon/impl/resolve_source.rb +354 -0
- data/lib/hocon/impl/resolve_status.rb +3 -1
- data/lib/hocon/impl/simple_config.rb +264 -10
- data/lib/hocon/impl/simple_config_document.rb +48 -0
- data/lib/hocon/impl/simple_config_list.rb +282 -8
- data/lib/hocon/impl/simple_config_object.rb +424 -88
- data/lib/hocon/impl/simple_config_origin.rb +263 -71
- data/lib/hocon/impl/simple_include_context.rb +31 -1
- data/lib/hocon/impl/simple_includer.rb +196 -1
- data/lib/hocon/impl/substitution_expression.rb +38 -0
- data/lib/hocon/impl/token.rb +17 -4
- data/lib/hocon/impl/token_type.rb +6 -2
- data/lib/hocon/impl/tokenizer.rb +339 -109
- data/lib/hocon/impl/tokens.rb +330 -79
- data/lib/hocon/impl/unmergeable.rb +14 -1
- data/lib/hocon/impl/unsupported_operation_error.rb +6 -0
- data/lib/hocon/impl/url.rb +37 -0
- data/lib/hocon/parser.rb +7 -0
- data/lib/hocon/parser/config_document.rb +92 -0
- data/lib/hocon/parser/config_document_factory.rb +36 -0
- data/lib/hocon/parser/config_node.rb +30 -0
- metadata +67 -43
- data/lib/hocon/impl/config_float.rb +0 -13
- data/lib/hocon/impl/parser.rb +0 -977
- data/lib/hocon/impl/properties_parser.rb +0 -83
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'hocon/impl'
|
4
|
+
require 'hocon/impl/config_node_array'
|
5
|
+
require 'hocon/impl/config_node_complex_value'
|
6
|
+
require 'hocon/impl/config_node_object'
|
7
|
+
|
8
|
+
class Hocon::Impl::ConfigNodeRoot
|
9
|
+
include Hocon::Impl::ConfigNodeComplexValue
|
10
|
+
def initialize(children, origin)
|
11
|
+
super(children)
|
12
|
+
@origin = origin
|
13
|
+
end
|
14
|
+
|
15
|
+
def new_node(nodes)
|
16
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError, "Tried to indent the root object"
|
17
|
+
end
|
18
|
+
|
19
|
+
def value
|
20
|
+
@children.each do |node|
|
21
|
+
if node.is_a?(Hocon::Impl::ConfigNodeComplexValue)
|
22
|
+
return node
|
23
|
+
end
|
24
|
+
end
|
25
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError, "ConfigNodeRoot did not contain a value"
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_value(desired_path, value, flavor)
|
29
|
+
children_copy = @children.clone
|
30
|
+
children_copy.each_with_index do |node, index|
|
31
|
+
if node.is_a?(Hocon::Impl::ConfigNodeComplexValue)
|
32
|
+
if node.is_a?(Hocon::Impl::ConfigNodeArray)
|
33
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError, "The ConfigDocument had an array at the root level, and values cannot be modified inside an array."
|
34
|
+
elsif node.is_a?(Hocon::Impl::ConfigNodeObject)
|
35
|
+
if value.nil?
|
36
|
+
children_copy[index] = node.remove_value_on_path(desired_path, flavor)
|
37
|
+
else
|
38
|
+
children_copy[index] = node.set_value_on_path(desired_path, value, flavor)
|
39
|
+
end
|
40
|
+
return self.class.new(children_copy, @origin)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError, "ConfigNodeRoot did not contain a value"
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_value(desired_path)
|
48
|
+
path = Hocon::Impl::PathParser.parse_path(desired_path)
|
49
|
+
@children.each do |node|
|
50
|
+
if node.is_a?(Hocon::Impl::ConfigNodeComplexValue)
|
51
|
+
if node.is_a?(Hocon::Impl::ConfigNodeArray)
|
52
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError, "The ConfigDocument had an array at the root level, and values cannot be modified inside an array."
|
53
|
+
elsif node.is_a?(Hocon::Impl::ConfigNodeObject)
|
54
|
+
return node.has_value(path)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError, "ConfigNodeRoot did not contain a value"
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'hocon/config_error'
|
4
|
+
require 'hocon/impl'
|
5
|
+
require 'hocon/impl/abstract_config_node_value'
|
6
|
+
require 'hocon/impl/array_iterator'
|
7
|
+
require 'hocon/impl/config_reference'
|
8
|
+
require 'hocon/impl/config_string'
|
9
|
+
require 'hocon/impl/path_parser'
|
10
|
+
require 'hocon/impl/substitution_expression'
|
11
|
+
require 'hocon/impl/tokens'
|
12
|
+
|
13
|
+
class Hocon::Impl::ConfigNodeSimpleValue
|
14
|
+
include Hocon::Impl::AbstractConfigNodeValue
|
15
|
+
|
16
|
+
Tokens = Hocon::Impl::Tokens
|
17
|
+
|
18
|
+
def initialize(value)
|
19
|
+
@token = value
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :token
|
23
|
+
|
24
|
+
def tokens
|
25
|
+
[@token]
|
26
|
+
end
|
27
|
+
|
28
|
+
def value
|
29
|
+
if Tokens.value?(@token)
|
30
|
+
return Tokens.value(@token)
|
31
|
+
elsif Tokens.unquoted_text?(@token)
|
32
|
+
return Hocon::Impl::ConfigString::Unquoted.new(@token.origin, Tokens.unquoted_text(@token))
|
33
|
+
elsif Tokens.substitution?(@token)
|
34
|
+
expression = Tokens.get_substitution_path_expression(@token)
|
35
|
+
path = Hocon::Impl::PathParser.parse_path_expression(Hocon::Impl::ArrayIterator.new(expression), @token.origin)
|
36
|
+
optional = Tokens.get_substitution_optional(@token)
|
37
|
+
|
38
|
+
return Hocon::Impl::ConfigReference.new(@token.origin, Hocon::Impl::SubstitutionExpression.new(path, optional))
|
39
|
+
end
|
40
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError, 'ConfigNodeSimpleValue did not contain a valid value token'
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'hocon/impl'
|
4
|
+
require 'hocon/impl/abstract_config_node'
|
5
|
+
|
6
|
+
class Hocon::Impl::ConfigNodeSingleToken
|
7
|
+
include Hocon::Impl::AbstractConfigNode
|
8
|
+
def initialize(t)
|
9
|
+
@token = t
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :token
|
13
|
+
|
14
|
+
def tokens
|
15
|
+
[@token]
|
16
|
+
end
|
17
|
+
end
|
@@ -1,9 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'hocon/impl'
|
2
4
|
require 'hocon/config_value_type'
|
3
5
|
|
4
|
-
class Hocon::Impl::ConfigNull
|
6
|
+
class Hocon::Impl::ConfigNull
|
7
|
+
include Hocon::Impl::AbstractConfigValue
|
8
|
+
|
9
|
+
def initialize(origin)
|
10
|
+
super(origin)
|
11
|
+
end
|
12
|
+
|
5
13
|
def value_type
|
6
|
-
Hocon::
|
14
|
+
Hocon::ConfigValueType::NULL
|
7
15
|
end
|
8
16
|
|
9
17
|
def unwrapped
|
@@ -14,12 +22,12 @@ class Hocon::Impl::ConfigNull < Hocon::Impl::AbstractConfigValue
|
|
14
22
|
"null"
|
15
23
|
end
|
16
24
|
|
17
|
-
def
|
18
|
-
sb
|
25
|
+
def render_value_to_sb(sb, indent, at_root, options)
|
26
|
+
sb << "null"
|
19
27
|
end
|
20
28
|
|
21
|
-
def
|
22
|
-
|
29
|
+
def new_copy(origin)
|
30
|
+
self.class.new(origin)
|
23
31
|
end
|
24
32
|
|
25
|
-
end
|
33
|
+
end
|
@@ -1,18 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require 'hocon/impl'
|
2
4
|
require 'hocon/impl/abstract_config_value'
|
3
5
|
|
4
|
-
class Hocon::Impl::ConfigNumber
|
6
|
+
class Hocon::Impl::ConfigNumber
|
7
|
+
include Hocon::Impl::AbstractConfigValue
|
5
8
|
## sigh... requiring these subclasses before this class
|
6
9
|
## is declared would cause an error. Thanks, ruby.
|
7
10
|
require 'hocon/impl/config_int'
|
8
|
-
require 'hocon/impl/
|
11
|
+
require 'hocon/impl/config_double'
|
9
12
|
|
10
13
|
def self.new_number(origin, number, original_text)
|
11
14
|
as_int = number.to_i
|
12
15
|
if as_int == number
|
13
16
|
Hocon::Impl::ConfigInt.new(origin, as_int, original_text)
|
14
17
|
else
|
15
|
-
Hocon::Impl::
|
18
|
+
Hocon::Impl::ConfigDouble.new(origin, number, original_text)
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
@@ -20,8 +23,44 @@ class Hocon::Impl::ConfigNumber < Hocon::Impl::AbstractConfigValue
|
|
20
23
|
super(origin)
|
21
24
|
@original_text = original_text
|
22
25
|
end
|
26
|
+
attr_reader :original_text
|
23
27
|
|
24
28
|
def transform_to_string
|
25
29
|
@original_text
|
26
30
|
end
|
27
|
-
|
31
|
+
|
32
|
+
def int_value_range_checked(path)
|
33
|
+
# We don't need to do any range checking here due to the way Ruby handles
|
34
|
+
# integers (doesn't have the 32-bit/64-bit distinction that Java does).
|
35
|
+
long_value
|
36
|
+
end
|
37
|
+
|
38
|
+
def long_value
|
39
|
+
raise "long_value needs to be overriden by sub-classes of #{Hocon::Impl::ConfigNumber}, in this case #{self.class}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def can_equal(other)
|
43
|
+
other.is_a?(Hocon::Impl::ConfigNumber)
|
44
|
+
end
|
45
|
+
|
46
|
+
def ==(other)
|
47
|
+
if other.is_a?(Hocon::Impl::ConfigNumber) && can_equal(other)
|
48
|
+
@value == other.value
|
49
|
+
else
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def hash
|
55
|
+
# This hash function makes it so that a ConfigNumber with a 3.0
|
56
|
+
# and one with a 3 will return the hash code
|
57
|
+
to_int = @value.round
|
58
|
+
|
59
|
+
# If the value is an integer or a floating point equal to an integer
|
60
|
+
if to_int == @value
|
61
|
+
to_int.hash
|
62
|
+
else
|
63
|
+
@value.hash
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,403 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
require 'hocon/impl'
|
5
|
+
require 'hocon/impl/path_builder'
|
6
|
+
require 'hocon/config_syntax'
|
7
|
+
require 'hocon/impl/config_string'
|
8
|
+
require 'hocon/impl/config_concatenation'
|
9
|
+
require 'hocon/config_error'
|
10
|
+
require 'hocon/impl/simple_config_list'
|
11
|
+
require 'hocon/impl/simple_config_object'
|
12
|
+
require 'hocon/impl/path'
|
13
|
+
require 'hocon/impl/url'
|
14
|
+
require 'hocon/impl/config_reference'
|
15
|
+
require 'hocon/impl/substitution_expression'
|
16
|
+
require 'hocon/impl/config_node_simple_value'
|
17
|
+
require 'hocon/impl/config_node_object'
|
18
|
+
require 'hocon/impl/config_node_array'
|
19
|
+
require 'hocon/impl/config_node_concatenation'
|
20
|
+
require 'hocon/impl/config_include_kind'
|
21
|
+
|
22
|
+
class Hocon::Impl::ConfigParser
|
23
|
+
|
24
|
+
ConfigSyntax = Hocon::ConfigSyntax
|
25
|
+
ConfigConcatenation = Hocon::Impl::ConfigConcatenation
|
26
|
+
ConfigReference = Hocon::Impl::ConfigReference
|
27
|
+
ConfigParseError = Hocon::ConfigError::ConfigParseError
|
28
|
+
ConfigBugOrBrokenError = Hocon::ConfigError::ConfigBugOrBrokenError
|
29
|
+
SimpleConfigObject = Hocon::Impl::SimpleConfigObject
|
30
|
+
SimpleConfigList = Hocon::Impl::SimpleConfigList
|
31
|
+
Path = Hocon::Impl::Path
|
32
|
+
ConfigIncludeKind = Hocon::Impl::ConfigIncludeKind
|
33
|
+
ConfigNodeInclude = Hocon::Impl::ConfigNodeInclude
|
34
|
+
ConfigNodeComment = Hocon::Impl::ConfigNodeComment
|
35
|
+
ConfigNodeSingleToken = Hocon::Impl::ConfigNodeSingleToken
|
36
|
+
Tokens = Hocon::Impl::Tokens
|
37
|
+
|
38
|
+
def self.parse(document, origin, options, include_context)
|
39
|
+
context = Hocon::Impl::ConfigParser::ParseContext.new(
|
40
|
+
options.syntax, origin, document,
|
41
|
+
Hocon::Impl::SimpleIncluder.make_full(options.includer),
|
42
|
+
include_context)
|
43
|
+
context.parse
|
44
|
+
end
|
45
|
+
|
46
|
+
class ParseContext
|
47
|
+
def initialize(flavor, origin, document, includer, include_context)
|
48
|
+
@line_number = 1
|
49
|
+
@document = document
|
50
|
+
@flavor = flavor
|
51
|
+
@base_origin = origin
|
52
|
+
@includer = includer
|
53
|
+
@include_context = include_context
|
54
|
+
@path_stack = []
|
55
|
+
@array_count = 0
|
56
|
+
end
|
57
|
+
|
58
|
+
# merge a bunch of adjacent values into one
|
59
|
+
# value; change unquoted text into a string
|
60
|
+
# value.
|
61
|
+
def parse_concatenation(n)
|
62
|
+
# this trick is not done in JSON
|
63
|
+
if @flavor.equal?(ConfigSyntax::JSON)
|
64
|
+
raise ConfigBugOrBrokenError, "Found a concatenation node in JSON"
|
65
|
+
end
|
66
|
+
|
67
|
+
values = []
|
68
|
+
|
69
|
+
n.children.each do |node|
|
70
|
+
if node.is_a?(Hocon::Impl::AbstractConfigNodeValue)
|
71
|
+
v = parse_value(node, nil)
|
72
|
+
values.push(v)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
ConfigConcatenation.concatenate(values)
|
77
|
+
end
|
78
|
+
|
79
|
+
def line_origin
|
80
|
+
@base_origin.with_line_number(@line_number)
|
81
|
+
end
|
82
|
+
|
83
|
+
def parse_error(message, cause = nil)
|
84
|
+
ConfigParseError.new(line_origin, message, cause)
|
85
|
+
end
|
86
|
+
|
87
|
+
def full_current_path
|
88
|
+
# pathStack has top of stack at front
|
89
|
+
if @path_stack.empty?
|
90
|
+
raise ConfigBugOrBrokenError, "Bug in parser; tried to get current path when at root"
|
91
|
+
else
|
92
|
+
Path.from_path_list(@path_stack.reverse)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def parse_value(n, comments)
|
97
|
+
starting_array_count = @array_count
|
98
|
+
|
99
|
+
if n.is_a?(Hocon::Impl::ConfigNodeSimpleValue)
|
100
|
+
v = n.value
|
101
|
+
elsif n.is_a?(Hocon::Impl::ConfigNodeObject)
|
102
|
+
v = parse_object(n)
|
103
|
+
elsif n.is_a?(Hocon::Impl::ConfigNodeArray)
|
104
|
+
v = parse_array(n)
|
105
|
+
elsif n.is_a?(Hocon::Impl::ConfigNodeConcatenation)
|
106
|
+
v = parse_concatenation(n)
|
107
|
+
else
|
108
|
+
raise parse_error("Expecting a value but got wrong node type: #{n.class}")
|
109
|
+
end
|
110
|
+
|
111
|
+
unless comments.nil? || comments.empty?
|
112
|
+
v = v.with_origin(v.origin.prepend_comments(comments.clone))
|
113
|
+
comments.clear
|
114
|
+
end
|
115
|
+
|
116
|
+
unless @array_count == starting_array_count
|
117
|
+
raise ConfigBugOrBrokenError, "Bug in config parser: unbalanced array count"
|
118
|
+
end
|
119
|
+
|
120
|
+
v
|
121
|
+
end
|
122
|
+
|
123
|
+
def create_value_under_path(path, value)
|
124
|
+
# for path foo.bar, we are creating
|
125
|
+
# { "foo" : { "bar" : value } }
|
126
|
+
keys = []
|
127
|
+
|
128
|
+
key = path.first
|
129
|
+
remaining = path.remainder
|
130
|
+
until key.nil?
|
131
|
+
keys.push(key)
|
132
|
+
if remaining.nil?
|
133
|
+
break
|
134
|
+
else
|
135
|
+
key = remaining.first
|
136
|
+
remaining = remaining.remainder
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# the setComments(null) is to ensure comments are only
|
141
|
+
# on the exact leaf node they apply to.
|
142
|
+
# a comment before "foo.bar" applies to the full setting
|
143
|
+
# "foo.bar" not also to "foo"
|
144
|
+
keys = keys.reverse
|
145
|
+
# this is just a ruby means for doing first/rest
|
146
|
+
deepest, *rest = *keys
|
147
|
+
o = SimpleConfigObject.new(value.origin.with_comments(nil),
|
148
|
+
{deepest => value})
|
149
|
+
while !rest.empty?
|
150
|
+
deepest, *rest = *rest
|
151
|
+
o = SimpleConfigObject.new(value.origin.with_comments(nil),
|
152
|
+
{deepest => o})
|
153
|
+
end
|
154
|
+
|
155
|
+
o
|
156
|
+
end
|
157
|
+
|
158
|
+
def parse_include(values, n)
|
159
|
+
case n.kind
|
160
|
+
when ConfigIncludeKind::URL
|
161
|
+
url = nil
|
162
|
+
begin
|
163
|
+
url = Hocon::Impl::Url.new(n.name)
|
164
|
+
rescue Hocon::Impl::Url::MalformedUrlError => e
|
165
|
+
raise parse_error("include url() specifies an invalid URL: #{n.name}", e)
|
166
|
+
end
|
167
|
+
obj = @includer.include_url(@include_context, url)
|
168
|
+
when ConfigIncludeKind::FILE
|
169
|
+
obj = @includer.include_file(@include_context, n.name)
|
170
|
+
when ConfigIncludeKind::CLASSPATH
|
171
|
+
obj = @includer.include_resources(@include_context, n.name)
|
172
|
+
when ConfigIncludeKind::HEURISTIC
|
173
|
+
obj = @includer.include(@include_context, n.name)
|
174
|
+
else
|
175
|
+
raise ConfigBugOrBrokenError, "should not be reached"
|
176
|
+
end
|
177
|
+
|
178
|
+
# we really should make this work, but for now throwing an
|
179
|
+
# exception is better than producing an incorrect result.
|
180
|
+
# See https://github.com/typesafehub/config/issues/160
|
181
|
+
if @array_count > 0 && (obj.resolve_status != Hocon::Impl::ResolveStatus::RESOLVED)
|
182
|
+
raise parse_error("Due to current limitations of the config parser, when an include statement is nested inside a list value, " +
|
183
|
+
"${} substitutions inside the included file cannot be resolved correctly. Either move the include outside of the list value or " +
|
184
|
+
"remove the ${} statements from the included file.")
|
185
|
+
end
|
186
|
+
|
187
|
+
if !(@path_stack.empty?)
|
188
|
+
prefix = full_current_path
|
189
|
+
obj = obj.relativized(prefix)
|
190
|
+
end
|
191
|
+
|
192
|
+
obj.key_set.each do |key|
|
193
|
+
v = obj.get(key)
|
194
|
+
existing = values[key]
|
195
|
+
if !(existing.nil?)
|
196
|
+
values[key] = v.with_fallback(existing)
|
197
|
+
else
|
198
|
+
values[key] = v
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def parse_object(n)
|
204
|
+
values = Hash.new
|
205
|
+
object_origin = line_origin
|
206
|
+
last_was_new_line = false
|
207
|
+
|
208
|
+
nodes = n.children.clone
|
209
|
+
comments = []
|
210
|
+
i = 0
|
211
|
+
while i < nodes.size
|
212
|
+
node = nodes[i]
|
213
|
+
if node.is_a?(ConfigNodeComment)
|
214
|
+
last_was_new_line = false
|
215
|
+
comments.push(node.comment_text)
|
216
|
+
elsif node.is_a?(ConfigNodeSingleToken) && Tokens.newline?(node.token)
|
217
|
+
@line_number += 1
|
218
|
+
if last_was_new_line
|
219
|
+
# Drop all comments if there was a blank line and start a new comment block
|
220
|
+
comments.clear
|
221
|
+
end
|
222
|
+
last_was_new_line = true
|
223
|
+
elsif !@flavor.equal?(ConfigSyntax::JSON) && node.is_a?(ConfigNodeInclude)
|
224
|
+
parse_include(values, node)
|
225
|
+
last_was_new_line = false
|
226
|
+
elsif node.is_a?(Hocon::Impl::ConfigNodeField)
|
227
|
+
last_was_new_line = false
|
228
|
+
path = node.path.value
|
229
|
+
comments += node.comments
|
230
|
+
|
231
|
+
# path must be on-stack while we parse the value
|
232
|
+
# Note that, in upstream, pathStack is a LinkedList, so use unshift instead of push
|
233
|
+
@path_stack.unshift(path)
|
234
|
+
if node.separator.equal?(Tokens::PLUS_EQUALS)
|
235
|
+
# we really should make this work, but for now throwing
|
236
|
+
# an exception is better than producing an incorrect
|
237
|
+
# result. See
|
238
|
+
# https://github.com/typesafehub/config/issues/160
|
239
|
+
if @array_count > 0
|
240
|
+
raise parse_error("Due to current limitations of the config parser, += does not work nested inside a list. " +
|
241
|
+
"+= expands to a ${} substitution and the path in ${} cannot currently refer to list elements. " +
|
242
|
+
"You might be able to move the += outside of the list and then refer to it from inside the list with ${}.")
|
243
|
+
end
|
244
|
+
|
245
|
+
# because we will put it in an array after the fact so
|
246
|
+
# we want this to be incremented during the parseValue
|
247
|
+
# below in order to throw the above exception.
|
248
|
+
@array_count += 1
|
249
|
+
end
|
250
|
+
|
251
|
+
value_node = node.value
|
252
|
+
|
253
|
+
# comments from the key token go to the value token
|
254
|
+
new_value = parse_value(value_node, comments)
|
255
|
+
|
256
|
+
if node.separator.equal?(Tokens::PLUS_EQUALS)
|
257
|
+
@array_count -= 1
|
258
|
+
|
259
|
+
concat = []
|
260
|
+
previous_ref = ConfigReference.new(new_value.origin,
|
261
|
+
Hocon::Impl::SubstitutionExpression.new(full_current_path, true))
|
262
|
+
list = SimpleConfigList.new(new_value.origin, [new_value])
|
263
|
+
concat << previous_ref
|
264
|
+
concat << list
|
265
|
+
new_value = ConfigConcatenation.concatenate(concat)
|
266
|
+
end
|
267
|
+
|
268
|
+
# Grab any trailing comments on the same line
|
269
|
+
if i < nodes.size - 1
|
270
|
+
i += 1
|
271
|
+
while i < nodes.size
|
272
|
+
if nodes[i].is_a?(ConfigNodeComment)
|
273
|
+
comment = nodes[i]
|
274
|
+
new_value = new_value.with_origin(new_value.origin.append_comments([comment.comment_text]))
|
275
|
+
break
|
276
|
+
elsif nodes[i].is_a?(ConfigNodeSingleToken)
|
277
|
+
curr = nodes[i]
|
278
|
+
if curr.token.equal?(Tokens::COMMA) || Tokens.ignored_whitespace?(curr.token)
|
279
|
+
# keep searching, as there could still be a comment
|
280
|
+
else
|
281
|
+
i -= 1
|
282
|
+
break
|
283
|
+
end
|
284
|
+
else
|
285
|
+
i -= 1
|
286
|
+
break
|
287
|
+
end
|
288
|
+
i += 1
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
@path_stack.shift
|
293
|
+
|
294
|
+
key = path.first
|
295
|
+
remaining = path.remainder
|
296
|
+
|
297
|
+
if remaining.nil?
|
298
|
+
existing = values[key]
|
299
|
+
unless existing.nil?
|
300
|
+
# In strict JSON, dups should be an error; while in
|
301
|
+
# our custom config language, they should be merged
|
302
|
+
# if the value is an object (or substitution that
|
303
|
+
# could become an object).
|
304
|
+
|
305
|
+
if @flavor.equal?(ConfigSyntax::JSON)
|
306
|
+
raise parse_error("JSON does not allow duplicate fields: '#{key}'" +
|
307
|
+
" was already seen at #{existing.origin().description()}")
|
308
|
+
else
|
309
|
+
new_value = new_value.with_fallback(existing)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
values[key] = new_value
|
313
|
+
else
|
314
|
+
if @flavor == ConfigSyntax::JSON
|
315
|
+
raise Hocon::ConfigError::ConfigBugOrBrokenError, "somehow got multi-element path in JSON mode"
|
316
|
+
end
|
317
|
+
|
318
|
+
obj = create_value_under_path(remaining, new_value)
|
319
|
+
existing = values[key]
|
320
|
+
if !existing.nil?
|
321
|
+
obj = obj.with_fallback(existing)
|
322
|
+
end
|
323
|
+
values[key] = obj
|
324
|
+
end
|
325
|
+
end
|
326
|
+
i += 1
|
327
|
+
end
|
328
|
+
|
329
|
+
SimpleConfigObject.new(object_origin, values)
|
330
|
+
end
|
331
|
+
|
332
|
+
def parse_array(n)
|
333
|
+
@array_count += 1
|
334
|
+
|
335
|
+
array_origin = line_origin
|
336
|
+
values = []
|
337
|
+
|
338
|
+
last_was_new_line = false
|
339
|
+
comments = []
|
340
|
+
|
341
|
+
v = nil
|
342
|
+
|
343
|
+
n.children.each do |node|
|
344
|
+
if node.is_a?(ConfigNodeComment)
|
345
|
+
comments << node.comment_text
|
346
|
+
last_was_new_line = false
|
347
|
+
elsif node.is_a?(ConfigNodeSingleToken) && Tokens.newline?(node.token)
|
348
|
+
@line_number += 1
|
349
|
+
if last_was_new_line && v.nil?
|
350
|
+
comments.clear
|
351
|
+
elsif !v.nil?
|
352
|
+
values << v.with_origin(v.origin.append_comments(comments.clone))
|
353
|
+
comments.clear
|
354
|
+
v = nil
|
355
|
+
end
|
356
|
+
last_was_new_line = true
|
357
|
+
elsif node.is_a?(Hocon::Impl::AbstractConfigNodeValue)
|
358
|
+
last_was_new_line = false
|
359
|
+
unless v.nil?
|
360
|
+
values << v.with_origin(v.origin.append_comments(comments.clone))
|
361
|
+
comments.clear
|
362
|
+
end
|
363
|
+
v = parse_value(node, comments)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
# There shouldn't be any comments at this point, but add them just in case
|
367
|
+
unless v.nil?
|
368
|
+
values << v.with_origin(v.origin.append_comments(comments.clone))
|
369
|
+
end
|
370
|
+
@array_count -= 1
|
371
|
+
SimpleConfigList.new(array_origin, values)
|
372
|
+
end
|
373
|
+
|
374
|
+
def parse
|
375
|
+
result = nil
|
376
|
+
comments = []
|
377
|
+
last_was_new_line = false
|
378
|
+
@document.children.each do |node|
|
379
|
+
if node.is_a?(ConfigNodeComment)
|
380
|
+
comments << node.comment_text
|
381
|
+
last_was_new_line = false
|
382
|
+
elsif node.is_a?(ConfigNodeSingleToken)
|
383
|
+
t = node.token
|
384
|
+
if Tokens.newline?(t)
|
385
|
+
@line_number += 1
|
386
|
+
if last_was_new_line && result.nil?
|
387
|
+
comments.clear
|
388
|
+
elsif !result.nil?
|
389
|
+
result = result.with_origin(result.origin.append_comments(comments.clone))
|
390
|
+
comments.clear
|
391
|
+
break
|
392
|
+
end
|
393
|
+
last_was_new_line = true
|
394
|
+
end
|
395
|
+
elsif node.is_a?(Hocon::Impl::ConfigNodeComplexValue)
|
396
|
+
result = parse_value(node, comments)
|
397
|
+
last_was_new_line = false
|
398
|
+
end
|
399
|
+
end
|
400
|
+
result
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|