Skip to content

Commit 95320c2

Browse files
authored
Merge pull request #180 from juliosueiras/features/resource-class-completion
Added completion for resource-like class
2 parents f50d75c + 672bdad commit 95320c2

File tree

2 files changed

+135
-5
lines changed

2 files changed

+135
-5
lines changed

lib/puppet-languageserver/manifest/completion_provider.rb

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ def self.complete(content, line_num, char_num, options = {})
5555
# properities and parameters.
5656

5757
# Try Types first
58-
item_object = PuppetLanguageServer::PuppetHelper.get_type(item.type_name.value)
58+
# The `class` pseudo resource type is actually used to set properties/params for the puppet type
59+
# specified in the resource title.
60+
# Ref: https://puppet.com/docs/puppet/5.3/lang_classes.html#using-resource-like-declarations
61+
item_value = item.type_name.value == 'class' && item.bodies.length == 1 ? item.bodies[0].title.value : item.type_name.value
62+
item_object = PuppetLanguageServer::PuppetHelper.get_type(item_value)
5963
unless item_object.nil?
6064
# Add Parameters
6165
item_object.attributes.select { |_name, data| data[:type] == :param }.each_key do |name|
@@ -66,7 +70,7 @@ def self.complete(content, line_num, char_num, options = {})
6670
'data' => {
6771
'type' => 'resource_parameter',
6872
'param' => name.to_s,
69-
'resource_type' => item.type_name.value
73+
'resource_type' => item_value
7074
}
7175
)
7276
end
@@ -79,15 +83,15 @@ def self.complete(content, line_num, char_num, options = {})
7983
'data' => {
8084
'type' => 'resource_property',
8185
'prop' => name.to_s,
82-
'resource_type' => item.type_name.value
86+
'resource_type' => item_value
8387
}
8488
)
8589
end
8690
# TODO: What about meta parameters?
8791
end
8892
if item_object.nil?
8993
# Try Classes/Defined Types
90-
item_object = PuppetLanguageServer::PuppetHelper.get_class(item.type_name.value)
94+
item_object = PuppetLanguageServer::PuppetHelper.get_class(item_value)
9195
unless item_object.nil?
9296
# Add Parameters
9397
item_object.parameters.each_key do |name|
@@ -98,7 +102,7 @@ def self.complete(content, line_num, char_num, options = {})
98102
'data' => {
99103
'type' => 'resource_class_parameter',
100104
'param' => name.to_s,
101-
'resource_type' => item.type_name.value
105+
'resource_type' => item_value
102106
}
103107
)
104108
end
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
require 'spec_helper'
2+
3+
describe 'PuppetLanguageServer::Manifest::CompletionProvider' do
4+
let(:subject) { PuppetLanguageServer::Manifest::CompletionProvider }
5+
6+
def number_of_completion_item_with_type(completion_list, typename)
7+
(completion_list.items.select { |item| item.data['type'] == typename}).length
8+
end
9+
10+
RSpec::Matchers.define :be_completion_item_with_type do |value|
11+
value = [value] unless value.is_a?(Array)
12+
13+
match { |actual| value.include?(actual.data['type']) }
14+
15+
description do
16+
"be a Completion Item with a data type in the list of #{value}"
17+
end
18+
end
19+
20+
def create_mock_type(parameters = [], properties = [])
21+
object = PuppetLanguageServer::Sidecar::Protocol::PuppetType.new
22+
object.doc = 'mock documentation'
23+
object.attributes = {}
24+
parameters.each { |name| object.attributes[name] = {
25+
:type => :param,
26+
:doc => 'mock parameter doc',
27+
:required? => nil,
28+
:isnamevar? => nil
29+
}}
30+
properties.each { |name| object.attributes[name] = {
31+
:type => :property,
32+
:doc => 'mock parameter doc',
33+
:required? => nil,
34+
:isnamevar? => nil
35+
}}
36+
37+
object
38+
end
39+
40+
before(:all) do
41+
# TODO: This shouldn't really be required, but the PuppetHelper seems to require the default types to be loaded
42+
# in order to query the cache. This is wrong.
43+
wait_for_puppet_loading
44+
end
45+
46+
before(:each) do
47+
# Prepopulate the Object Cache with workspace objects
48+
# Types
49+
list = PuppetLanguageServer::Sidecar::Protocol::PuppetTypeList.new
50+
list << create_mock_type(['param1'], ['prop1']).tap { |i| i.key = :mocktype }
51+
PuppetLanguageServer::PuppetHelper.cache.import_sidecar_list!(list, :type, :workspace)
52+
end
53+
54+
after(:each) do
55+
# Clear out the Object Cache of workspace objects
56+
PuppetLanguageServer::PuppetHelper::Cache::SECTIONS.each do |section|
57+
PuppetLanguageServer::PuppetHelper.cache.import_sidecar_list!([], section, :workspace)
58+
end
59+
end
60+
61+
describe '#complete' do
62+
# https://puppet.com/docs/puppet/latest/lang_classes.html#section-x54-1hk-xhb
63+
context 'given a resource-like declaration of a resource' do
64+
context 'where the title refers to a non-existant class' do
65+
let(:content) { <<-EOT
66+
class { 'does::not::exist':
67+
68+
}
69+
EOT
70+
}
71+
let(:line_num) { 1 }
72+
let(:char_num) { 0 }
73+
74+
it 'should return an empty completion list' do
75+
result = subject.complete(content, line_num, char_num)
76+
expect(result.items.count).to eq(0)
77+
end
78+
end
79+
80+
context 'with a missing title name' do
81+
let(:content) { <<-EOT
82+
class {
83+
84+
}
85+
EOT
86+
}
87+
let(:line_num) { 1 }
88+
let(:char_num) { 0 }
89+
90+
it 'should raise an error' do
91+
expect{ subject.complete(content, line_num, char_num) }.to raise_error(RuntimeError)
92+
end
93+
end
94+
95+
context 'with a known title class' do
96+
let(:content) { <<-EOT
97+
class { 'mocktype':
98+
99+
}
100+
EOT
101+
}
102+
let(:line_num) { 1 }
103+
let(:char_num) { 0 }
104+
let(:expected_types) { ['resource_parameter','resource_property'] }
105+
106+
it 'should return only parameter and property items' do
107+
result = subject.complete(content, line_num, char_num)
108+
109+
result.items.each do |item|
110+
expect(item).to be_completion_item_with_type(expected_types)
111+
end
112+
end
113+
114+
it 'should return the parameters of the class' do
115+
result = subject.complete(content, line_num, char_num)
116+
expect(number_of_completion_item_with_type(result, 'resource_parameter')).to eq(1)
117+
end
118+
119+
it 'should return the properties of the class' do
120+
result = subject.complete(content, line_num, char_num)
121+
expect(number_of_completion_item_with_type(result, 'resource_property')).to eq(1)
122+
end
123+
end
124+
end
125+
end
126+
end

0 commit comments

Comments
 (0)