151 lines
5.1 KiB
VimL
151 lines
5.1 KiB
VimL
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 = "http://rawgit.com/joyent/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"
|
|
return s:CORE_URL_PREFIX ."/". l:version ."/". l:dir ."/". a:name .".js"
|
|
endif
|
|
|
|
return s:resolve(s:absolutize(a:name, a:from))
|
|
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
|