6acc957fe604ad31d9380a39a61f52a293932fb5
[platform/framework/web/crosswalk-tizen.git] /
1 "use strict";
2
3 var stripJsonComments = require('strip-json-comments');
4 var fs = require('fs');
5 var path = require('path');
6
7 var _ws = require('rocambole-whitespace');
8 var _br = require('rocambole-linebreak');
9 var indent = require('./indent');
10 var plugins = require('./plugins');
11
12 var deepMixIn = require('mout/object/deepMixIn');
13 var merge = require('mout/object/merge');
14 var get = require('mout/object/get');
15 var isObject = require('mout/lang/isObject');
16
17
18 // ---
19
20 var _curOpts;
21
22 // ---
23
24 exports.presets = {
25   'default': require('./preset/default.json'),
26   'jquery' : require('./preset/jquery.json')
27 };
28
29
30 exports.set = function(opts) {
31   var preset = opts && opts.preset ? opts.preset : 'default';
32   // we need to pass all the user settings and default settings to the plugins
33   // so they are able to toggle the behavior and make changes based on the
34   // options
35   _curOpts = mergeOptions(preset, opts);
36
37   _ws.setOptions(_curOpts.whiteSpace);
38   _br.setOptions(_curOpts.lineBreak);
39   indent.setOptions(_curOpts.indent);
40   plugins.setOptions(_curOpts);
41
42   // user provided options should override default settings and also any
43   // changes made by plugins
44   if (opts) {
45     _curOpts = deepMixIn(_curOpts, opts);
46   }
47 };
48
49
50 function mergeOptions(preset, opts){
51   if (!(preset in exports.presets)) {
52     throw new Error('Invalid preset file "' + preset + '".');
53   }
54   var baseOpts = exports.presets[preset];
55   // recursively merge options to allow a "prototype chain"
56   if (baseOpts.preset) {
57     baseOpts = mergeOptions(baseOpts.preset, baseOpts);
58   }
59   return merge({}, baseOpts, opts);
60 }
61
62
63 exports.get = function(prop) {
64   return prop ? get(_curOpts, prop) : _curOpts;
65 };
66
67
68 exports.getRc = getRc;
69 function getRc(filePath, customOptions) {
70   // if user sets the "preset" we don't load any other config file
71   // we assume the "preset" overrides any user settings
72   if (isTopLevel(customOptions)) {
73     return customOptions;
74   }
75
76   if (isObject(filePath)) {
77     customOptions = filePath;
78     filePath = null;
79   }
80   // we search for config file starting from source directory or from cwd if
81   // path is not provided
82   var basedir = filePath ? path.dirname(filePath) : process.cwd();
83   var cwd = process.cwd();
84   var rc = findAndMergeConfigs(basedir);
85   if (!rc && basedir !== cwd) {
86     rc = findAndMergeConfigs(cwd);
87   }
88   return merge(rc || getGlobalConfig(), customOptions);
89 }
90
91
92 function findAndMergeConfigs(basedir) {
93   if (!basedir || !basedir.length) return;
94
95   var configFiles = ['.esformatter', 'package.json'];
96   var config;
97
98   configFiles.some(function(name) {
99     var filePath = path.join(basedir, name);
100     if (!fs.existsSync(filePath)) return;
101
102     var cur = loadAndParseConfig(filePath);
103     if (name === 'package.json') {
104       cur = cur.esformatter;
105     }
106
107     if (!cur) return;
108
109     // we merge configs on same folder as well just in case user have
110     // ".esformatter" and "package.json" on same folder
111     // notice that ".esformatter" file takes precedence and will override the
112     // "package.json" settings.
113     config = config ? merge(cur, config) : cur;
114
115     // stop the loop
116     if (isTopLevel(config)) return true;
117   });
118
119   if (isTopLevel(config)) {
120     return config;
121   }
122
123   // we merge configs from parent folders so it's easier to add different rules
124   // for each folder on a project and/or override just specific settings
125   var parentDir = path.resolve(basedir, '..');
126   // we need to check if parentDir is different from basedir to avoid conflicts
127   // on windows (see #174)
128   var parentConfig = parentDir && parentDir !== basedir ?
129     findAndMergeConfigs(parentDir) :
130     {};
131   // notice that current folder config overrides the parent folder config
132   return merge(parentConfig, config);
133 }
134
135
136 function isTopLevel(config) {
137   // if config contains 'root:true' or inherit from another "preset" we
138   // consider it as top-level and don't merge the settings with config files on
139   // parent folders.
140   return config && (config.root || config.preset);
141 }
142
143
144 function getGlobalConfig() {
145   var home = process.platform === 'win32' ? process.env.USERPROFILE : process.env.HOME;
146   var file = path.join(home, '.esformatter');
147   return fs.existsSync(file) ? loadAndParseConfig(file) : {};
148 }
149
150
151 exports.loadAndParseConfig = loadAndParseConfig;
152 function loadAndParseConfig(file) {
153   try {
154     return JSON.parse(stripJsonComments(fs.readFileSync(file).toString()));
155   } catch (ex) {
156     console.error('Can\'t parse configuration file: "' + file + '"\nException: ' + ex.message);
157     process.exit(1);
158   }
159 }
160
161