PageRenderTime 23ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/node_modules/bower/lib/renderers/StandardRenderer.js

https://gitlab.com/KongMono/GuitarChord
JavaScript | 507 lines | 376 code | 100 blank | 31 comment | 71 complexity | 5ad998552bc69482f1b1502962d6a5d9 MD5 | raw file
  1. var chalk = require('chalk');
  2. var path = require('path');
  3. var mout = require('mout');
  4. var archy = require('archy');
  5. var Q = require('q');
  6. var stringifyObject = require('stringify-object');
  7. var os = require('os');
  8. var semverUtils = require('semver-utils');
  9. var version = require('../version');
  10. var template = require('../util/template');
  11. function StandardRenderer(command, config) {
  12. this._sizes = {
  13. id: 13, // Id max chars
  14. label: 20, // Label max chars
  15. sumup: 5 // Amount to sum when the label exceeds
  16. };
  17. this._colors = {
  18. warn: chalk.yellow,
  19. error: chalk.red,
  20. conflict: chalk.magenta,
  21. debug: chalk.gray,
  22. default: chalk.cyan
  23. };
  24. this._command = command;
  25. this._config = config || {};
  26. if (this.constructor._wideCommands.indexOf(command) === -1) {
  27. this._compact = true;
  28. } else {
  29. this._compact = process.stdout.columns < 120;
  30. }
  31. var exitOnPipeError = function (err) {
  32. if (err.code === 'EPIPE') {
  33. process.exit(0);
  34. }
  35. };
  36. // It happens when piping command to "head" util
  37. process.stdout.on('error', exitOnPipeError);
  38. process.stderr.on('error', exitOnPipeError);
  39. }
  40. StandardRenderer.prototype.end = function (data) {
  41. var method = '_' + mout.string.camelCase(this._command);
  42. if (this[method]) {
  43. this[method](data);
  44. }
  45. };
  46. StandardRenderer.prototype.error = function (err) {
  47. var str;
  48. var stack;
  49. this._guessOrigin(err);
  50. err.id = err.code || 'error';
  51. err.level = 'error';
  52. str = this._prefix(err) + ' ' + err.message.replace(/\r?\n/g, ' ').trim() + '\n';
  53. this._write(process.stderr, 'bower ' + str);
  54. // Check if additional details were provided
  55. if (err.details) {
  56. str = chalk.yellow('\nAdditional error details:\n') + err.details.trim() + '\n';
  57. this._write(process.stderr, str);
  58. }
  59. // Print trace if verbose, the error has no code
  60. // or if the error is a node error
  61. if (this._config.verbose || !err.code || err.errno) {
  62. stack = err.fstream_stack || err.stack || 'N/A';
  63. str = chalk.yellow('\nStack trace:\n');
  64. str += (Array.isArray(stack) ? stack.join('\n') : stack) + '\n';
  65. str += chalk.yellow('\nConsole trace:\n');
  66. this._write(process.stderr, str);
  67. this._write(process.stderr, new Error().stack);
  68. // Print bower version, node version and system info.
  69. this._write(process.stderr, chalk.yellow('\nSystem info:\n'));
  70. this._write(process.stderr, 'Bower version: ' + version + '\n');
  71. this._write(process.stderr, 'Node version: ' + process.versions.node + '\n');
  72. this._write(process.stderr, 'OS: ' + os.type() + ' ' + os.release() + ' ' + os.arch() + '\n');
  73. }
  74. };
  75. StandardRenderer.prototype.log = function (log) {
  76. var method = '_' + mout.string.camelCase(log.id) + 'Log';
  77. this._guessOrigin(log);
  78. // Call render method for this log entry or the generic one
  79. if (this[method]) {
  80. this[method](log);
  81. } else {
  82. this._genericLog(log);
  83. }
  84. };
  85. StandardRenderer.prototype.prompt = function (prompts) {
  86. var deferred;
  87. // Strip colors from the prompt if color is disabled
  88. if (!this._config.color) {
  89. prompts.forEach(function (prompt) {
  90. prompt.message = chalk.stripColor(prompt.message);
  91. });
  92. }
  93. // Prompt
  94. deferred = Q.defer();
  95. var inquirer = require('inquirer');
  96. inquirer.prompt(prompts, deferred.resolve);
  97. return deferred.promise;
  98. };
  99. // -------------------------
  100. StandardRenderer.prototype._help = function (data) {
  101. var str;
  102. var that = this;
  103. var specific;
  104. if (!data.command) {
  105. str = template.render('std/help.std', data);
  106. that._write(process.stdout, str);
  107. } else {
  108. // Check if a specific template exists for the command
  109. specific = 'std/help-' + data.command.replace(/\s+/g, '/') + '.std';
  110. if (template.exists(specific)) {
  111. str = template.render(specific, data);
  112. } else {
  113. str = template.render('std/help-generic.std', data);
  114. }
  115. that._write(process.stdout, str);
  116. }
  117. };
  118. StandardRenderer.prototype._install = function (packages) {
  119. var str = '';
  120. mout.object.forOwn(packages, function (pkg) {
  121. var cliTree;
  122. // List only 1 level deep dependencies
  123. mout.object.forOwn(pkg.dependencies, function (dependency) {
  124. dependency.dependencies = {};
  125. });
  126. // Make canonical dir relative
  127. pkg.canonicalDir = path.relative(this._config.cwd, pkg.canonicalDir);
  128. // Signal as root
  129. pkg.root = true;
  130. cliTree = this._tree2archy(pkg);
  131. str += '\n' + archy(cliTree);
  132. }, this);
  133. if (str) {
  134. this._write(process.stdout, str);
  135. }
  136. };
  137. StandardRenderer.prototype._update = function (packages) {
  138. this._install(packages);
  139. };
  140. StandardRenderer.prototype._list = function (tree) {
  141. var cliTree;
  142. if (tree.pkgMeta) {
  143. tree.root = true;
  144. cliTree = archy(this._tree2archy(tree));
  145. } else {
  146. cliTree = stringifyObject(tree, { indent: ' ' }).replace(/[{}]/g, '') + '\n';
  147. }
  148. this._write(process.stdout, cliTree);
  149. };
  150. StandardRenderer.prototype._search = function (results) {
  151. var str = template.render('std/search-results.std', results);
  152. this._write(process.stdout, str);
  153. };
  154. StandardRenderer.prototype._info = function (data) {
  155. var str = '';
  156. var pkgMeta = data;
  157. var includeVersions = false;
  158. // If the response is the whole package info, the package meta
  159. // is under the "latest" property
  160. if (typeof data === 'object' && data.versions) {
  161. pkgMeta = data.latest;
  162. includeVersions = true;
  163. }
  164. // Render package meta
  165. if (pkgMeta != null) {
  166. str += '\n' + this._highlightJson(pkgMeta) + '\n';
  167. }
  168. // Render the versions at the end
  169. if (includeVersions) {
  170. data.hidePreReleases = false;
  171. data.numPreReleases = 0;
  172. // If output isn't verbose, hide prereleases
  173. if (!this._config.verbose) {
  174. data.versions = mout.array.filter(data.versions, function (version) {
  175. version = semverUtils.parse(version);
  176. if (!version.release && !version.build) {
  177. return true;
  178. }
  179. data.numPreReleases++;
  180. });
  181. data.hidePreReleases = !!data.numPreReleases;
  182. }
  183. str += '\n' + template.render('std/info.std', data);
  184. }
  185. this._write(process.stdout, str);
  186. };
  187. StandardRenderer.prototype._lookup = function (data) {
  188. var str = template.render('std/lookup.std', data);
  189. this._write(process.stdout, str);
  190. };
  191. StandardRenderer.prototype._link = function (data) {
  192. this._sizes.id = 4;
  193. this.log({
  194. id: 'link',
  195. level: 'info',
  196. message: data.dst + ' > ' + data.src
  197. });
  198. // Print also a tree of the installed packages
  199. if (data.installed) {
  200. this._install(data.installed);
  201. }
  202. };
  203. StandardRenderer.prototype._register = function (data) {
  204. var str;
  205. // If no data passed, it means the user aborted
  206. if (!data) {
  207. return;
  208. }
  209. str = '\n' + template.render('std/register.std', data);
  210. this._write(process.stdout, str);
  211. };
  212. StandardRenderer.prototype._cacheList = function (entries) {
  213. entries.forEach(function (entry) {
  214. var pkgMeta = entry.pkgMeta;
  215. var version = pkgMeta.version || pkgMeta._target;
  216. this._write(process.stdout, pkgMeta.name + '=' + pkgMeta._source + '#' + version + '\n');
  217. }, this);
  218. };
  219. // -------------------------
  220. StandardRenderer.prototype._genericLog = function (log) {
  221. var stream;
  222. var str;
  223. if (log.level === 'warn') {
  224. stream = process.stderr;
  225. } else {
  226. stream = process.stdout;
  227. }
  228. str = this._prefix(log) + ' ' + log.message + '\n';
  229. this._write(stream, 'bower ' + str);
  230. };
  231. StandardRenderer.prototype._checkoutLog = function (log) {
  232. if (this._compact) {
  233. log.message = log.origin.split('#')[0] + '#' + log.message;
  234. }
  235. this._genericLog(log);
  236. };
  237. StandardRenderer.prototype._progressLog = function (log) {
  238. if (this._compact) {
  239. log.message = log.origin + ' ' + log.message;
  240. }
  241. this._genericLog(log);
  242. };
  243. StandardRenderer.prototype._extractLog = function (log) {
  244. if (this._compact) {
  245. log.message = log.origin + ' ' + log.message;
  246. }
  247. this._genericLog(log);
  248. };
  249. StandardRenderer.prototype._incompatibleLog = function (log) {
  250. var str;
  251. var templatePath;
  252. // Generate dependants string for each pick
  253. log.data.picks.forEach(function (pick) {
  254. pick.dependants = pick.dependants.map(function (dependant) {
  255. var release = dependant.pkgMeta._release;
  256. return dependant.endpoint.name + (release ? '#' + release : '');
  257. }).join(', ');
  258. });
  259. templatePath = log.data.suitable ? 'std/conflict-resolved.std' : 'std/conflict.std';
  260. str = template.render(templatePath, log.data);
  261. this._write(process.stdout, '\n');
  262. this._write(process.stdout, str);
  263. this._write(process.stdout, '\n');
  264. };
  265. StandardRenderer.prototype._solvedLog = function (log) {
  266. this._incompatibleLog(log);
  267. };
  268. StandardRenderer.prototype._jsonLog = function (log) {
  269. this._write(process.stdout, '\n' + this._highlightJson(log.data.json) + '\n\n');
  270. };
  271. StandardRenderer.prototype._cachedEntryLog = function (log) {
  272. if (this._compact) {
  273. log.message = log.origin;
  274. }
  275. this._genericLog(log);
  276. };
  277. // -------------------------
  278. StandardRenderer.prototype._guessOrigin = function (log) {
  279. var data = log.data;
  280. if (!data) {
  281. return;
  282. }
  283. if (data.endpoint) {
  284. log.origin = data.endpoint.name || (data.registry && data.endpoint.source);
  285. // Resort to using the resolver name for unnamed endpoints
  286. if (!log.origin && data.resolver) {
  287. log.origin = data.resolver.name;
  288. }
  289. if (log.origin && data.endpoint.target) {
  290. log.origin += '#' + data.endpoint.target;
  291. }
  292. } else if (data.name) {
  293. log.origin = data.name;
  294. if (data.version) {
  295. log.origin += '#' + data.version;
  296. }
  297. }
  298. };
  299. StandardRenderer.prototype._prefix = function (log) {
  300. var label;
  301. var length;
  302. var nrSpaces;
  303. var id = this.constructor._idMappings[log.id] || log.id;
  304. var idColor = this._colors[log.level] || this._colors.default;
  305. if (this._compact) {
  306. // If there's not enough space for the id, adjust it
  307. // for subsequent logs
  308. if (id.length > this._sizes.id) {
  309. this._sizes.id = id.length += this._sizes.sumup;
  310. }
  311. return idColor(mout.string.rpad(id, this._sizes.id));
  312. }
  313. // Construct the label
  314. label = log.origin || '';
  315. length = id.length + label.length + 1;
  316. nrSpaces = this._sizes.id + this._sizes.label - length;
  317. // Ensure at least one space between the label and the id
  318. if (nrSpaces < 1) {
  319. // Also adjust the label size for subsequent logs
  320. this._sizes.label = label.length + this._sizes.sumup;
  321. nrSpaces = this._sizes.id + this._sizes.label - length;
  322. }
  323. return chalk.green(label) + mout.string.repeat(' ', nrSpaces) + idColor(id);
  324. };
  325. StandardRenderer.prototype._write = function (stream, str) {
  326. if (!this._config.color) {
  327. str = chalk.stripColor(str);
  328. }
  329. stream.write(str);
  330. };
  331. StandardRenderer.prototype._highlightJson = function (json) {
  332. var cardinal = require('cardinal');
  333. return cardinal.highlight(stringifyObject(json, { indent: ' ' }), {
  334. theme: {
  335. String: {
  336. _default: function (str) {
  337. return chalk.cyan(str);
  338. }
  339. },
  340. Identifier: {
  341. _default: function (str) {
  342. return chalk.green(str);
  343. }
  344. }
  345. },
  346. json: true
  347. });
  348. };
  349. StandardRenderer.prototype._tree2archy = function (node) {
  350. var dependencies = mout.object.values(node.dependencies);
  351. var version = !node.missing ? node.pkgMeta._release || node.pkgMeta.version : null;
  352. var label = node.endpoint.name + (version ? '#' + version : '');
  353. var update;
  354. if (node.root) {
  355. label += ' ' + node.canonicalDir;
  356. }
  357. // State labels
  358. if (node.missing) {
  359. label += chalk.red(' not installed');
  360. return label;
  361. }
  362. if (node.different) {
  363. label += chalk.red(' different');
  364. }
  365. if (node.linked) {
  366. label += chalk.magenta(' linked');
  367. }
  368. if (node.incompatible) {
  369. label += chalk.yellow(' incompatible') + ' with ' + node.endpoint.target;
  370. } else if (node.extraneous) {
  371. label += chalk.green(' extraneous');
  372. }
  373. // New versions
  374. if (node.update) {
  375. update = '';
  376. if (node.update.target && node.pkgMeta.version !== node.update.target) {
  377. update += node.update.target + ' available';
  378. }
  379. if (node.update.latest !== node.update.target) {
  380. update += (update ? ', ' : '');
  381. update += 'latest is ' + node.update.latest;
  382. }
  383. if (update) {
  384. label += ' (' + chalk.cyan(update) + ')';
  385. }
  386. }
  387. if (!dependencies.length) {
  388. return label;
  389. }
  390. return {
  391. label: label,
  392. nodes: mout.object.values(dependencies).map(this._tree2archy, this)
  393. };
  394. };
  395. StandardRenderer._wideCommands = [
  396. 'install',
  397. 'update',
  398. 'link',
  399. 'info',
  400. 'home',
  401. 'register'
  402. ];
  403. StandardRenderer._idMappings = {
  404. 'mutual': 'conflict',
  405. 'cached-entry': 'cached'
  406. };
  407. module.exports = StandardRenderer;