Skip to content

Commit 7986bbb

Browse files
committed
Add method to check if package is installed
1 parent 64ebc3b commit 7986bbb

File tree

3 files changed

+201
-2
lines changed

3 files changed

+201
-2
lines changed

autoload/composer.vim

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,29 @@ function! s:project_query(key, ...) dict abort
184184
return s:get_nested(self.json(), a:key, default)
185185
endfunction
186186

187+
""
188+
" Determine if {package} is installed with optional [version] constraint.
189+
"
190+
" composer#project().is_installed('my/package', '>=', '1.2.0')
191+
"
192+
function! s:project_is_installed(package, ...) dict abort
193+
let comparator = get(a:000, 0, '')
194+
let ver = get(a:000, 1, '')
195+
let packages = self.packages_installed()
196+
197+
call filter(packages, {idx, package -> package.name == a:package})
198+
199+
if len(packages) < 1
200+
return v:false
201+
endif
202+
203+
if len(ver) < 1
204+
return v:true
205+
endif
206+
207+
return composer#semver#compare(packages[0].version_normalized, comparator, ver)
208+
endfunction
209+
187210
""
188211
" Get Dict of packages required in composer.json, where the keys represent
189212
" package names and the values represent the version constraints.
@@ -194,7 +217,7 @@ endfunction
194217
""
195218
" Get Dict of packages installed in current project from installed.json.
196219
function! s:project_packages_installed() dict abort
197-
return self.installed_json()
220+
return deepcopy(self.installed_json())
198221
endfunction
199222

200223
""
@@ -270,7 +293,7 @@ function! s:project_search(keyword) dict abort
270293
return self.cache.get(cache)
271294
endfunction
272295

273-
call s:add_methods('project', ['json', 'lock', 'installed_json', 'query', 'scripts', 'makeprg', 'exec', 'commands', 'packages_required', 'packages_installed', 'search'])
296+
call s:add_methods('project', ['json', 'lock', 'installed_json', 'query', 'is_installed', 'scripts', 'makeprg', 'exec', 'commands', 'packages_required', 'packages_installed', 'search'])
274297

275298
let s:cache_prototype = {'cache': {}}
276299

autoload/composer/semver.vim

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
" autoload/composer/semver.vim - Semver parsing and comparison
2+
" Maintainer: Noah Frederick
3+
4+
""
5+
" @private
6+
" Parse semver version string into object.
7+
function! composer#semver#parse(version_string) abort
8+
let semver = {}
9+
let parts = matchlist(a:version_string, '\v^(\d+)%(.(\d+)%(.(\d+))?)?')
10+
11+
let semver.major = get(parts, 1, '')
12+
let semver.minor = get(parts, 2, '')
13+
let semver.patch = get(parts, 3, '')
14+
15+
return semver
16+
endfunction
17+
18+
""
19+
" @private
20+
" Compare semver version strings.
21+
function! composer#semver#compare(a, comparator, b) abort
22+
if !has_key(s:comparators, a:comparator)
23+
echoerr 'Composer semver: ' . a:comparator . ' is not a valid comparator'
24+
return v:false
25+
endif
26+
27+
let a = composer#semver#parse(a:a)
28+
let b = composer#semver#parse(a:b)
29+
30+
if funcref(s:comparators[a:comparator], [a, b])() is v:false
31+
return v:false
32+
endif
33+
34+
return v:true
35+
endfunction
36+
37+
let s:comparators = {
38+
\ '==': 's:is_equal',
39+
\ '!=': 's:is_not_equal',
40+
\ '>': 's:is_greater_than',
41+
\ '>=': 's:is_greater_than_or_equal',
42+
\ '<': 's:is_less_than',
43+
\ '<=': 's:is_less_than_or_equal',
44+
\ }
45+
46+
function! s:is_equal(a, b) abort
47+
if a:a.major != a:b.major
48+
return v:false
49+
endif
50+
51+
if empty(a:a.minor) || empty(a:b.minor)
52+
return v:true
53+
endif
54+
55+
if a:a.minor != a:b.minor
56+
return v:false
57+
endif
58+
59+
if empty(a:a.patch) || empty(a:b.patch)
60+
return v:true
61+
endif
62+
63+
if a:a.patch != a:b.patch
64+
return v:false
65+
endif
66+
67+
return v:true
68+
endfunction
69+
70+
function! s:is_not_equal(a, b) abort
71+
return s:is_equal(a:a, a:b) ? v:false : v:true
72+
endfunction
73+
74+
function! s:is_greater_than(a, b) abort
75+
if s:is_equal(a:a, a:b)
76+
return v:false
77+
endif
78+
79+
if a:a.major > a:b.major
80+
return v:true
81+
elseif a:a.major == a:b.major
82+
if a:a.minor > a:b.minor
83+
return v:true
84+
elseif a:a.minor == a:b.minor
85+
return a:a.patch > a:b.patch
86+
endif
87+
endif
88+
89+
return v:false
90+
endfunction
91+
92+
function! s:is_less_than(a, b) abort
93+
return ((s:is_greater_than(a:a, a:b) || s:is_equal(a:a, a:b))) ? v:false : v:true
94+
endfunction
95+
96+
function! s:is_greater_than_or_equal(a, b)
97+
return ((s:is_greater_than(a:a, a:b) || s:is_equal(a:a, a:b))) ? v:true : v:false
98+
endfunction
99+
100+
function! s:is_less_than_or_equal(a, b)
101+
return ((s:is_less_than(a:a, a:b) || s:is_equal(a:a, a:b))) ? v:true : v:false
102+
endfunction
103+
104+
" vim: fdm=marker:sw=2:sts=2:et

t/semver.vim

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
" t/semver.vim - Semver parsing and comparison tests
2+
" Maintainer: Noah Frederick
3+
4+
describe 'composer#semver#parse()'
5+
it 'parses the major version'
6+
Expect composer#semver#parse('1.0.0').major is '1'
7+
Expect composer#semver#parse('2.0').major is '2'
8+
Expect composer#semver#parse('3').major is '3'
9+
end
10+
11+
it 'parses the minor version'
12+
Expect composer#semver#parse('1.1.0').minor is '1'
13+
Expect composer#semver#parse('2.2').minor is '2'
14+
Expect composer#semver#parse('3').minor is ''
15+
end
16+
17+
it 'parses the patch version'
18+
Expect composer#semver#parse('1.0.1').patch is '1'
19+
Expect composer#semver#parse('2.0').patch is ''
20+
Expect composer#semver#parse('3').patch is ''
21+
end
22+
end
23+
24+
describe 'composer#semver#compare()'
25+
it 'fails with invalid comparator'
26+
Expect expr { composer#semver#compare('1.0.1', 'blah', '1.2.0').patch } to_throw 'blah is not a valid comparator'
27+
end
28+
29+
it 'compares with =='
30+
Expect composer#semver#compare('1.0.1', '==', '1.0.1') is v:true
31+
Expect composer#semver#compare('1.4.1', '==', '1.0.1') is v:false
32+
Expect composer#semver#compare('1.0', '==', '1.0') is v:true
33+
Expect composer#semver#compare('1', '==', '1') is v:true
34+
Expect composer#semver#compare('1', '==', '1.6.0') is v:true
35+
end
36+
37+
it 'compares with !='
38+
Expect composer#semver#compare('1.4.1', '!=', '1.0.1') is v:true
39+
Expect composer#semver#compare('1.0.1', '!=', '1.0.1') is v:false
40+
end
41+
42+
it 'compares with <'
43+
Expect composer#semver#compare('1.4.1', '<', '2.0.0') is v:true
44+
Expect composer#semver#compare('3.0.1', '<', '1.0.1') is v:false
45+
Expect composer#semver#compare('1.0.1', '<', '1.0.1') is v:false
46+
Expect composer#semver#compare('2.0', '<', '2') is v:false
47+
Expect composer#semver#compare('2', '<', '2.6.3') is v:false
48+
Expect composer#semver#compare('2.3.4', '<', '3') is v:true
49+
end
50+
51+
it 'compares with <='
52+
Expect composer#semver#compare('1.4.1', '<=', '1.9.0') is v:true
53+
Expect composer#semver#compare('2.0.0', '<=', '1.0.1') is v:false
54+
Expect composer#semver#compare('1.0.1', '<=', '1.0.1') is v:true
55+
end
56+
57+
it 'compares with >'
58+
Expect composer#semver#compare('1.4.1', '>', '1.0.1') is v:true
59+
Expect composer#semver#compare('1.0.1', '>', '2.0.0') is v:false
60+
Expect composer#semver#compare('1.0.1', '>', '1.0.1') is v:false
61+
Expect composer#semver#compare('1.0.1', '>', '1') is v:false
62+
end
63+
64+
it 'compares with >='
65+
Expect composer#semver#compare('1.4.1', '>=', '1.0.1') is v:true
66+
Expect composer#semver#compare('1.0.1', '>=', '8.0.1') is v:false
67+
Expect composer#semver#compare('1.0.1', '>=', '1.0.1') is v:true
68+
Expect composer#semver#compare('1', '>=', '1.6.10') is v:true
69+
end
70+
end
71+
72+
" vim: fdm=marker:sw=2:sts=2:et

0 commit comments

Comments
 (0)