]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/lib/help-search.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / lib / help-search.js
1
2 module.exports = helpSearch
3
4 var fs = require("graceful-fs")
5   , path = require("path")
6   , asyncMap = require("slide").asyncMap
7   , npm = require("./npm.js")
8   , glob = require("glob")
9   , color = require("ansicolors")
10
11 helpSearch.usage = "npm help-search <text>"
12
13 function helpSearch (args, silent, cb) {
14   if (typeof cb !== "function") cb = silent, silent = false
15   if (!args.length) return cb(helpSearch.usage)
16
17   var docPath = path.resolve(__dirname, "..", "doc")
18   return glob(docPath + "/*/*.md", function (er, files) {
19     if (er)
20       return cb(er)
21     readFiles(files, function (er, data) {
22       if (er)
23         return cb(er)
24       searchFiles(args, data, function (er, results) {
25         if (er)
26           return cb(er)
27         formatResults(args, results, cb)
28       })
29     })
30   })
31 }
32
33 function readFiles (files, cb) {
34   var res = {}
35   asyncMap(files, function (file, cb) {
36     fs.readFile(file, 'utf8', function (er, data) {
37       res[file] = data
38       return cb(er)
39     })
40   }, function (er) {
41     return cb(er, res)
42   })
43 }
44
45 function searchFiles (args, files, cb) {
46   var results = []
47   Object.keys(files).forEach(function (file) {
48     var data = files[file]
49
50     // skip if no matches at all
51     var match
52     for (var a = 0, l = args.length; a < l && !match; a++) {
53       match = data.toLowerCase().indexOf(args[a].toLowerCase()) !== -1
54     }
55     if (!match)
56       return
57
58     var lines = data.split(/\n+/)
59
60     // if a line has a search term, then skip it and the next line.
61     // if the next line has a search term, then skip all 3
62     // otherwise, set the line to null.  then remove the nulls.
63     l = lines.length
64     for (var i = 0; i < l; i ++) {
65       var line = lines[i]
66         , nextLine = lines[i + 1]
67         , ll
68
69       match = false
70       if (nextLine) {
71         for (a = 0, ll = args.length; a < ll && !match; a ++) {
72           match = nextLine.toLowerCase()
73                   .indexOf(args[a].toLowerCase()) !== -1
74         }
75         if (match) {
76           // skip over the next line, and the line after it.
77           i += 2
78           continue
79         }
80       }
81
82       match = false
83       for (a = 0, ll = args.length; a < ll && !match; a ++) {
84         match = line.toLowerCase().indexOf(args[a].toLowerCase()) !== -1
85       }
86       if (match) {
87         // skip over the next line
88         i ++
89         continue
90       }
91
92       lines[i] = null
93     }
94
95     // now squish any string of nulls into a single null
96     lines = lines.reduce(function (l, r) {
97       if (!(r === null && l[l.length-1] === null)) l.push(r)
98       return l
99     }, [])
100
101     if (lines[lines.length - 1] === null) lines.pop()
102     if (lines[0] === null) lines.shift()
103
104     // now see how many args were found at all.
105     var found = {}
106       , totalHits = 0
107     lines.forEach(function (line) {
108       args.forEach(function (arg) {
109         var hit = (line || "").toLowerCase()
110                   .split(arg.toLowerCase()).length - 1
111         if (hit > 0) {
112           found[arg] = (found[arg] || 0) + hit
113           totalHits += hit
114         }
115       })
116     })
117
118     var cmd = "npm help "
119     if (path.basename(path.dirname(file)) === "api") {
120       cmd = "npm apihelp "
121     }
122     cmd += path.basename(file, ".md").replace(/^npm-/, "")
123     results.push({ file: file
124                  , cmd: cmd
125                  , lines: lines
126                  , found: Object.keys(found)
127                  , hits: found
128                  , totalHits: totalHits
129                  })
130   })
131
132   // if only one result, then just show that help section.
133   if (results.length === 1) {
134     return npm.commands.help([results[0].file.replace(/\.md$/, "")], cb)
135   }
136
137   if (results.length === 0) {
138     console.log("No results for " + args.map(JSON.stringify).join(" "))
139     return cb()
140   }
141
142   // sort results by number of results found, then by number of hits
143   // then by number of matching lines
144   results = results.sort(function (a, b) {
145     return a.found.length > b.found.length ? -1
146          : a.found.length < b.found.length ? 1
147          : a.totalHits > b.totalHits ? -1
148          : a.totalHits < b.totalHits ? 1
149          : a.lines.length > b.lines.length ? -1
150          : a.lines.length < b.lines.length ? 1
151          : 0
152   })
153
154   cb(null, results)
155 }
156
157 function formatResults (args, results, cb) {
158   if (!results) return cb(null)
159
160   var cols = Math.min(process.stdout.columns || Infinity, 80) + 1
161
162   var out = results.map(function (res) {
163     var out = res.cmd
164       , r = Object.keys(res.hits).map(function (k) {
165           return k + ":" + res.hits[k]
166         }).sort(function (a, b) {
167           return a > b ? 1 : -1
168         }).join(" ")
169
170     out += ((new Array(Math.max(1, cols - out.length - r.length)))
171              .join(" ")) + r
172
173     if (!npm.config.get("long")) return out
174
175     out = "\n\n" + out
176          + "\n" + (new Array(cols)).join("—") + "\n"
177          + res.lines.map(function (line, i) {
178       if (line === null || i > 3) return ""
179       for (var out = line, a = 0, l = args.length; a < l; a ++) {
180         var finder = out.toLowerCase().split(args[a].toLowerCase())
181           , newOut = ""
182           , p = 0
183
184         finder.forEach(function (f) {
185           newOut += out.substr(p, f.length)
186
187           var hilit = out.substr(p + f.length, args[a].length)
188           if (npm.color) hilit = color.bgBlack(color.red(hilit))
189           newOut += hilit
190
191           p += f.length + args[a].length
192         })
193       }
194
195       return newOut
196     }).join("\n").trim()
197     return out
198   }).join("\n")
199
200   if (results.length && !npm.config.get("long")) {
201     out = "Top hits for "+(args.map(JSON.stringify).join(" "))
202         + "\n" + (new Array(cols)).join("—") + "\n"
203         + out
204         + "\n" + (new Array(cols)).join("—") + "\n"
205         + "(run with -l or --long to see more context)"
206   }
207
208   console.log(out.trim())
209   cb(null, results)
210 }