index.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. * spmrc
  3. *
  4. * Thanks to: https://github.com/shockie/node-iniparser
  5. *
  6. * An example of ~/.spm/spmrc-3x
  7. *
  8. * [user]
  9. * username=lepture
  10. *
  11. * [server:spm]
  12. * url = https://spmjs.io
  13. *
  14. */
  15. var fs = require('fs');
  16. var path = require('path');
  17. var homedir = process.env.HOME;
  18. if (!homedir) {
  19. homedir = process.env.HOMEDRIVE + process.env.HOMEPATH;
  20. }
  21. module.exports = function (opts) {
  22. var DIR = opts.dir || '.node-cli-config'
  23. var FILE = opts.file || 'config'
  24. var DEFAULTS = opts.defaults || {}
  25. /**
  26. * Where is your spmrc file.
  27. */
  28. var spmrcfile = path.join(homedir, DIR, FILE);
  29. var tmpdir = process.env.TMPDIR || process.env.TMP || process.env.TEMP;
  30. if (!tmpdir) {
  31. if (process.platform === 'win32') {
  32. tmpdir = 'c:\\windows\\temp';
  33. } else {
  34. tmpdir = '/tmp';
  35. }
  36. }
  37. var defaults = DEFAULTS
  38. var get = function (key) {
  39. var file = spmrcfile;
  40. var ret = renderConfig(parse(file));
  41. if (!key) return ret;
  42. key = key.replace(':', '.');
  43. var keys = key.split('.');
  44. keys.forEach(function (section) {
  45. ret = ret ? ret[section] : null;
  46. });
  47. if (!ret && defaults[key]) {
  48. return defaults[key];
  49. }
  50. return ret;
  51. };
  52. var set = function (key, value) {
  53. var file = spmrcfile;
  54. var data = parse(file);
  55. var keys = key.split('.');
  56. var ret;
  57. if (keys.length === 3) {
  58. ret = [];
  59. ret.push(keys[0] + ':' + keys[1]);
  60. ret.push(keys[2]);
  61. keys = ret;
  62. }
  63. if (keys.length === 2) {
  64. data[keys[0]] = data[keys[0]] || {};
  65. data[keys[0]][keys[1]] = value;
  66. } else if (keys.length === 1) {
  67. data[keys[0]] = value;
  68. } else {
  69. throw new Error('A valid input should be something like user.username=spm');
  70. }
  71. updateConfig(data);
  72. return data;
  73. };
  74. /**
  75. * Combine set and get into one function.
  76. */
  77. var config = function (key, value) {
  78. if (!value) return get(key);
  79. return set(key, value);
  80. };
  81. var regex = {
  82. section: /^\s*\[\s*([^\]]*)\s*\]\s*$/,
  83. param: /^\s*([\w\.\-\_]+)\s*=\s*(.*?)\s*$/,
  84. comment: /^\s*;.*$/
  85. };
  86. var _cache = {};
  87. /**
  88. * Parse ini format data.
  89. */
  90. function parse(file) {
  91. file = file || spmrcfile;
  92. if (!fs.existsSync(file)) {
  93. return {};
  94. }
  95. var data;
  96. if (_cache.hasOwnProperty(file)) {
  97. data = _cache[file];
  98. } else {
  99. data = fs.readFileSync(file, 'utf8');
  100. _cache[file] = data;
  101. }
  102. var value = {};
  103. var lines = data.split(/\r\n|\r|\n/);
  104. var section = null;
  105. var match;
  106. lines.forEach(function (line) {
  107. if (regex.comment.test(line)) {
  108. return;
  109. }
  110. if (regex.param.test(line)) {
  111. match = line.match(regex.param);
  112. if (section) {
  113. value[section][match[1]] = match[2];
  114. } else {
  115. value[match[1]] = match[2];
  116. }
  117. } else if (regex.section.test(line)) {
  118. match = line.match(regex.section);
  119. value[match[1]] = {};
  120. section = match[1];
  121. } else if (line.length === 0 && section) {
  122. section = null;
  123. }
  124. });
  125. return value;
  126. }
  127. var parse = parse;
  128. function updateConfig(data) {
  129. var text = '';
  130. var init = true;
  131. var file = spmrcfile;
  132. Object.keys(data).forEach(function (section) {
  133. if (!init) {
  134. text += '\n';
  135. } else {
  136. init = false;
  137. }
  138. if (typeof data[section] === 'object') {
  139. text += '[' + section + ']\n';
  140. Object.keys(data[section]).forEach(function (key) {
  141. text += key + ' = ' + data[section][key] + '\n';
  142. });
  143. } else {
  144. text += section + ' = ' + data[section];
  145. }
  146. });
  147. mkdir(path.dirname(file));
  148. fs.writeFileSync(file, text);
  149. delete _cache[file];
  150. }
  151. var write = updateConfig;
  152. return {
  153. get: get,
  154. set: set,
  155. config: config,
  156. write: write,
  157. parse: parse,
  158. spmrcfile: spmrcfile
  159. }
  160. }
  161. /**
  162. * Make config data to objects.
  163. */
  164. function renderConfig(data) {
  165. var ret = {};
  166. Object.keys(data).forEach(function (section) {
  167. var sections = section.split(':');
  168. if (sections.length === 2) {
  169. ret[sections[0]] = ret[sections[0]] || {};
  170. ret[sections[0]][sections[1]] = data[section];
  171. } else {
  172. ret[section] = data[section];
  173. }
  174. });
  175. return ret;
  176. }
  177. /**
  178. * Merge object key values.
  179. */
  180. function merge(obj) {
  181. var target, key;
  182. for (var i = 1; i < arguments.length; i++) {
  183. target = arguments[i];
  184. for (key in target) {
  185. if (Object.prototype.hasOwnProperty.call(target, key)) {
  186. obj[key] = target[key];
  187. }
  188. }
  189. }
  190. return obj;
  191. }
  192. /**
  193. * Recursively mkdir. Like `mkdir -r`
  194. */
  195. function mkdir(dirpath) {
  196. if (fs.existsSync(dirpath)) return;
  197. dirpath.split(/[\/\\]/g).reduce(function (parts, part) {
  198. parts += part + '/';
  199. var subpath = path.resolve(parts);
  200. if (!fs.existsSync(subpath)) {
  201. fs.mkdirSync(subpath);
  202. }
  203. return parts;
  204. }, '');
  205. }