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.
- checksums.yaml +4 -4
- data/.rubocop.yml +522 -0
- data/lib/puppet-lint/bin.rb +71 -6
- data/lib/puppet-lint/checkplugin.rb +43 -9
- data/lib/puppet-lint/checks.rb +16 -16
- data/lib/puppet-lint/configuration.rb +134 -134
- data/lib/puppet-lint/data.rb +28 -28
- data/lib/puppet-lint/lexer/string_slurper.rb +138 -140
- data/lib/puppet-lint/lexer/token.rb +188 -190
- data/lib/puppet-lint/lexer.rb +416 -417
- data/lib/puppet-lint/monkeypatches.rb +1 -1
- data/lib/puppet-lint/optparser.rb +5 -1
- data/lib/puppet-lint/plugins/check_classes/arrow_on_right_operand_line.rb +6 -4
- data/lib/puppet-lint/plugins/check_classes/autoloader_layout.rb +5 -3
- data/lib/puppet-lint/plugins/check_classes/class_inherits_from_params_class.rb +6 -4
- data/lib/puppet-lint/plugins/check_classes/code_on_top_scope.rb +5 -3
- data/lib/puppet-lint/plugins/check_classes/inherits_across_namespaces.rb +5 -3
- data/lib/puppet-lint/plugins/check_classes/names_containing_dash.rb +5 -3
- data/lib/puppet-lint/plugins/check_classes/names_containing_uppercase.rb +7 -5
- data/lib/puppet-lint/plugins/check_classes/nested_classes_or_defines.rb +5 -3
- data/lib/puppet-lint/plugins/check_classes/parameter_order.rb +7 -4
- data/lib/puppet-lint/plugins/check_classes/right_to_left_relationship.rb +5 -3
- data/lib/puppet-lint/plugins/check_classes/variable_scope.rb +15 -13
- data/lib/puppet-lint/plugins/check_comments/slash_comments.rb +9 -7
- data/lib/puppet-lint/plugins/check_comments/star_comments.rb +10 -8
- data/lib/puppet-lint/plugins/check_conditionals/case_without_default.rb +6 -4
- data/lib/puppet-lint/plugins/check_conditionals/selector_inside_resource.rb +5 -3
- data/lib/puppet-lint/plugins/check_documentation/documentation.rb +7 -3
- data/lib/puppet-lint/plugins/check_nodes/unquoted_node_name.rb +15 -11
- data/lib/puppet-lint/plugins/check_resources/duplicate_params.rb +5 -3
- data/lib/puppet-lint/plugins/check_resources/ensure_first_param.rb +8 -5
- data/lib/puppet-lint/plugins/check_resources/ensure_not_symlink_target.rb +11 -8
- data/lib/puppet-lint/plugins/check_resources/file_mode.rb +14 -9
- data/lib/puppet-lint/plugins/check_resources/unquoted_file_mode.rb +11 -6
- data/lib/puppet-lint/plugins/check_resources/unquoted_resource_title.rb +6 -4
- data/lib/puppet-lint/plugins/check_strings/double_quoted_strings.rb +12 -7
- data/lib/puppet-lint/plugins/check_strings/only_variable_string.rb +8 -6
- data/lib/puppet-lint/plugins/check_strings/puppet_url_without_modules.rb +14 -8
- data/lib/puppet-lint/plugins/check_strings/quoted_booleans.rb +11 -7
- data/lib/puppet-lint/plugins/check_strings/single_quote_string_with_variables.rb +11 -6
- data/lib/puppet-lint/plugins/check_strings/variables_not_enclosed.rb +12 -8
- data/lib/puppet-lint/plugins/check_variables/variable_contains_dash.rb +11 -7
- data/lib/puppet-lint/plugins/check_variables/variable_is_lowercase.rb +11 -7
- data/lib/puppet-lint/plugins/check_whitespace/140chars.rb +3 -8
- data/lib/puppet-lint/plugins/check_whitespace/2sp_soft_tabs.rb +10 -8
- data/lib/puppet-lint/plugins/check_whitespace/80chars.rb +3 -8
- data/lib/puppet-lint/plugins/check_whitespace/arrow_alignment.rb +10 -8
- data/lib/puppet-lint/plugins/check_whitespace/hard_tabs.rb +11 -7
- data/lib/puppet-lint/plugins/check_whitespace/line_length.rb +29 -0
- data/lib/puppet-lint/plugins/check_whitespace/trailing_whitespace.rb +13 -7
- data/lib/puppet-lint/plugins.rb +63 -61
- data/lib/puppet-lint/report/github.rb +17 -0
- data/lib/puppet-lint/report/sarif_template.json +63 -0
- data/lib/puppet-lint/tasks/puppet-lint.rb +84 -83
- data/lib/puppet-lint/tasks/release_test.rb +4 -1
- data/lib/puppet-lint/version.rb +1 -1
- data/lib/puppet-lint.rb +27 -12
- data/spec/acceptance/puppet_lint_spec.rb +46 -0
- data/spec/spec_helper.rb +92 -91
- data/spec/spec_helper_acceptance.rb +6 -0
- data/spec/spec_helper_acceptance_local.rb +38 -0
- data/spec/{puppet-lint → unit/puppet-lint}/bin_spec.rb +79 -35
- data/spec/{puppet-lint → unit/puppet-lint}/checks_spec.rb +36 -36
- data/spec/unit/puppet-lint/configuration_spec.rb +88 -0
- data/spec/{puppet-lint → unit/puppet-lint}/data_spec.rb +6 -3
- data/spec/{puppet-lint → unit/puppet-lint}/ignore_overrides_spec.rb +17 -17
- data/spec/{puppet-lint → unit/puppet-lint}/lexer/string_slurper_spec.rb +128 -128
- data/spec/{puppet-lint → unit/puppet-lint}/lexer/token_spec.rb +1 -1
- data/spec/{puppet-lint → unit/puppet-lint}/lexer_spec.rb +653 -671
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/arrow_on_right_operand_line_spec.rb +16 -16
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/autoloader_layout_spec.rb +13 -13
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/class_inherits_from_params_class_spec.rb +3 -3
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/code_on_top_scope_spec.rb +4 -4
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/inherits_across_namespaces_spec.rb +4 -4
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/name_contains_uppercase_spec.rb +10 -10
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/names_containing_dash_spec.rb +7 -7
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/nested_classes_or_defines_spec.rb +7 -7
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/parameter_order_spec.rb +9 -9
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/right_to_left_relationship_spec.rb +3 -3
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_classes/variable_scope_spec.rb +25 -25
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_comments/slash_comments_spec.rb +7 -7
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_comments/star_comments_spec.rb +13 -13
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_conditionals/case_without_default_spec.rb +10 -10
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_conditionals/selector_inside_resource_spec.rb +3 -3
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_documentation/documentation_spec.rb +8 -8
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_nodes/unquoted_node_name_spec.rb +24 -24
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/duplicate_params_spec.rb +9 -9
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/ensure_first_param_spec.rb +19 -19
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/ensure_not_symlink_target_spec.rb +10 -10
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/file_mode_spec.rb +40 -40
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/unquoted_file_mode_spec.rb +20 -20
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_resources/unquoted_resource_title_spec.rb +24 -24
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/double_quoted_strings_spec.rb +27 -27
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/only_variable_string_spec.rb +18 -18
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/puppet_url_without_modules_spec.rb +9 -9
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/quoted_booleans_spec.rb +22 -22
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/single_quote_string_with_variables_spec.rb +2 -2
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_strings/variables_not_enclosed_spec.rb +21 -21
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_variables/variable_contains_dash_spec.rb +6 -6
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_variables/variable_is_lowercase_spec.rb +7 -7
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/140chars_spec.rb +5 -5
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/2sp_soft_tabs_spec.rb +2 -2
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/80chars_spec.rb +6 -6
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/arrow_alignment_spec.rb +127 -127
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/hard_tabs_spec.rb +7 -7
- data/spec/{puppet-lint → unit/puppet-lint}/plugins/check_whitespace/trailing_whitespace_spec.rb +15 -15
- data/spec/unit/puppet-lint/puppet-lint_spec.rb +18 -0
- metadata +63 -119
- data/CHANGELOG.md +0 -33
- data/HISTORY.md +0 -1130
- data/spec/puppet-lint/configuration_spec.rb +0 -66
- data/spec/puppet-lint_spec.rb +0 -16
data/lib/puppet-lint/lexer.rb
CHANGED
@@ -6,461 +6,460 @@ require 'set'
|
|
6
6
|
require 'puppet-lint/lexer/token'
|
7
7
|
require 'puppet-lint/lexer/string_slurper'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
34
|
-
|
35
|
-
end
|
33
|
+
def to_s
|
34
|
+
"PuppetLint::LexerError: Line:#{line_no} Column: #{column} Reason: #{reason}"
|
36
35
|
end
|
36
|
+
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
46
|
+
def self.heredoc_queue
|
47
|
+
@heredoc_queue ||= []
|
48
|
+
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
def heredoc_queue
|
51
|
+
self.class.heredoc_queue
|
52
|
+
end
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
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
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
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
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
319
|
+
i += length
|
323
320
|
end
|
324
321
|
|
325
|
-
|
326
|
-
|
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
|
-
|
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
|
-
|
337
|
-
end
|
334
|
+
return true if prev_token.nil?
|
338
335
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
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
|
-
|
383
|
+
token.raw = opts[:raw] if opts[:raw]
|
384
384
|
|
385
|
-
|
386
|
-
|
387
|
-
|
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
|
-
|
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
|
-
|
405
|
-
|
401
|
+
token
|
402
|
+
end
|
406
403
|
|
407
|
-
|
408
|
-
|
409
|
-
return
|
410
|
-
end
|
404
|
+
def process_string_segments(segments)
|
405
|
+
return if segments.empty?
|
411
406
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
tokens << new_token(
|
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
|
-
|
435
|
-
|
434
|
+
def process_heredoc_segments(segments)
|
435
|
+
return if segments.empty?
|
436
436
|
|
437
|
-
|
437
|
+
end_tag = segments.delete_at(-1)
|
438
438
|
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
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
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
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
|