puppet-lint 2.5.2 → 3.0.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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +522 -0
  3. data/lib/puppet-lint/bin.rb +71 -6
  4. data/lib/puppet-lint/checkplugin.rb +43 -9
  5. data/lib/puppet-lint/checks.rb +16 -16
  6. data/lib/puppet-lint/configuration.rb +134 -134
  7. data/lib/puppet-lint/data.rb +28 -28
  8. data/lib/puppet-lint/lexer/string_slurper.rb +138 -140
  9. data/lib/puppet-lint/lexer/token.rb +188 -190
  10. data/lib/puppet-lint/lexer.rb +416 -417
  11. data/lib/puppet-lint/monkeypatches.rb +1 -1
  12. data/lib/puppet-lint/optparser.rb +5 -1
  13. data/lib/puppet-lint/plugins/check_classes/arrow_on_right_operand_line.rb +6 -4
  14. data/lib/puppet-lint/plugins/check_classes/autoloader_layout.rb +5 -3
  15. data/lib/puppet-lint/plugins/check_classes/class_inherits_from_params_class.rb +6 -4
  16. data/lib/puppet-lint/plugins/check_classes/code_on_top_scope.rb +5 -3
  17. data/lib/puppet-lint/plugins/check_classes/inherits_across_namespaces.rb +5 -3
  18. data/lib/puppet-lint/plugins/check_classes/names_containing_dash.rb +5 -3
  19. data/lib/puppet-lint/plugins/check_classes/names_containing_uppercase.rb +7 -5
  20. data/lib/puppet-lint/plugins/check_classes/nested_classes_or_defines.rb +5 -3
  21. data/lib/puppet-lint/plugins/check_classes/parameter_order.rb +7 -4
  22. data/lib/puppet-lint/plugins/check_classes/right_to_left_relationship.rb +5 -3
  23. data/lib/puppet-lint/plugins/check_classes/variable_scope.rb +15 -13
  24. data/lib/puppet-lint/plugins/check_comments/slash_comments.rb +9 -7
  25. data/lib/puppet-lint/plugins/check_comments/star_comments.rb +10 -8
  26. data/lib/puppet-lint/plugins/check_conditionals/case_without_default.rb +6 -4
  27. data/lib/puppet-lint/plugins/check_conditionals/selector_inside_resource.rb +5 -3
  28. data/lib/puppet-lint/plugins/check_documentation/documentation.rb +7 -3
  29. data/lib/puppet-lint/plugins/check_nodes/unquoted_node_name.rb +15 -11
  30. data/lib/puppet-lint/plugins/check_resources/duplicate_params.rb +5 -3
  31. data/lib/puppet-lint/plugins/check_resources/ensure_first_param.rb +8 -5
  32. data/lib/puppet-lint/plugins/check_resources/ensure_not_symlink_target.rb +11 -8
  33. data/lib/puppet-lint/plugins/check_resources/file_mode.rb +14 -9
  34. data/lib/puppet-lint/plugins/check_resources/unquoted_file_mode.rb +11 -6
  35. data/lib/puppet-lint/plugins/check_resources/unquoted_resource_title.rb +6 -4
  36. data/lib/puppet-lint/plugins/check_strings/double_quoted_strings.rb +12 -7
  37. data/lib/puppet-lint/plugins/check_strings/only_variable_string.rb +8 -6
  38. data/lib/puppet-lint/plugins/check_strings/puppet_url_without_modules.rb +14 -8
  39. data/lib/puppet-lint/plugins/check_strings/quoted_booleans.rb +11 -7
  40. data/lib/puppet-lint/plugins/check_strings/single_quote_string_with_variables.rb +11 -6
  41. data/lib/puppet-lint/plugins/check_strings/variables_not_enclosed.rb +12 -8
  42. data/lib/puppet-lint/plugins/check_variables/variable_contains_dash.rb +11 -7
  43. data/lib/puppet-lint/plugins/check_variables/variable_is_lowercase.rb +11 -7
  44. data/lib/puppet-lint/plugins/check_whitespace/140chars.rb +3 -8
  45. data/lib/puppet-lint/plugins/check_whitespace/2sp_soft_tabs.rb +10 -8
  46. data/lib/puppet-lint/plugins/check_whitespace/80chars.rb +3 -8
  47. data/lib/puppet-lint/plugins/check_whitespace/arrow_alignment.rb +10 -8
  48. data/lib/puppet-lint/plugins/check_whitespace/hard_tabs.rb +11 -7
  49. data/lib/puppet-lint/plugins/check_whitespace/line_length.rb +29 -0
  50. data/lib/puppet-lint/plugins/check_whitespace/trailing_whitespace.rb +13 -7
  51. data/lib/puppet-lint/plugins.rb +63 -61
  52. data/lib/puppet-lint/report/github.rb +17 -0
  53. data/lib/puppet-lint/report/sarif_template.json +63 -0
  54. data/lib/puppet-lint/tasks/puppet-lint.rb +84 -83
  55. data/lib/puppet-lint/tasks/release_test.rb +4 -1
  56. data/lib/puppet-lint/version.rb +1 -1
  57. data/lib/puppet-lint.rb +27 -12
  58. data/spec/acceptance/puppet_lint_spec.rb +46 -0
  59. data/spec/spec_helper.rb +92 -91
  60. data/spec/spec_helper_acceptance.rb +6 -0
  61. data/spec/spec_helper_acceptance_local.rb +38 -0
  62. data/spec/{puppet-lint → unit/puppet-lint}/bin_spec.rb +79 -35
  63. data/spec/{puppet-lint → unit/puppet-lint}/checks_spec.rb +36 -36
  64. data/spec/unit/puppet-lint/configuration_spec.rb +88 -0
  65. data/spec/{puppet-lint → unit/puppet-lint}/data_spec.rb +6 -3
  66. data/spec/{puppet-lint → unit/puppet-lint}/ignore_overrides_spec.rb +17 -17
  67. data/spec/{puppet-lint → unit/puppet-lint}/lexer/string_slurper_spec.rb +128 -128
  68. data/spec/{puppet-lint → unit/puppet-lint}/lexer/token_spec.rb +1 -1
  69. data/spec/{puppet-lint → unit/puppet-lint}/lexer_spec.rb +653 -671
  70. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/arrow_on_right_operand_line_spec.rb +16 -16
  71. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/autoloader_layout_spec.rb +13 -13
  72. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/class_inherits_from_params_class_spec.rb +3 -3
  73. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/code_on_top_scope_spec.rb +4 -4
  74. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/inherits_across_namespaces_spec.rb +4 -4
  75. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/name_contains_uppercase_spec.rb +10 -10
  76. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/names_containing_dash_spec.rb +7 -7
  77. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/nested_classes_or_defines_spec.rb +7 -7
  78. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/parameter_order_spec.rb +9 -9
  79. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/right_to_left_relationship_spec.rb +3 -3
  80. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/variable_scope_spec.rb +25 -25
  81. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_comments/slash_comments_spec.rb +7 -7
  82. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_comments/star_comments_spec.rb +13 -13
  83. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_conditionals/case_without_default_spec.rb +10 -10
  84. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_conditionals/selector_inside_resource_spec.rb +3 -3
  85. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_documentation/documentation_spec.rb +8 -8
  86. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_nodes/unquoted_node_name_spec.rb +24 -24
  87. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/duplicate_params_spec.rb +9 -9
  88. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/ensure_first_param_spec.rb +19 -19
  89. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/ensure_not_symlink_target_spec.rb +10 -10
  90. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/file_mode_spec.rb +40 -40
  91. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/unquoted_file_mode_spec.rb +20 -20
  92. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/unquoted_resource_title_spec.rb +24 -24
  93. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/double_quoted_strings_spec.rb +27 -27
  94. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/only_variable_string_spec.rb +18 -18
  95. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/puppet_url_without_modules_spec.rb +9 -9
  96. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/quoted_booleans_spec.rb +22 -22
  97. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/single_quote_string_with_variables_spec.rb +2 -2
  98. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/variables_not_enclosed_spec.rb +21 -21
  99. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_variables/variable_contains_dash_spec.rb +6 -6
  100. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_variables/variable_is_lowercase_spec.rb +7 -7
  101. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/140chars_spec.rb +5 -5
  102. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/2sp_soft_tabs_spec.rb +2 -2
  103. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/80chars_spec.rb +6 -6
  104. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/arrow_alignment_spec.rb +127 -127
  105. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/hard_tabs_spec.rb +7 -7
  106. data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/trailing_whitespace_spec.rb +15 -15
  107. data/spec/unit/puppet-lint/puppet-lint_spec.rb +18 -0
  108. metadata +63 -119
  109. data/CHANGELOG.md +0 -33
  110. data/HISTORY.md +0 -1130
  111. data/spec/puppet-lint/configuration_spec.rb +0 -66
  112. data/spec/puppet-lint_spec.rb +0 -16
@@ -6,461 +6,460 @@ require 'set'
6
6
  require 'puppet-lint/lexer/token'
7
7
  require 'puppet-lint/lexer/string_slurper'
8
8
 
9
- class PuppetLint
10
- # Internal: A generic error thrown by the lexer when it encounters something
11
- # it can't handle.
12
- class LexerError < StandardError
13
- # Internal: Get the Integer line number of the location of the error.
14
- attr_reader :line_no
15
-
16
- # Internal: Get the Integer column number of the location of the error.
17
- attr_reader :column
18
-
19
- # Internal: Get the String reason for the error (if known).
20
- attr_reader :reason
21
-
22
- # Internal: Initialise a new PuppetLint::LexerError object.
23
- #
24
- # line_no - The Integer line number of the location of the error.
25
- # column - The Integer column number of the location of the error.
26
- # reason - A String describing the cause of the error (if known).
27
- def initialize(line_no, column, reason = nil)
28
- @line_no = line_no
29
- @column = column
30
- @reason = reason
31
- end
9
+ # Internal: A generic error thrown by the lexer when it encounters something
10
+ # it can't handle.
11
+ class PuppetLint::LexerError < StandardError
12
+ # Internal: Get the Integer line number of the location of the error.
13
+ attr_reader :line_no
14
+
15
+ # Internal: Get the Integer column number of the location of the error.
16
+ attr_reader :column
17
+
18
+ # Internal: Get the String reason for the error (if known).
19
+ attr_reader :reason
20
+
21
+ # Internal: Initialise a new PuppetLint::LexerError object.
22
+ #
23
+ # line_no - The Integer line number of the location of the error.
24
+ # column - The Integer column number of the location of the error.
25
+ # reason - A String describing the cause of the error (if known).
26
+ # rubocop:disable Lint/MissingSuper
27
+ def initialize(line_no, column, reason = nil)
28
+ @line_no = line_no
29
+ @column = column
30
+ @reason = reason
31
+ end
32
32
 
33
- def to_s
34
- "PuppetLint::LexerError: Line:#{line_no} Column: #{column} Reason: #{reason}"
35
- end
33
+ def to_s
34
+ "PuppetLint::LexerError: Line:#{line_no} Column: #{column} Reason: #{reason}"
36
35
  end
36
+ end
37
37
 
38
- # Internal: The puppet-lint lexer. Converts your manifest into its tokenised
39
- # form.
40
- class Lexer
41
- def initialize
42
- @line_no = 1
43
- @column = 1
44
- end
38
+ # Internal: The puppet-lint lexer. Converts your manifest into its tokenised
39
+ # form.
40
+ class PuppetLint::Lexer
41
+ def initialize
42
+ @line_no = 1
43
+ @column = 1
44
+ end
45
45
 
46
- def self.heredoc_queue
47
- @heredoc_queue ||= []
48
- end
46
+ def self.heredoc_queue
47
+ @heredoc_queue ||= []
48
+ end
49
49
 
50
- def heredoc_queue
51
- self.class.heredoc_queue
52
- end
50
+ def heredoc_queue
51
+ self.class.heredoc_queue
52
+ end
53
53
 
54
- # Internal: A Hash whose keys are Strings representing reserved keywords in
55
- # the Puppet DSL.
56
- # From https://github.com/puppetlabs/puppet/blob/master/lib/puppet/pops/parser/lexer2.rb#L116-L137
57
- # or thereabouts
58
- KEYWORDS = {
59
- 'case' => true,
60
- 'class' => true,
61
- 'default' => true,
62
- 'define' => true,
63
- 'import' => true,
64
- 'if' => true,
65
- 'elsif' => true,
66
- 'else' => true,
67
- 'inherits' => true,
68
- 'node' => true,
69
- 'and' => true,
70
- 'or' => true,
71
- 'undef' => true,
72
- 'false' => true,
73
- 'true' => true,
74
- 'in' => true,
75
- 'unless' => true,
76
- 'function' => true,
77
- 'type' => true,
78
- 'attr' => true,
79
- 'private' => true,
80
- }.freeze
81
-
82
- # Internal: A Hash whose keys are Strings representing reserved keywords in
83
- # the Puppet DSL when Application Management is enabled
84
- # From https://github.com/puppetlabs/puppet/blob/master/lib/puppet/pops/parser/lexer2.rb#L142-L159
85
- # or therabouts
86
- # Currently unused
87
- APP_MANAGEMENT_TOKENS = {
88
- 'application' => true,
89
- 'consumes' => true,
90
- 'produces' => true,
91
- 'site' => true,
92
- }.freeze
93
-
94
- # Internal: A Hash whose keys are Symbols representing token types which
95
- # a regular expression can follow.
96
- REGEX_PREV_TOKENS = {
97
- :NODE => true,
98
- :LBRACE => true,
99
- :RBRACE => true,
100
- :MATCH => true,
101
- :NOMATCH => true,
102
- :COMMA => true,
103
- :LBRACK => true,
104
- :IF => true,
105
- :ELSIF => true,
106
- :LPAREN => true,
107
- :EQUALS => true,
108
- }.freeze
109
-
110
- # Internal: some commonly used regular expressions
111
- # \t == tab
112
- # \v == vertical tab
113
- # \f == form feed
114
- # \p{Zs} == ASCII + Unicode non-linebreaking whitespace
115
- WHITESPACE_RE = RUBY_VERSION == '1.8.7' ? %r{[\t\v\f ]} : %r{[\t\v\f\p{Zs}]}
116
-
117
- LINE_END_RE = %r{(?:\r\n|\r|\n)}
118
-
119
- NAME_RE = %r{\A((?:(?:::)?[_a-z0-9][-\w]*)(?:::[a-z0-9][-\w]*)*)}
120
-
121
- # Internal: An Array of Arrays containing tokens that can be described by
122
- # a single regular expression. Each sub-Array contains 2 elements, the
123
- # name of the token as a Symbol and a regular expression describing the
124
- # value of the token.
125
- KNOWN_TOKENS = [
126
- [:WHITESPACE, %r{\A(#{WHITESPACE_RE}+)}],
127
- # FIXME: Future breaking change, the following :TYPE tokens conflict with
128
- # the :TYPE keyword token.
129
- [:TYPE, %r{\A(Integer|Float|Boolean|Regexp|String|Array|Hash|Resource|Class|Collection|Scalar|Numeric|CatalogEntry|Data|Tuple|Struct|Optional|NotUndef|Variant|Enum|Pattern|Any|Callable|Type|Runtime|Undef|Default|Sensitive)\b}], # rubocop:disable Metrics/LineLength
130
- [:CLASSREF, %r{\A(((::){0,1}[A-Z][-\w]*)+)}],
131
- [:NUMBER, %r{\A\b((?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?))\b}],
132
- [:FUNCTION_NAME, %r{#{NAME_RE}(?=\()}],
133
- [:NAME, NAME_RE],
134
- [:LBRACK, %r{\A(\[)}],
135
- [:RBRACK, %r{\A(\])}],
136
- [:LBRACE, %r{\A(\{)}],
137
- [:RBRACE, %r{\A(\})}],
138
- [:LPAREN, %r{\A(\()}],
139
- [:RPAREN, %r{\A(\))}],
140
- [:ISEQUAL, %r{\A(==)}],
141
- [:MATCH, %r{\A(=~)}],
142
- [:FARROW, %r{\A(=>)}],
143
- [:EQUALS, %r{\A(=)}],
144
- [:APPENDS, %r{\A(\+=)}],
145
- [:PARROW, %r{\A(\+>)}],
146
- [:PLUS, %r{\A(\+)}],
147
- [:GREATEREQUAL, %r{\A(>=)}],
148
- [:RSHIFT, %r{\A(>>)}],
149
- [:GREATERTHAN, %r{\A(>)}],
150
- [:LESSEQUAL, %r{\A(<=)}],
151
- [:LLCOLLECT, %r{\A(<<\|)}],
152
- [:OUT_EDGE, %r{\A(<-)}],
153
- [:OUT_EDGE_SUB, %r{\A(<~)}],
154
- [:LCOLLECT, %r{\A(<\|)}],
155
- [:LSHIFT, %r{\A(<<)}],
156
- [:LESSTHAN, %r{\A(<)}],
157
- [:NOMATCH, %r{\A(!~)}],
158
- [:NOTEQUAL, %r{\A(!=)}],
159
- [:NOT, %r{\A(!)}],
160
- [:RRCOLLECT, %r{\A(\|>>)}],
161
- [:RCOLLECT, %r{\A(\|>)}],
162
- [:IN_EDGE, %r{\A(->)}],
163
- [:IN_EDGE_SUB, %r{\A(~>)}],
164
- [:MINUS, %r{\A(-)}],
165
- [:COMMA, %r{\A(,)}],
166
- [:DOT, %r{\A(\.)}],
167
- [:COLON, %r{\A(:)}],
168
- [:SEMIC, %r{\A(;)}],
169
- [:QMARK, %r{\A(\?)}],
170
- [:BACKSLASH, %r{\A(\\)}],
171
- [:TIMES, %r{\A(\*)}],
172
- [:MODULO, %r{\A(%)}],
173
- [:PIPE, %r{\A(\|)}],
174
- ].freeze
175
-
176
- # Internal: A Hash whose keys are Symbols representing token types which
177
- # are considered to be formatting tokens (i.e. tokens that don't contain
178
- # code).
179
- FORMATTING_TOKENS = {
180
- :WHITESPACE => true,
181
- :NEWLINE => true,
182
- :COMMENT => true,
183
- :MLCOMMENT => true,
184
- :SLASH_COMMENT => true,
185
- :INDENT => true,
186
- }.freeze
187
-
188
- # Internal: Access the internal token storage.
189
- #
190
- # Returns an Array of PuppetLint::Lexer::Toxen objects.
191
- def tokens
192
- @tokens ||= []
193
- end
54
+ # Internal: A Hash whose keys are Strings representing reserved keywords in
55
+ # the Puppet DSL.
56
+ # From https://github.com/puppetlabs/puppet/blob/master/lib/puppet/pops/parser/lexer2.rb#L116-L137
57
+ # or thereabouts
58
+ KEYWORDS = {
59
+ 'case' => true,
60
+ 'class' => true,
61
+ 'default' => true,
62
+ 'define' => true,
63
+ 'import' => true,
64
+ 'if' => true,
65
+ 'elsif' => true,
66
+ 'else' => true,
67
+ 'inherits' => true,
68
+ 'node' => true,
69
+ 'and' => true,
70
+ 'or' => true,
71
+ 'undef' => true,
72
+ 'false' => true,
73
+ 'true' => true,
74
+ 'in' => true,
75
+ 'unless' => true,
76
+ 'function' => true,
77
+ 'type' => true,
78
+ 'attr' => true,
79
+ 'private' => true,
80
+ }.freeze
81
+
82
+ # Internal: A Hash whose keys are Strings representing reserved keywords in
83
+ # the Puppet DSL when Application Management is enabled
84
+ # From https://github.com/puppetlabs/puppet/blob/master/lib/puppet/pops/parser/lexer2.rb#L142-L159
85
+ # or therabouts
86
+ # Currently unused
87
+ APP_MANAGEMENT_TOKENS = {
88
+ 'application' => true,
89
+ 'consumes' => true,
90
+ 'produces' => true,
91
+ 'site' => true,
92
+ }.freeze
93
+
94
+ # Internal: A Hash whose keys are Symbols representing token types which
95
+ # a regular expression can follow.
96
+ REGEX_PREV_TOKENS = {
97
+ NODE: true,
98
+ LBRACE: true,
99
+ RBRACE: true,
100
+ MATCH: true,
101
+ NOMATCH: true,
102
+ COMMA: true,
103
+ LBRACK: true,
104
+ IF: true,
105
+ ELSIF: true,
106
+ LPAREN: true,
107
+ EQUALS: true,
108
+ }.freeze
109
+
110
+ # Internal: some commonly used regular expressions
111
+ # \t == tab
112
+ # \v == vertical tab
113
+ # \f == form feed
114
+ # \p{Zs} == ASCII + Unicode non-linebreaking whitespace
115
+ WHITESPACE_RE = RUBY_VERSION == '1.8.7' ? %r{[\t\v\f ]} : %r{[\t\v\f\p{Zs}]}
116
+
117
+ LINE_END_RE = %r{(?:\r\n|\r|\n)}.freeze
118
+
119
+ NAME_RE = %r{\A((?:(?:::)?[_a-z0-9][-\w]*)(?:::[a-z0-9][-\w]*)*)}.freeze
120
+
121
+ # Internal: An Array of Arrays containing tokens that can be described by
122
+ # a single regular expression. Each sub-Array contains 2 elements, the
123
+ # name of the token as a Symbol and a regular expression describing the
124
+ # value of the token.
125
+ KNOWN_TOKENS = [
126
+ [:WHITESPACE, %r{\A(#{WHITESPACE_RE}+)}],
127
+ # FIXME: Future breaking change, the following :TYPE tokens conflict with
128
+ # the :TYPE keyword token.
129
+ [:TYPE, %r{\A(Integer|Float|Boolean|Regexp|String|Array|Hash|Resource|Class|Collection|Scalar|Numeric|CatalogEntry|Data|Tuple|Struct|Optional|NotUndef|Variant|Enum|Pattern|Any|Callable|Type|Runtime|Undef|Default|Sensitive)\b}], # rubocop:disable Layout/LineLength
130
+ [:CLASSREF, %r{\A(((::){0,1}[A-Z][-\w]*)+)}],
131
+ [:NUMBER, %r{\A\b((?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?))\b}],
132
+ [:FUNCTION_NAME, %r{#{NAME_RE}(?=\()}],
133
+ [:NAME, NAME_RE],
134
+ [:LBRACK, %r{\A(\[)}],
135
+ [:RBRACK, %r{\A(\])}],
136
+ [:LBRACE, %r{\A(\{)}],
137
+ [:RBRACE, %r{\A(\})}],
138
+ [:LPAREN, %r{\A(\()}],
139
+ [:RPAREN, %r{\A(\))}],
140
+ [:ISEQUAL, %r{\A(==)}],
141
+ [:MATCH, %r{\A(=~)}],
142
+ [:FARROW, %r{\A(=>)}],
143
+ [:EQUALS, %r{\A(=)}],
144
+ [:APPENDS, %r{\A(\+=)}],
145
+ [:PARROW, %r{\A(\+>)}],
146
+ [:PLUS, %r{\A(\+)}],
147
+ [:GREATEREQUAL, %r{\A(>=)}],
148
+ [:RSHIFT, %r{\A(>>)}],
149
+ [:GREATERTHAN, %r{\A(>)}],
150
+ [:LESSEQUAL, %r{\A(<=)}],
151
+ [:LLCOLLECT, %r{\A(<<\|)}],
152
+ [:OUT_EDGE, %r{\A(<-)}],
153
+ [:OUT_EDGE_SUB, %r{\A(<~)}],
154
+ [:LCOLLECT, %r{\A(<\|)}],
155
+ [:LSHIFT, %r{\A(<<)}],
156
+ [:LESSTHAN, %r{\A(<)}],
157
+ [:NOMATCH, %r{\A(!~)}],
158
+ [:NOTEQUAL, %r{\A(!=)}],
159
+ [:NOT, %r{\A(!)}],
160
+ [:RRCOLLECT, %r{\A(\|>>)}],
161
+ [:RCOLLECT, %r{\A(\|>)}],
162
+ [:IN_EDGE, %r{\A(->)}],
163
+ [:IN_EDGE_SUB, %r{\A(~>)}],
164
+ [:MINUS, %r{\A(-)}],
165
+ [:COMMA, %r{\A(,)}],
166
+ [:DOT, %r{\A(\.)}],
167
+ [:COLON, %r{\A(:)}],
168
+ [:SEMIC, %r{\A(;)}],
169
+ [:QMARK, %r{\A(\?)}],
170
+ [:BACKSLASH, %r{\A(\\)}],
171
+ [:TIMES, %r{\A(\*)}],
172
+ [:MODULO, %r{\A(%)}],
173
+ [:PIPE, %r{\A(\|)}],
174
+ ].freeze
175
+
176
+ # Internal: A Hash whose keys are Symbols representing token types which
177
+ # are considered to be formatting tokens (i.e. tokens that don't contain
178
+ # code).
179
+ FORMATTING_TOKENS = {
180
+ WHITESPACE: true,
181
+ NEWLINE: true,
182
+ COMMENT: true,
183
+ MLCOMMENT: true,
184
+ SLASH_COMMENT: true,
185
+ INDENT: true,
186
+ }.freeze
187
+
188
+ # Internal: Access the internal token storage.
189
+ #
190
+ # Returns an Array of PuppetLint::Lexer::Toxen objects.
191
+ def tokens
192
+ @tokens ||= []
193
+ end
194
194
 
195
- # Internal: Convert a Puppet manifest into tokens.
196
- #
197
- # code - The Puppet manifest to be tokenised as a String.
198
- #
199
- # Returns an Array of PuppetLint::Lexer::Token objects.
200
- # Raises PuppetLint::LexerError if it encounters unexpected characters
201
- # (usually the result of syntax errors).
202
- def tokenise(code)
203
- i = 0
204
-
205
- while i < code.size
206
- chunk = code[i..-1]
207
-
208
- found = false
209
-
210
- KNOWN_TOKENS.each do |type, regex|
211
- value = chunk[regex, 1]
212
- next if value.nil?
213
-
214
- i += value.size
215
- tokens << if type == :NAME && KEYWORDS.include?(value)
216
- new_token(value.upcase.to_sym, value)
217
- else
218
- new_token(type, value)
219
- end
220
- found = true
221
- break
222
- end
195
+ # Internal: Convert a Puppet manifest into tokens.
196
+ #
197
+ # code - The Puppet manifest to be tokenised as a String.
198
+ #
199
+ # Returns an Array of PuppetLint::Lexer::Token objects.
200
+ # Raises PuppetLint::LexerError if it encounters unexpected characters
201
+ # (usually the result of syntax errors).
202
+ def tokenise(code)
203
+ i = 0
204
+
205
+ while i < code.size
206
+ chunk = code[i..-1]
207
+
208
+ found = false
209
+
210
+ KNOWN_TOKENS.each do |type, regex|
211
+ value = chunk[regex, 1]
212
+ next if value.nil?
213
+
214
+ i += value.size
215
+ tokens << if type == :NAME && KEYWORDS.include?(value)
216
+ new_token(value.upcase.to_sym, value)
217
+ else
218
+ new_token(type, value)
219
+ end
220
+ found = true
221
+ break
222
+ end
223
223
 
224
- next if found
225
-
226
- if var_name = chunk[%r{\A\$((::)?(\w+(-\w+)*::)*\w+(-\w+)*(\[.+?\])*)}, 1]
227
- length = var_name.size + 1
228
- opts = if chunk.start_with?('$')
229
- { :raw => "$#{var_name}" }
230
- else
231
- {}
232
- end
233
- tokens << new_token(:VARIABLE, var_name, opts)
234
-
235
- elsif chunk =~ %r{\A'.*?'}m
236
- str_content = StringScanner.new(code[i + 1..-1]).scan_until(%r{(\A|[^\\])(\\\\)*'}m)
237
- length = str_content.size + 1
238
- tokens << new_token(:SSTRING, str_content[0..-2])
239
-
240
- elsif chunk.start_with?('"')
241
- slurper = PuppetLint::Lexer::StringSlurper.new(code[i + 1..-1])
242
- begin
243
- string_segments = slurper.parse
244
- process_string_segments(string_segments)
245
- length = slurper.consumed_chars + 1
246
- rescue PuppetLint::Lexer::StringSlurper::UnterminatedStringError
247
- raise PuppetLint::LexerError.new(@line_no, @column, 'unterminated string')
248
- end
249
-
250
- elsif heredoc_name = chunk[%r{\A@\(("?.+?"?(:.+?)?#{WHITESPACE_RE}*(/.*?)?)\)}, 1]
251
- heredoc_queue << heredoc_name
252
- tokens << new_token(:HEREDOC_OPEN, heredoc_name)
253
- length = heredoc_name.size + 3
254
-
255
- elsif comment = chunk[%r{\A(#[^\r\n]*)#{LINE_END_RE}?}, 1]
256
- length = comment.size
257
- comment.sub!(%r{#}, '')
258
- tokens << new_token(:COMMENT, comment)
259
-
260
- elsif slash_comment = chunk[%r{\A(//[^\r\n]*)#{LINE_END_RE}?}, 1]
261
- length = slash_comment.size
262
- slash_comment.sub!(%r{//}, '')
263
- tokens << new_token(:SLASH_COMMENT, slash_comment)
264
-
265
- elsif mlcomment = chunk[%r{\A(/\*.*?\*/)}m, 1]
266
- length = mlcomment.size
267
- mlcomment_raw = mlcomment.dup
268
- mlcomment.sub!(%r{\A/\* ?}, '')
269
- mlcomment.sub!(%r{ ?\*/\Z}, '')
270
- mlcomment.gsub!(%r{^ *\*}, '')
271
- tokens << new_token(:MLCOMMENT, mlcomment, :raw => mlcomment_raw)
272
-
273
- elsif chunk.match(%r{\A/.*?/}m) && possible_regex?
274
- str_content = StringScanner.new(code[i + 1..-1]).scan_until(%r{(\A|[^\\])(\\\\)*/}m)
275
- length = str_content.size + 1
276
- tokens << new_token(:REGEX, str_content[0..-2])
277
-
278
- elsif eolindent = chunk[%r{\A(#{LINE_END_RE}#{WHITESPACE_RE}+)}m, 1]
279
- eol = eolindent[%r{\A(#{LINE_END_RE})}m, 1]
280
- tokens << new_token(:NEWLINE, eol)
281
- length = eol.size
282
-
283
- if heredoc_queue.empty?
284
- indent = eolindent[%r{\A#{LINE_END_RE}+(#{WHITESPACE_RE}+)}m, 1]
285
- tokens << new_token(:INDENT, indent)
286
- length += indent.size
287
- else
288
- heredoc_tag = heredoc_queue.shift
289
- slurper = PuppetLint::Lexer::StringSlurper.new(code[i + length..-1])
290
- heredoc_segments = slurper.parse_heredoc(heredoc_tag)
291
- process_heredoc_segments(heredoc_segments)
292
- length += slurper.consumed_chars
293
- end
294
-
295
- elsif eol = chunk[%r{\A(#{LINE_END_RE})}, 1]
296
- length = eol.size
297
- tokens << new_token(:NEWLINE, eol)
298
-
299
- unless heredoc_queue.empty?
300
- heredoc_tag = heredoc_queue.shift
301
- slurper = PuppetLint::Lexer::StringSlurper.new(code[i + length..-1])
302
- heredoc_segments = slurper.parse_heredoc(heredoc_tag)
303
- process_heredoc_segments(heredoc_segments)
304
- length += slurper.consumed_chars
305
- end
306
-
307
- elsif chunk.start_with?('/')
308
- length = 1
309
- tokens << new_token(:DIV, '/')
310
-
311
- elsif chunk.start_with?('@')
312
- length = 1
313
- tokens << new_token(:AT, '@')
224
+ next if found
225
+
226
+ if (var_name = chunk[%r{\A\$((::)?(\w+(-\w+)*::)*\w+(-\w+)*(\[.+?\])*)}, 1])
227
+ length = var_name.size + 1
228
+ opts = if chunk.start_with?('$')
229
+ { raw: "$#{var_name}" }
230
+ else
231
+ {}
232
+ end
233
+ tokens << new_token(:VARIABLE, var_name, opts)
234
+
235
+ elsif %r{\A'.*?'}m.match?(chunk)
236
+ str_content = StringScanner.new(code[i + 1..-1]).scan_until(%r{(\A|[^\\])(\\\\)*'}m)
237
+ length = str_content.size + 1
238
+ tokens << new_token(:SSTRING, str_content[0..-2])
239
+
240
+ elsif chunk.start_with?('"')
241
+ slurper = PuppetLint::Lexer::StringSlurper.new(code[i + 1..-1])
242
+ begin
243
+ string_segments = slurper.parse
244
+ process_string_segments(string_segments)
245
+ length = slurper.consumed_chars + 1
246
+ rescue PuppetLint::Lexer::StringSlurper::UnterminatedStringError
247
+ raise PuppetLint::LexerError.new(@line_no, @column, 'unterminated string')
248
+ end
314
249
 
250
+ elsif (heredoc_name = chunk[%r{\A@\(("?.+?"?(:.+?)?#{WHITESPACE_RE}*(/.*?)?)\)}o, 1])
251
+ heredoc_queue << heredoc_name
252
+ tokens << new_token(:HEREDOC_OPEN, heredoc_name)
253
+ length = heredoc_name.size + 3
254
+
255
+ elsif (comment = chunk[%r{\A(#[^\r\n]*)#{LINE_END_RE}?}o, 1])
256
+ length = comment.size
257
+ comment.sub!(%r{#}, '')
258
+ tokens << new_token(:COMMENT, comment)
259
+
260
+ elsif (slash_comment = chunk[%r{\A(//[^\r\n]*)#{LINE_END_RE}?}o, 1])
261
+ length = slash_comment.size
262
+ slash_comment.sub!(%r{//}, '')
263
+ tokens << new_token(:SLASH_COMMENT, slash_comment)
264
+
265
+ elsif (mlcomment = chunk[%r{\A(/\*.*?\*/)}m, 1])
266
+ length = mlcomment.size
267
+ mlcomment_raw = mlcomment.dup
268
+ mlcomment.sub!(%r{\A/\* ?}, '')
269
+ mlcomment.sub!(%r{ ?\*/\Z}, '')
270
+ mlcomment.gsub!(%r{^ *\*}, '')
271
+ tokens << new_token(:MLCOMMENT, mlcomment, raw: mlcomment_raw)
272
+
273
+ elsif chunk.match(%r{\A/.*?/}m) && possible_regex?
274
+ str_content = StringScanner.new(code[i + 1..-1]).scan_until(%r{(\A|[^\\])(\\\\)*/}m)
275
+ length = str_content.size + 1
276
+ tokens << new_token(:REGEX, str_content[0..-2])
277
+
278
+ elsif (eolindent = chunk[%r{\A(#{LINE_END_RE}#{WHITESPACE_RE}+)}mo, 1])
279
+ eol = eolindent[%r{\A(#{LINE_END_RE})}mo, 1]
280
+ tokens << new_token(:NEWLINE, eol)
281
+ length = eol.size
282
+
283
+ if heredoc_queue.empty?
284
+ indent = eolindent[%r{\A#{LINE_END_RE}+(#{WHITESPACE_RE}+)}mo, 1]
285
+ tokens << new_token(:INDENT, indent)
286
+ length += indent.size
315
287
  else
316
- raise PuppetLint::LexerError.new(@line_no, @column)
288
+ heredoc_tag = heredoc_queue.shift
289
+ slurper = PuppetLint::Lexer::StringSlurper.new(code[i + length..-1])
290
+ heredoc_segments = slurper.parse_heredoc(heredoc_tag)
291
+ process_heredoc_segments(heredoc_segments)
292
+ length += slurper.consumed_chars
317
293
  end
318
294
 
319
- i += length
295
+ elsif (eol = chunk[%r{\A(#{LINE_END_RE})}o, 1])
296
+ length = eol.size
297
+ tokens << new_token(:NEWLINE, eol)
298
+
299
+ unless heredoc_queue.empty?
300
+ heredoc_tag = heredoc_queue.shift
301
+ slurper = PuppetLint::Lexer::StringSlurper.new(code[i + length..-1])
302
+ heredoc_segments = slurper.parse_heredoc(heredoc_tag)
303
+ process_heredoc_segments(heredoc_segments)
304
+ length += slurper.consumed_chars
305
+ end
306
+
307
+ elsif chunk.start_with?('/')
308
+ length = 1
309
+ tokens << new_token(:DIV, '/')
310
+
311
+ elsif chunk.start_with?('@')
312
+ length = 1
313
+ tokens << new_token(:AT, '@')
314
+
315
+ else
316
+ raise PuppetLint::LexerError.new(@line_no, @column)
320
317
  end
321
318
 
322
- tokens
319
+ i += length
323
320
  end
324
321
 
325
- # Internal: Given the tokens already processed, determine if the next token
326
- # could be a regular expression.
327
- #
328
- # Returns true if the next token could be a regex, otherwise return false.
329
- def possible_regex?
330
- prev_token = tokens.reject { |r|
331
- FORMATTING_TOKENS.include?(r.type)
332
- }.last
322
+ tokens
323
+ end
333
324
 
334
- return true if prev_token.nil?
325
+ # Internal: Given the tokens already processed, determine if the next token
326
+ # could be a regular expression.
327
+ #
328
+ # Returns true if the next token could be a regex, otherwise return false.
329
+ def possible_regex?
330
+ prev_token = tokens.reject { |r|
331
+ FORMATTING_TOKENS.include?(r.type)
332
+ }.last
335
333
 
336
- REGEX_PREV_TOKENS.include?(prev_token.type)
337
- end
334
+ return true if prev_token.nil?
338
335
 
339
- # Internal: Create a new PuppetLint::Lexer::Token object, calculate its
340
- # line number and column and then add it to the Linked List of tokens.
341
- #
342
- # type - The Symbol token type.
343
- # value - The token value.
344
- # opts - A Hash of additional values required to determine line number and
345
- # column:
346
- # :line - The Integer line number if calculated externally.
347
- # :column - The Integer column number if calculated externally.
348
- # :raw - The String raw value of the token (if necessary).
349
- #
350
- # Returns the instantiated PuppetLint::Lexer::Token object.
351
- def new_token(type, value, *args)
352
- # This bit of magic is used instead of an "opts = {}" argument so that we
353
- # can safely deprecate the old "length" parameter that might still be
354
- # passed by 3rd party plugins that haven't updated yet.
355
- opts = args.last.is_a?(Hash) ? args.last : {}
356
-
357
- # column number is calculated at the end of this method by calling
358
- # to_manifest on the token. Because the string tokens (DQPRE, DQMID etc)
359
- # are parsed before the variable token, they default to assuming that
360
- # they are followed by an enclosed variable and we need to remove 2 from
361
- # the column number if we encounter an unenclosed variable because of the
362
- # missing ${ at the end of the token value.
363
- @column -= 2 if type == :UNENC_VARIABLE
364
-
365
- column = opts[:column] || @column
366
- line_no = opts[:line] || @line_no
367
-
368
- token = Token.new(type, value, line_no, column)
369
- unless tokens.last.nil?
370
- token.prev_token = tokens.last
371
- tokens.last.next_token = token
372
-
373
- unless FORMATTING_TOKENS.include?(token.type)
374
- prev_nf_idx = tokens.rindex { |r| !FORMATTING_TOKENS.include?(r.type) }
375
- unless prev_nf_idx.nil?
376
- prev_nf_token = tokens[prev_nf_idx]
377
- prev_nf_token.next_code_token = token
378
- token.prev_code_token = prev_nf_token
379
- end
336
+ REGEX_PREV_TOKENS.include?(prev_token.type)
337
+ end
338
+
339
+ # Internal: Create a new PuppetLint::Lexer::Token object, calculate its
340
+ # line number and column and then add it to the Linked List of tokens.
341
+ #
342
+ # type - The Symbol token type.
343
+ # value - The token value.
344
+ # opts - A Hash of additional values required to determine line number and
345
+ # column:
346
+ # :line - The Integer line number if calculated externally.
347
+ # :column - The Integer column number if calculated externally.
348
+ # :raw - The String raw value of the token (if necessary).
349
+ #
350
+ # Returns the instantiated PuppetLint::Lexer::Token object.
351
+ def new_token(type, value, *args)
352
+ # This bit of magic is used instead of an "opts = {}" argument so that we
353
+ # can safely deprecate the old "length" parameter that might still be
354
+ # passed by 3rd party plugins that haven't updated yet.
355
+ opts = args.last.is_a?(Hash) ? args.last : {}
356
+
357
+ # column number is calculated at the end of this method by calling
358
+ # to_manifest on the token. Because the string tokens (DQPRE, DQMID etc)
359
+ # are parsed before the variable token, they default to assuming that
360
+ # they are followed by an enclosed variable and we need to remove 2 from
361
+ # the column number if we encounter an unenclosed variable because of the
362
+ # missing ${ at the end of the token value.
363
+ @column -= 2 if type == :UNENC_VARIABLE
364
+
365
+ column = opts[:column] || @column
366
+ line_no = opts[:line] || @line_no
367
+
368
+ token = Token.new(type, value, line_no, column)
369
+ unless tokens.last.nil?
370
+ token.prev_token = tokens.last
371
+ tokens.last.next_token = token
372
+
373
+ unless FORMATTING_TOKENS.include?(token.type)
374
+ prev_nf_idx = tokens.rindex { |r| !FORMATTING_TOKENS.include?(r.type) }
375
+ unless prev_nf_idx.nil?
376
+ prev_nf_token = tokens[prev_nf_idx]
377
+ prev_nf_token.next_code_token = token
378
+ token.prev_code_token = prev_nf_token
380
379
  end
381
380
  end
381
+ end
382
382
 
383
- token.raw = opts[:raw] if opts[:raw]
383
+ token.raw = opts[:raw] if opts[:raw]
384
384
 
385
- if type == :NEWLINE
386
- @line_no += 1
387
- @column = 1
385
+ if type == :NEWLINE
386
+ @line_no += 1
387
+ @column = 1
388
+ else
389
+ lines = token.to_manifest.split(LINE_END_RE, -1)
390
+ @line_no += lines.length - 1
391
+ if lines.length > 1
392
+ # if the token renders to multiple lines, set the column state to the
393
+ # length of the last line plus 1 (because column numbers are
394
+ # 1 indexed)
395
+ @column = lines.last.size + 1
388
396
  else
389
- lines = token.to_manifest.split(LINE_END_RE, -1)
390
- @line_no += lines.length - 1
391
- if lines.length > 1
392
- # if the token renders to multiple lines, set the column state to the
393
- # length of the last line plus 1 (because column numbers are
394
- # 1 indexed)
395
- @column = lines.last.size + 1
396
- else
397
- @column += (lines.last || '').size
398
- end
397
+ @column += (lines.last || '').size
399
398
  end
400
-
401
- token
402
399
  end
403
400
 
404
- def process_string_segments(segments)
405
- return if segments.empty?
401
+ token
402
+ end
406
403
 
407
- if segments.length == 1
408
- tokens << new_token(:STRING, segments[0][1])
409
- return
410
- end
404
+ def process_string_segments(segments)
405
+ return if segments.empty?
411
406
 
412
- pre_segment = segments.delete_at(0)
413
- post_segment = segments.delete_at(-1)
414
-
415
- tokens << new_token(:DQPRE, pre_segment[1])
416
- segments.each do |segment|
417
- case segment[0]
418
- when :INTERP
419
- lexer = PuppetLint::Lexer.new
420
- lexer.tokenise(segment[1])
421
- lexer.tokens.each_with_index do |t, i|
422
- type = i.zero? && t.interpolated_variable? ? :VARIABLE : t.type
423
- tokens << new_token(type, t.value, :raw => t.raw)
424
- end
425
- when :UNENC_VAR
426
- tokens << new_token(:UNENC_VARIABLE, segment[1].gsub(%r{\A\$}, ''))
427
- else
428
- tokens << new_token(:DQMID, segment[1])
407
+ if segments.length == 1
408
+ tokens << new_token(:STRING, segments[0][1])
409
+ return
410
+ end
411
+
412
+ pre_segment = segments.delete_at(0)
413
+ post_segment = segments.delete_at(-1)
414
+
415
+ tokens << new_token(:DQPRE, pre_segment[1])
416
+ segments.each do |segment|
417
+ case segment[0]
418
+ when :INTERP
419
+ lexer = PuppetLint::Lexer.new
420
+ lexer.tokenise(segment[1])
421
+ lexer.tokens.each_with_index do |t, i|
422
+ type = i.zero? && t.interpolated_variable? ? :VARIABLE : t.type
423
+ tokens << new_token(type, t.value, raw: t.raw)
429
424
  end
425
+ when :UNENC_VAR
426
+ tokens << new_token(:UNENC_VARIABLE, segment[1].gsub(%r{\A\$}, ''))
427
+ else
428
+ tokens << new_token(:DQMID, segment[1])
430
429
  end
431
- tokens << new_token(:DQPOST, post_segment[1])
432
430
  end
431
+ tokens << new_token(:DQPOST, post_segment[1])
432
+ end
433
433
 
434
- def process_heredoc_segments(segments)
435
- return if segments.empty?
434
+ def process_heredoc_segments(segments)
435
+ return if segments.empty?
436
436
 
437
- end_tag = segments.delete_at(-1)
437
+ end_tag = segments.delete_at(-1)
438
438
 
439
- if segments.length == 1
440
- tokens << new_token(:HEREDOC, segments[0][1], :raw => "#{segments[0][1]}#{end_tag[1]}")
441
- return
442
- end
439
+ if segments.length == 1
440
+ tokens << new_token(:HEREDOC, segments[0][1], raw: "#{segments[0][1]}#{end_tag[1]}")
441
+ return
442
+ end
443
443
 
444
- pre_segment = segments.delete_at(0)
445
- post_segment = segments.delete_at(-1)
446
-
447
- tokens << new_token(:HEREDOC_PRE, pre_segment[1])
448
- segments.each do |segment|
449
- case segment[0]
450
- when :INTERP
451
- lexer = PuppetLint::Lexer.new
452
- lexer.tokenise(segment[1])
453
- lexer.tokens.each_with_index do |t, i|
454
- type = i.zero? && t.interpolated_variable? ? :VARIABLE : t.type
455
- tokens << new_token(type, t.value, :raw => t.raw)
456
- end
457
- when :UNENC_VAR
458
- tokens << new_token(:UNENC_VARIABLE, segment[1].gsub(%r{\A\$}, ''))
459
- else
460
- tokens << new_token(:HEREDOC_MID, segment[1])
444
+ pre_segment = segments.delete_at(0)
445
+ post_segment = segments.delete_at(-1)
446
+
447
+ tokens << new_token(:HEREDOC_PRE, pre_segment[1])
448
+ segments.each do |segment|
449
+ case segment[0]
450
+ when :INTERP
451
+ lexer = PuppetLint::Lexer.new
452
+ lexer.tokenise(segment[1])
453
+ lexer.tokens.each_with_index do |t, i|
454
+ type = i.zero? && t.interpolated_variable? ? :VARIABLE : t.type
455
+ tokens << new_token(type, t.value, raw: t.raw)
461
456
  end
457
+ when :UNENC_VAR
458
+ tokens << new_token(:UNENC_VARIABLE, segment[1].gsub(%r{\A\$}, ''))
459
+ else
460
+ tokens << new_token(:HEREDOC_MID, segment[1])
462
461
  end
463
- tokens << new_token(:HEREDOC_POST, post_segment[1], :raw => "#{post_segment[1]}#{end_tag[1]}")
464
462
  end
463
+ tokens << new_token(:HEREDOC_POST, post_segment[1], raw: "#{post_segment[1]}#{end_tag[1]}")
465
464
  end
466
465
  end