You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

util.js 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. 'use strict';
  2. const fs = require('fs');
  3. const path = require('path');
  4. const types = require('./types');
  5. // https://github.com/npm/npm/blob/latest/lib/config/core.js#L409-L423
  6. const envReplace = str => {
  7. if (typeof str !== 'string' || !str) {
  8. return str;
  9. }
  10. // Replace any ${ENV} values with the appropriate environment
  11. const regex = /(\\*)\$\{([^}]+)\}/g;
  12. return str.replace(regex, (orig, esc, name) => {
  13. esc = esc.length > 0 && esc.length % 2;
  14. if (esc) {
  15. return orig;
  16. }
  17. if (process.env[name] === undefined) {
  18. throw new Error(`Failed to replace env in config: ${orig}`);
  19. }
  20. return process.env[name];
  21. });
  22. };
  23. // https://github.com/npm/npm/blob/latest/lib/config/core.js#L362-L407
  24. const parseField = (field, key) => {
  25. if (typeof field !== 'string') {
  26. return field;
  27. }
  28. const typeList = [].concat(types[key]);
  29. const isPath = typeList.indexOf(path) !== -1;
  30. const isBool = typeList.indexOf(Boolean) !== -1;
  31. const isString = typeList.indexOf(String) !== -1;
  32. const isNumber = typeList.indexOf(Number) !== -1;
  33. field = `${field}`.trim();
  34. if (/^".*"$/.test(field)) {
  35. try {
  36. field = JSON.parse(field);
  37. } catch (err) {
  38. throw new Error(`Failed parsing JSON config key ${key}: ${field}`);
  39. }
  40. }
  41. if (isBool && !isString && field === '') {
  42. return true;
  43. }
  44. switch (field) { // eslint-disable-line default-case
  45. case 'true': {
  46. return true;
  47. }
  48. case 'false': {
  49. return false;
  50. }
  51. case 'null': {
  52. return null;
  53. }
  54. case 'undefined': {
  55. return undefined;
  56. }
  57. }
  58. field = envReplace(field);
  59. if (isPath) {
  60. const regex = process.platform === 'win32' ? /^~(\/|\\)/ : /^~\//;
  61. if (regex.test(field) && process.env.HOME) {
  62. field = path.resolve(process.env.HOME, field.substr(2));
  63. }
  64. field = path.resolve(field);
  65. }
  66. if (isNumber && !field.isNan()) {
  67. field = Number(field);
  68. }
  69. return field;
  70. };
  71. // https://github.com/npm/npm/blob/latest/lib/config/find-prefix.js
  72. const findPrefix = name => {
  73. name = path.resolve(name);
  74. let walkedUp = false;
  75. while (path.basename(name) === 'node_modules') {
  76. name = path.dirname(name);
  77. walkedUp = true;
  78. }
  79. if (walkedUp) {
  80. return name;
  81. }
  82. const find = (name, original) => {
  83. const regex = /^[a-zA-Z]:(\\|\/)?$/;
  84. if (name === '/' || (process.platform === 'win32' && regex.test(name))) {
  85. return original;
  86. }
  87. try {
  88. const files = fs.readdirSync(name);
  89. if (files.indexOf('node_modules') !== -1 || files.indexOf('package.json') !== -1) {
  90. return name;
  91. }
  92. const dirname = path.dirname(name);
  93. if (dirname === name) {
  94. return original;
  95. }
  96. return find(dirname, original);
  97. } catch (err) {
  98. if (name === original) {
  99. if (err.code === 'ENOENT') {
  100. return original;
  101. }
  102. throw err;
  103. }
  104. return original;
  105. }
  106. };
  107. return find(name, name);
  108. };
  109. exports.envReplace = envReplace;
  110. exports.findPrefix = findPrefix;
  111. exports.parseField = parseField;