aboutsummaryrefslogtreecommitdiff
path: root/dotfiles/.vim/autoload/node/lib.vim
blob: 1c7a8c1fd5e9f77668b8e1b42924534a0ceec27c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
let s:ABSPATH = '^/'
let s:RELPATH = '\v^\.\.?(/|$)'
let s:MODULE = '\v^(/|\.\.?(/|$))@!'

" Damn Netrw can't handle HTTPS at all. It's 2013! Insecure bastard!
let s:CORE_URL_PREFIX = "https://rawgit.com/nodejs/node"
let s:CORE_MODULES = ["_debugger", "_http_agent", "_http_client",
	\ "_http_common", "_http_incoming", "_http_outgoing", "_http_server",
	\ "_linklist", "_stream_duplex", "_stream_passthrough", "_stream_readable",
	\ "_stream_transform", "_stream_writable", "_tls_legacy", "_tls_wrap",
	\ "assert", "buffer", "child_process", "cluster", "console", "constants",
	\ "crypto", "dgram", "dns", "domain", "events", "freelist", "fs", "http",
	\ "https", "module", "net", "node", "os", "path", "punycode", "querystring",
	\ "readline", "repl", "smalloc", "stream", "string_decoder", "sys",
	\ "timers", "tls", "tty", "url", "util", "vm", "zlib"]

function! node#lib#find(name, from)
	if index(s:CORE_MODULES, a:name) != -1
		let l:version = node#lib#version()
		let l:version = empty(l:version) ? "master" : "v" . l:version
		let l:dir = a:name == "node" ? "src" : "lib"
		let l:url = get(g:, "node_repository_url", s:CORE_URL_PREFIX)
		return l:url ."/". l:version ."/". l:dir ."/". a:name .".js"
	endif

	let l:path = s:resolve(s:absolutize(a:name, a:from))
	if !empty(path) | return fnamemodify(resolve(path), ":.") | endif
endfunction

function! node#lib#version()
	if exists("b:node_version") | return b:node_version | endif
	if !executable("node") | let b:node_version = "" | return | endif
	let b:node_version = matchstr(system("node --version"), '^v\?\zs[0-9.]\+')
	return b:node_version
endfunction

function! s:absolutize(name, from)
	if a:name =~# s:ABSPATH
		return a:name
	elseif a:name =~# s:RELPATH
		let dir = isdirectory(a:from) ? a:from : fnamemodify(a:from, ":h")
		return dir . "/" . a:name
	else
		return b:node_root . "/node_modules/" . a:name
	endif
endfunction

function! s:resolve(path)
	" Node checks for files *before* directories, so see if the path does not
	" end with a slash or dots and try to match it as a file.
	if a:path !~# '\v/(\.\.?/?)?$'
		let path_with_suffix = s:resolveSuffix(a:path)
		if !empty(path_with_suffix) | return path_with_suffix | endif
	endif

	if isdirectory(a:path) | return s:resolveFromDirectory(a:path) | endif
endfunction

function! s:resolveFromDirectory(path)
	" Node.js checks for package.json in every directory, not just the
	" module's parent. According to:
	" http://nodejs.org/api/modules.html#modules_all_together
	if filereadable(a:path . "/package.json")
		" Turns out, even though Node says it does not support directories in
		" main, it does.
		" NOTE: If package.json's main is empty or refers to a non-existent file,
		" ./index.js is still tried.
		let main = s:mainFromPackage(a:path . "/package.json")

		if !empty(main) && main != ""
			let path = s:resolve(a:path . "/" . main)
			if !empty(path) | return path | endif
		endif
	endif

	" We need to check for ./index.js's existence here rather than leave it to
	" the caller, because otherwise we can't distinguish if this ./index was
	" from the directory defaulting to ./index.js or it was the package.json
	" which referred to ./index, which in itself could mean both ./index.js and
	" ./index/index.js.
	return s:resolveSuffix(a:path . "/index")
endfunction

function! s:mainFromPackage(path)
	for line in readfile(a:path)
		if line !~# '"main"\s*:' | continue | endif
		return matchstr(line, '"main"\s*:\s*"\zs[^"]\+\ze"')
	endfor
endfunction

function! s:resolveSuffix(path)
	for suffix in s:uniq([""] + g:node#suffixesadd + split(&l:suffixesadd, ","))
		let path = a:path . suffix
		if filereadable(path) | return path | endif
	endfor
endfunction

let s:GLOB_WILDIGNORE = 1

function! node#lib#glob(name)
	let matches = []

	if empty(a:name)
		let matches += s:CORE_MODULES
	endif

	if empty(a:name) || a:name =~# s:MODULE
		let root = b:node_root . "/node_modules"
		let matches += s:glob(empty(a:name) ? root : root . "/" . a:name, root)
	endif

	if a:name =~# s:ABSPATH
		let matches += s:glob(a:name, 0)
	endif

	if empty(a:name) || a:name =~# s:RELPATH
		let root = b:node_root
		let relatives = s:glob(empty(a:name) ? root : root . "/" . a:name, root)

		"call map(relatives, "substitute(v:val, '^\./\./', './', '')")
		if empty(a:name) | call map(relatives, "'./' . v:val") | endif
		call filter(relatives, "v:val !~# '^\\.//*node_modules/$'")

		let matches += relatives
	endif

	return matches
endfunction

function! s:glob(path, stripPrefix)
	" Remove a single trailing slash because we're adding one with the glob.
	let path = substitute(a:path, '/$', "", "")
	" Glob() got the ability to return a list only in Vim 7.3.465. Using split
	" for compatibility.
	let list = split(glob(fnameescape(path)."/*", s:GLOB_WILDIGNORE), "\n")

	" Add slashes to directories, like /bin/ls.
	call map(list, "v:val . (isdirectory(v:val) ? '/' : '')")

	if !empty(a:stripPrefix)
		" Counting and removing bytes intentionally as there's no substr function
		" that takes character count, only bytes.
		let	prefix_length = len(a:stripPrefix) + 1
		return map(list, "strpart(v:val, prefix_length)")
	endif

	return list
endfunction

function! s:uniq(list)
	let list = reverse(copy(a:list))
	return reverse(filter(list, "index(list, v:val, v:key + 1) == -1"))
endfunction