puppet-lint-param_comment-check 0.1.4 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 760c2ecbb41952244ece53d7fddafcc91f322300b512a65dfc4d5ab7b5622636
4
- data.tar.gz: 187d476c9e3418c03935d00ddf84fd9c9618cd8ac4a14a391e0046f68f92221f
3
+ metadata.gz: 8c928aed3decd05d2876d4b37ecd564e069317d4b918bf49c36561bac2aa8878
4
+ data.tar.gz: 7122d1353312ff519d240c89e9e6e538cc7cd6453451ba8fa8c3cc2a90b86e64
5
5
  SHA512:
6
- metadata.gz: 8396f55b48c7cd1e82f66855eb950c2c1fd4e908423625a262e6ba11496d2cd3b9c90931c66deb97efba5d706502416e71ef4ae47f7d459b5c0fcf24d7b86ef4
7
- data.tar.gz: '08c1d478a70c0a204805844aa0ad1724ee7a371852c3f7059596204d3c62f89d9044fa2cf44b26b6df2731331f371765b3cdf86de148ecf5cab88216336dea93'
6
+ metadata.gz: 883d3841875fb24bc60cdf566a22e917a0a42c9f127739d82c22923eb092b39dbd3e804ec8d6392a04102b9f114142c48f9d98093f24d807c8177f3689b909c5
7
+ data.tar.gz: 4d76a9e6d9a79ed2989495a47456a8148661b3363cbf5d6c590e0f5ec028d8156995165f7991b5b21f5305441bdfd3e1d698bbe5c315ea64eeffeb03ef35b32a
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../../puppet-lint-param_comment-check/param_workflow'
4
3
  require_relative '../../puppet-lint-param_comment-check/param_comments'
4
+ require_relative '../../puppet-lint-param_comment-check/param'
5
5
 
6
6
  # The empty data of a parameter
7
7
  EMPTY_PARAM = {
@@ -18,52 +18,23 @@ EMPTY_PARAM = {
18
18
  # @return The head comments
19
19
  def get_comments(tokens, token_start)
20
20
  comments = []
21
- token_pointer = token_start
21
+ token_pointer = token_start - 1
22
22
  while token_pointer >= 0
23
- comments.append(tokens[token_pointer]) if tokens[token_pointer].type == :COMMENT
24
- token_pointer -= 1
25
- end
26
- comments.reverse
27
- end
23
+ break unless %i[COMMENT NEWLINE].include? tokens[token_pointer].type
28
24
 
29
- # Analyze a parameter token
30
- #
31
- # @param token The token to analyze
32
- # @param current_param the data object for the currently analyzed parameter
33
- def analyze_param_token(token, current_param)
34
- # noinspection RubyCaseWithoutElseBlockInspection
35
- case token.type
36
- when :VARIABLE
37
- current_param[:name] = token.value
38
- when :CLASSREF, :TYPE
39
- current_param[:type] = token.value
40
- when :EQUALS
41
- current_param[:has_default] = true
42
- current_param[:default] = token.next_token.value
25
+ comments.append(tokens[token_pointer])
26
+ token_pointer -= 1
43
27
  end
44
- current_param
28
+ comments.reject { |comment| comment.type == :NEWLINE }.reverse
45
29
  end
46
30
 
47
31
  # Analyze the parameters of a class or a defined type
48
32
  #
49
33
  # @param param_tokens The parameter tokens to analyze
50
- def analyze_params(param_tokens) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
51
- params = []
52
- current_param = EMPTY_PARAM.dup
53
- brackets = 0
54
- param_tokens.reject { |token| %i[WHITESPACE NEWLINE INDENT].include? token.type }.each do |token|
55
- brackets += 1 if %i[LBRACK LBRACE].include? token.type
56
- brackets -= 1 if %i[RBRACK RBRACE].include? token.type
57
- next unless brackets.zero?
58
-
59
- current_param = analyze_param_token(token, current_param) unless token.type == :COMMA
60
- if token.type == :COMMA
61
- params.append(current_param)
62
- current_param = EMPTY_PARAM.dup
63
- end
64
- end
65
- params.append(current_param) unless current_param[:name] == ''
66
- params
34
+ def analyze_params(param_tokens)
35
+ param_workflow = Param.new
36
+ param_workflow.process(param_tokens)
37
+ param_workflow.params
67
38
  end
68
39
 
69
40
  # Find, which parameters in the long list are missing in the short list and return their names
@@ -141,10 +112,14 @@ PuppetLint.new_check(:param_comment) do # rubocop:disable Metrics/BlockLength
141
112
  end
142
113
 
143
114
  # Check class or defined type indexes
144
- def check_indexes(indexes)
115
+ def check_indexes(indexes) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
145
116
  indexes.each do |index|
146
117
  comments = get_comments(tokens, index[:start])
147
- params = analyze_params(index[:param_tokens])
118
+ begin
119
+ params = analyze_params(index[:param_tokens])
120
+ rescue InvalidTokenForState, InvalidDefaultForOptional => e
121
+ return warn(e.message, e.token.line, e.token.column)
122
+ end
148
123
  return false unless check_comments(comments)
149
124
  return false unless check_parameters_count(params)
150
125
 
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'param_workflow'
4
+
5
+ PARAM_TYPE_ENUM = {
6
+ mandatory: 1,
7
+ with_default: 2,
8
+ optional: 3
9
+ }.freeze
10
+
11
+ # The empty data of a parameter
12
+ EMPTY_PARAM = {
13
+ name: '',
14
+ type: '',
15
+ default: [],
16
+ param_type: PARAM_TYPE_ENUM[:mandatory]
17
+ }.freeze
18
+
19
+ # Comment received in an invalid state
20
+ class InvalidTokenForState < StandardError
21
+ def initialize(token, state)
22
+ @token = token
23
+ @state = state
24
+ super "Can not process the token '#{@token.value.strip}' in the state #{@state}"
25
+ end
26
+
27
+ attr_reader :token
28
+ end
29
+
30
+ # An optional parameter does not have "undef" as the default
31
+ class InvalidDefaultForOptional < StandardError
32
+ def initialize(token, default_value)
33
+ @token = token
34
+ super "Invalid value '#{default_value}' for an parameter of type Optional. undef is required"
35
+ end
36
+
37
+ attr_reader :token
38
+ end
39
+
40
+ # A helper to analyze parameter comments using the ParamWorkflow fsm
41
+ class Param
42
+ def initialize
43
+ @workflow = ParamWorkflow.new(self)
44
+
45
+ reset
46
+ end
47
+
48
+ def reset
49
+ @params = []
50
+ @in_default = false
51
+ @default_tokens = []
52
+ @in_type = false
53
+ @type_tokens = []
54
+ @current_param = EMPTY_PARAM.dup
55
+ @current_token = nil
56
+ @workflow.restore!(:start)
57
+ end
58
+
59
+ # Walk through every parameter and transition the workflow fsm accordingly
60
+ #
61
+ # @param tokens A list of parameter tokens
62
+ def process(tokens) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
63
+ reset
64
+ brackets = 0
65
+ tokens.reject { |token| %i[NEWLINE INDENT].include? token.type }.each do |token| # rubocop:disable Metrics/BlockLength
66
+ @current_token = token
67
+ case token.type
68
+ when :TYPE
69
+ if @in_default
70
+ @default_tokens.append(token)
71
+ next
72
+ end
73
+ @workflow.got_type unless @in_type
74
+ @in_type = true
75
+ @type_tokens.append(token)
76
+ when :VARIABLE
77
+ @workflow.got_name(token, @type_tokens) unless @in_default
78
+ @in_type = false unless @in_default
79
+ @type_tokens = [] unless @in_default
80
+ @default_tokens.append(token) if @in_default
81
+ when :EQUALS
82
+ @in_default = true
83
+ when :COMMA
84
+ @workflow.got_end(@default_tokens) unless @in_type || brackets.positive?
85
+ @default_tokens = [] unless @in_type && brackets.positive?
86
+ @in_default = false unless @in_type && brackets.positive?
87
+ @type_tokens.append(token) if @in_type
88
+ when :LBRACE, :LBRACK
89
+ brackets += 1
90
+ @type_tokens.append(token) if @in_type
91
+ @default_tokens.append(token) if @in_default
92
+ when :RBRACE, :RBRACK
93
+ brackets -= 1
94
+ @type_tokens.append(token) if @in_type
95
+ @default_tokens.append(token) if @in_default
96
+ else
97
+ @type_tokens.append(token) if @in_type
98
+ @default_tokens.append(token) if @in_default
99
+ end
100
+ end
101
+ @workflow.got_end(@default_tokens) unless @workflow.current == :start
102
+ end
103
+
104
+ def got_name_trigger(_, token, type_tokens)
105
+ @current_param[:type] = type_tokens.map(&:value).join('')
106
+ if !@type_tokens.empty? && @type_tokens[0].value == 'OPTIONAL'
107
+ @current_param[:param_type] = PARAM_TYPE_ENUM[:optional]
108
+ end
109
+ @current_param[:name] = token.value
110
+ end
111
+
112
+ def got_end_trigger(_, default_tokens) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
113
+ raise InvalidDefaultForOptional if @current_param[:param_type] == PARAM_TYPE_ENUM[:optional] &&
114
+ !default_tokens.empty? &&
115
+ default_tokens[0].value != 'undef'
116
+
117
+ @current_param[:default] = @default_tokens.map(&:value).join('') unless @default_tokens.empty?
118
+ @current_param[:param_type] = PARAM_TYPE_ENUM[:with_default] unless
119
+ @current_param[:param_type] == PARAM_TYPE_ENUM[:optional] || default_tokens.empty?
120
+ @params.append(@current_param)
121
+ @current_param = EMPTY_PARAM.dup
122
+ @in_default, @in_type = false
123
+ end
124
+
125
+ # Called when an invalid state transition would happen
126
+ def invalid_state
127
+ raise InvalidTokenForState.new(@current_token, @workflow.current)
128
+ end
129
+
130
+ # The list of analyzed parameters in the comments
131
+ attr_reader :params
132
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'param_comments_workflow'
4
+
3
5
  # The empty data of a parameter
4
6
  EMPTY_PARAM_COMMENT = {
5
7
  name: '',
@@ -56,19 +58,25 @@ end
56
58
  # A helper to analyze parameter comments using the ParamWorkflow fsm
57
59
  class ParamComments
58
60
  def initialize
59
- @workflow = ParamWorkflow.new(self)
61
+ @workflow = ParamCommentsWorkflow.new(self)
62
+
63
+ reset
64
+ end
60
65
 
66
+ def reset
61
67
  @current_param = nil
62
68
  @current_option = nil
63
69
  @in_option = false
64
70
  @params_have_started = false
65
71
  @params = []
72
+ @workflow.restore!(:start)
66
73
  end
67
74
 
68
75
  # Walk through every comment and transition the workflow fsm accordingly
69
76
  #
70
77
  # @param comments A list of Comment tokens appearing before the class/defined type header
71
- def process(comments) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
78
+ def process(comments) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity,Metrics/AbcSize
79
+ reset
72
80
  @current_comment = PuppetLint::Lexer::Token.new(:COMMENT, '', 1, 1)
73
81
  comments.each do |comment|
74
82
  @current_comment = comment
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'finite_machine'
4
+
5
+ # A finite state machine working through the expected parameter comments
6
+ class ParamCommentsWorkflow < FiniteMachine::Definition
7
+ initial :start
8
+
9
+ event :got_header, from: :start, to: :awaiting_description
10
+ event :got_header, from: :awaiting_header, to: :awaiting_description
11
+ event :got_description, from: :awaiting_description, to: :awaiting_separator
12
+ event :got_separator, from: :awaiting_separator, to: :awaiting_header
13
+
14
+ # for multi-line descriptions
15
+ event :got_description, from: :awaiting_separator, to: :awaiting_separator
16
+
17
+ # handling options
18
+ event :got_option_header, from: :awaiting_separator, to: :awaiting_option_description
19
+ event :got_option_description, from: :awaiting_option_description, to: :awaiting_separator
20
+
21
+ # for separators inside descriptions
22
+ event :got_description, from: :awaiting_header, to: :awaiting_separator
23
+ event :got_option_description, from: :awaiting_separator, to: :awaiting_separator
24
+
25
+ on_before(:got_header) { |event, comment| target.got_header_trigger(event, comment) }
26
+ on_before(:got_description) { |event, comment| target.got_description_trigger(event, comment) }
27
+ on_before(:got_option_description) { |event, comment| target.got_description_trigger(event, comment) }
28
+ on_before(:got_option_header) { |event, comment| target.got_option_header_trigger(event, comment) }
29
+
30
+ handle FiniteMachine::InvalidStateError, with: -> { target.invalid_state }
31
+ end
@@ -2,30 +2,22 @@
2
2
 
3
3
  require 'finite_machine'
4
4
 
5
- # A finite state machine working through the expected parameter comments
5
+ # A finite state machine working through the expected parameter tokens
6
6
  class ParamWorkflow < FiniteMachine::Definition
7
7
  initial :start
8
8
 
9
- event :got_header, from: :start, to: :awaiting_description
10
- event :got_header, from: :awaiting_header, to: :awaiting_description
11
- event :got_description, from: :awaiting_description, to: :awaiting_separator
12
- event :got_separator, from: :awaiting_separator, to: :awaiting_header
9
+ event :got_type, from: :start, to: :awaiting_name
10
+ event :got_name, from: :awaiting_name, to: :awaiting_default
13
11
 
14
- # for multi-line descriptions
15
- event :got_description, from: :awaiting_separator, to: :awaiting_separator
12
+ # For mandatory parameters
13
+ event :got_end, from: :awaiting_name, to: :start
14
+ event :got_end, from: :awaiting_default, to: :start
16
15
 
17
- # handling options
18
- event :got_option_header, from: :awaiting_separator, to: :awaiting_option_description
19
- event :got_option_description, from: :awaiting_option_description, to: :awaiting_separator
16
+ # For typeless parameters
17
+ event :got_name, from: :start, to: :awaiting_default
20
18
 
21
- # for separators inside descriptions
22
- event :got_description, from: :awaiting_header, to: :awaiting_separator
23
- event :got_option_description, from: :awaiting_separator, to: :awaiting_separator
24
-
25
- on_before(:got_header) { |event, comment| target.got_header_trigger(event, comment) }
26
- on_before(:got_description) { |event, comment| target.got_description_trigger(event, comment) }
27
- on_before(:got_option_description) { |event, comment| target.got_description_trigger(event, comment) }
28
- on_before(:got_option_header) { |event, comment| target.got_option_header_trigger(event, comment) }
19
+ on_before(:got_name) { |event, token, type_tokens| target.got_name_trigger(event, token, type_tokens) }
20
+ on_before(:got_end) { |event, default_tokens| target.got_end_trigger(event, default_tokens) }
29
21
 
30
22
  handle FiniteMachine::InvalidStateError, with: -> { target.invalid_state }
31
23
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require_relative '../../spec_helper'
4
4
 
5
+ # rubocop:disable Metrics/BlockLength
5
6
  describe 'param_comment' do
6
7
  context 'valid code' do
7
8
  let(:code) do
@@ -121,6 +122,38 @@ describe 'param_comment' do
121
122
  end
122
123
  end
123
124
 
125
+ context 'valid code with multiple classes' do
126
+ let(:code) do
127
+ <<~CODE
128
+ # @summary
129
+ # some class
130
+ #
131
+ # @param mandatory
132
+ # A mandatory parameter
133
+ # with two lines
134
+ class my_class (
135
+ String $mandatory,
136
+ ) {}
137
+
138
+ # @summary
139
+ # some other class
140
+ #
141
+ # @see something
142
+ #
143
+ # @param mandatory
144
+ # A mandatory parameter
145
+ # with two lines
146
+ class my_other_class (
147
+ String $mandatory,
148
+ ) {}
149
+ CODE
150
+ end
151
+
152
+ it 'should not detect any problems' do
153
+ expect(problems).to have(0).problems
154
+ end
155
+ end
156
+
124
157
  context 'code with missing parameter comment' do
125
158
  let(:code) do
126
159
  <<~CODE
@@ -223,9 +256,11 @@ describe 'param_comment' do
223
256
  end
224
257
 
225
258
  it 'should create a warning' do
226
- expect(problems).to contain_warning('Can not process the comment \'@param withdefault\' in the state awaiting_separator')
227
- .on_line(3)
228
- .in_column(1)
259
+ expect(problems).to contain_warning(
260
+ 'Can not process the comment \'@param withdefault\' in the state awaiting_separator'
261
+ )
262
+ .on_line(3)
263
+ .in_column(1)
229
264
  end
230
265
  end
231
266
 
@@ -244,9 +279,11 @@ describe 'param_comment' do
244
279
  end
245
280
 
246
281
  it 'should create a warning' do
247
- expect(problems).to contain_warning('Invalid param or hash option header: @param mandatory A mandatory parameter')
248
- .on_line(1)
249
- .in_column(1)
282
+ expect(problems).to contain_warning(
283
+ 'Invalid param or hash option header: @param mandatory A mandatory parameter'
284
+ )
285
+ .on_line(1)
286
+ .in_column(1)
250
287
  end
251
288
  end
252
289
 
@@ -289,9 +326,11 @@ describe 'param_comment' do
289
326
  end
290
327
 
291
328
  it 'should create a warning' do
292
- expect(problems).to contain_warning('Option references wrong hash @option mandatry [Boolean] :some_option')
293
- .on_line(3)
294
- .in_column(1)
329
+ expect(problems).to contain_warning(
330
+ 'Option references wrong hash @option mandatry [Boolean] :some_option'
331
+ )
332
+ .on_line(3)
333
+ .in_column(1)
295
334
  end
296
335
  end
297
336
 
@@ -315,10 +354,10 @@ describe 'param_comment' do
315
354
 
316
355
  it 'should create a warning' do
317
356
  expect(problems).to contain_warning(
318
- 'Can not process the comment \'@option mandatory [Boolean] :some_option\' in the state awaiting_header'
319
- )
320
- .on_line(4)
321
- .in_column(1)
357
+ 'Can not process the comment \'@option mandatory [Boolean] :some_option\' in the state awaiting_header'
358
+ )
359
+ .on_line(4)
360
+ .in_column(1)
322
361
  end
323
362
  end
324
363
 
@@ -340,10 +379,10 @@ describe 'param_comment' do
340
379
 
341
380
  it 'should create a warning' do
342
381
  expect(problems).to contain_warning(
343
- 'Invalid param or hash option header: @option mandatory [Boolean] :some_option An option'
344
- )
345
- .on_line(3)
346
- .in_column(1)
382
+ 'Invalid param or hash option header: @option mandatory [Boolean] :some_option An option'
383
+ )
384
+ .on_line(3)
385
+ .in_column(1)
347
386
  end
348
387
  end
349
388
 
@@ -369,10 +408,10 @@ describe 'param_comment' do
369
408
 
370
409
  it 'should create a warning' do
371
410
  expect(problems).to contain_warning(
372
- 'Can not process the comment \'@param second\' in the state awaiting_separator'
373
- )
374
- .on_line(5)
375
- .in_column(1)
411
+ 'Can not process the comment \'@param second\' in the state awaiting_separator'
412
+ )
413
+ .on_line(5)
414
+ .in_column(1)
376
415
  end
377
416
  end
378
417
 
@@ -394,3 +433,4 @@ describe 'param_comment' do
394
433
  end
395
434
  end
396
435
  end
436
+ # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet-lint-param_comment-check
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dennis Ploeger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-31 00:00:00.000000000 Z
11
+ date: 2022-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: finite_machine
@@ -131,7 +131,9 @@ extra_rdoc_files: []
131
131
  files:
132
132
  - LICENSE
133
133
  - README.md
134
+ - lib/puppet-lint-param_comment-check/param.rb
134
135
  - lib/puppet-lint-param_comment-check/param_comments.rb
136
+ - lib/puppet-lint-param_comment-check/param_comments_workflow.rb
135
137
  - lib/puppet-lint-param_comment-check/param_workflow.rb
136
138
  - lib/puppet-lint/plugins/check_param_comment.rb
137
139
  - spec/puppet-lint/plugins/check_param_comment_spec.rb