UNPKG

5.86 kBJavaScriptView Raw
1var path = require('path');
2var Vow = require('vow');
3var reservedWords = require('reserved-words');
4
5var IDENTIFIER_NAME_ES5_RE = require('../patterns/identifiers-ES5');
6var IDENTIFIER_NAME_ES6_RE = require('../patterns/identifiers-ES6');
7
8var TRAILING_UNDERSCORES_RE = /(^_+|_+$)/g;
9
10var SNAKE_CASE_RE = /^([a-z$][a-z0-9$]+)(_[a-z0-9$]+)+$/i;
11
12/**
13 * All keywords where spaces are a stylistic choice
14 * @type {Array}
15 */
16exports.spacedKeywords = [
17 'do',
18 'for',
19 'if',
20 'else',
21 'switch',
22 'case',
23 'try',
24 'catch',
25 'finally',
26 'void',
27 'while',
28 'with',
29 'return',
30 'typeof',
31 'function'
32];
33
34/**
35 * All keywords where curly braces are a stylistic choice
36 * @type {Array}
37 */
38exports.curlyBracedKeywords = [
39 'if',
40 'else',
41 'for',
42 'while',
43 'do',
44 'case',
45 'default',
46 'with'
47];
48
49/**
50 * Returns true if name is valid identifier name.
51 *
52 * @param {String} name
53 * @param {String} dialect
54 * @returns {Boolean}
55 */
56exports.isValidIdentifierName = function(name, dialect) {
57 dialect = dialect || 'es5';
58 var identifierRegex = dialect === 'es5' ? IDENTIFIER_NAME_ES5_RE : IDENTIFIER_NAME_ES6_RE;
59 return !reservedWords.check(name, dialect, true) && identifierRegex.test(name);
60};
61
62/**
63 * Snake case tester
64 *
65 * @param {String} name
66 * @return {Boolean}
67 */
68exports.isSnakeCased = function(name) {
69 return SNAKE_CASE_RE.test(name);
70};
71
72/**
73 * Returns the function expression node if the provided node is an IIFE,
74 * otherwise returns null.
75 *
76 * @param {Object} node
77 * @return {?Object}
78 */
79exports.getFunctionNodeFromIIFE = function(node) {
80 if (node.type !== 'CallExpression') {
81 return null;
82 }
83
84 var callee = node.callee;
85
86 if (callee.type === 'FunctionExpression') {
87 return callee;
88 }
89
90 if (callee.type === 'MemberExpression' &&
91 callee.object.type === 'FunctionExpression' &&
92 callee.property.type === 'Identifier' &&
93 (callee.property.name === 'call' || callee.property.name === 'apply')
94 ) {
95 return callee.object;
96 }
97
98 return null;
99};
100
101/**
102 * Trims leading and trailing underscores
103 *
104 * @param {String} name
105 * @return {String}
106 */
107exports.trimUnderscores = function(name) {
108 var res = name.replace(TRAILING_UNDERSCORES_RE, '');
109 return res ? res : name;
110};
111
112/**
113 * Whether or not the given path is relative
114 *
115 * @param {String} path
116 * @return {Boolean}
117 */
118exports.isRelativePath = function(path) {
119 // Logic from: https://github.com/joyent/node/blob/4f1ae11a62b97052bc83756f8cb8700cc1f61661/lib/module.js#L237
120 var start = path.substring(0, 2);
121 return start === './' || start === '..';
122};
123
124/**
125 * Resolves a relative filepath against the supplied base path
126 * or just returns the filepath if not relative
127 *
128 * @param {String} filepath
129 * @param {String} basePath
130 * @return {String}
131 */
132exports.normalizePath = function(filepath, basePath) {
133 if (this.isRelativePath(filepath)) {
134 return path.resolve(basePath, filepath);
135 }
136
137 return filepath;
138};
139
140/**
141 * Wraps a function such that you can interact with a promise and not a
142 * node-style callback.
143 *
144 * @param {Function} fn - function that expects a node-style callback
145 * @return {Function} When invoked with arguments, returns a promise resolved/rejected
146 * based on the results of the wrapped node-style callback
147 */
148exports.promisify = function(fn) {
149 return function() {
150 var deferred = Vow.defer();
151 var args = [].slice.call(arguments);
152
153 args.push(function(err, result) {
154 if (err) {
155 deferred.reject(err);
156 } else {
157 deferred.resolve(result);
158 }
159 });
160
161 fn.apply(null, args);
162
163 return deferred.promise();
164 };
165};
166
167/**
168 * All possible binary operators supported by JSCS
169 * @type {Array}
170 */
171exports.binaryOperators = [
172
173 // assignment operators
174 '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
175 '&=', '|=', '^=',
176
177 '+', '-', '*', '/', '%', '<<', '>>', '>>>', '&',
178 '|', '^', '&&', '||', '===', '==', '>=',
179 '<=', '<', '>', '!=', '!=='
180];
181
182/**
183 * Increment and decrement operators
184 * @type {Array}
185 */
186exports.incrementAndDecrementOperators = ['++', '--'];
187
188/**
189 * All possible unary operators supported by JSCS
190 * @type {Array}
191 */
192exports.unaryOperators = ['-', '+', '!', '~'].concat(exports.incrementAndDecrementOperators);
193
194/**
195 * All possible operators support by JSCS
196 * @type {Array}
197 */
198exports.operators = exports.binaryOperators.concat(exports.unaryOperators);
199
200/**
201 * Returns a function that can check if a comment is a valid pragma.
202 *
203 * @param {Array} additionalExceptions can optionally be added to the existing pragmaKeywords
204 * @returns {Function} that can be used to determine if a comment (supplied as an argument is a valid pragma
205 *
206 */
207exports.isPragma = function(additionalExceptions) {
208 var pragmaKeywords = [
209 'eslint',
210 'eslint-env',
211 'eslint-enable',
212 'eslint-disable',
213 'eslint-disable-line',
214 'eslint-disable-next-line',
215 'global',
216 'jshint',
217 'jslint',
218 'globals',
219 'falls through',
220 'exported',
221 'jscs:',
222 'jscs:enable',
223 'jscs:disable',
224 'jscs:ignore',
225 'istanbul'
226 ];
227 if (additionalExceptions && Array.isArray(additionalExceptions)) {
228 pragmaKeywords = pragmaKeywords.concat(additionalExceptions);
229 }
230
231 return function(comment) {
232 // pragmaKeywords precede a space or the end of the comment
233 var trimmedComment = comment.trim() + ' ';
234 for (var i = 0; i < pragmaKeywords.length; i++) {
235 if (trimmedComment.indexOf(pragmaKeywords[i] + ' ') === 0) {
236 return true;
237 }
238 }
239 return false;
240 };
241};