@master/eslint-plugin-css 2.0.0-beta.185 → 2.0.0-beta.186

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,23 +1,22 @@
1
1
  'use strict'
2
2
 
3
- var rule = require('../../lib/rules/class-order')
4
- var RuleTester = require('eslint').RuleTester
5
- var parserOptions = {
6
- ecmaVersion: 2019,
7
- sourceType: 'module',
8
- ecmaFeatures: {
9
- jsx: true,
10
- },
11
- }
3
+ const rule = require('../../lib/rules/class-order')
4
+ const RuleTester = require('eslint').RuleTester
5
+ const ruleTester = new RuleTester({
6
+ parserOptions: {
7
+ ecmaFeatures: {
8
+ jsx: true,
9
+ },
10
+ }
11
+ })
12
12
 
13
- var ruleTester = new RuleTester({ parserOptions })
14
13
  ruleTester.run('svelte class order', rule, {
15
14
  valid: [{ code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>` }],
16
15
  invalid: [
17
16
  {
18
17
  code: `<div class="m:8 bg:black p:8 fg:white f:24 {flipped ? 'flipped' : ''}">Enhancing readability</div>`,
19
18
  output: `<div class="bg:black fg:white f:24 m:8 p:8 {flipped ? 'flipped' : ''}">Enhancing readability</div>`,
20
- errors: [{ messageId: 'invalidOrder' }],
19
+ errors: [{ messageId: 'invalidClassOrder' }],
21
20
  filename: 'test.svelte',
22
21
  parser: require.resolve('svelte-eslint-parser'),
23
22
  },
@@ -1,23 +1,22 @@
1
1
  'use strict'
2
2
 
3
- var rule = require('../../lib/rules/class-order')
4
- var RuleTester = require('eslint').RuleTester
5
- var parserOptions = {
6
- ecmaVersion: 2019,
7
- sourceType: 'module',
8
- ecmaFeatures: {
9
- jsx: true,
10
- },
11
- }
3
+ const rule = require('../../lib/rules/class-order')
4
+ const RuleTester = require('eslint').RuleTester
5
+ const ruleTester = new RuleTester({
6
+ parserOptions: {
7
+ ecmaFeatures: {
8
+ jsx: true,
9
+ }
10
+ }
11
+ })
12
12
 
13
- var ruleTester = new RuleTester({ parserOptions })
14
13
  ruleTester.run('vue class order', rule, {
15
14
  valid: [{ code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>` }],
16
15
  invalid: [
17
16
  {
18
17
  code: `<template><div class="m:8 bg:black p:8 fg:white f:24">Enhancing readability</div></template>`,
19
18
  output: `<template><div class="bg:black fg:white f:24 m:8 p:8">Enhancing readability</div></template>`,
20
- errors: [{ messageId: 'invalidOrder' }],
19
+ errors: [{ messageId: 'invalidClassOrder' }],
21
20
  filename: 'test.vue',
22
21
  parser: require.resolve('vue-eslint-parser'),
23
22
  },
package/tests/order.js ADDED
@@ -0,0 +1,66 @@
1
+ 'use strict'
2
+
3
+ const rule = require('../lib/rules/class-order')
4
+ const RuleTester = require('eslint').RuleTester
5
+ const ruleTester = new RuleTester({
6
+ parserOptions: {
7
+ ecmaFeatures: {
8
+ jsx: true,
9
+ },
10
+ }
11
+ })
12
+
13
+ ruleTester.run('class order', rule, {
14
+ valid: [
15
+ {
16
+ code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>`,
17
+ },
18
+ {
19
+ code: `<div class="card mt:20">Traditional class + syntax</div>`,
20
+ },
21
+ {
22
+ code: `<div test="bg:black fg:white f:24 m:8 p:8">Simple, using 'test' prop</div>`,
23
+ options: [
24
+ {
25
+ classMatching: '^test$',
26
+ },
27
+ ],
28
+ },
29
+ ],
30
+ invalid: [
31
+ {
32
+ code: `<div class="fg:white f:24 m:8 p:8 bg:black">Classnames will be ordered</div>`,
33
+ output: `<div class="bg:black fg:white f:24 m:8 p:8">Classnames will be ordered</div>`,
34
+ errors: [{ messageId: 'invalidClassOrder' }],
35
+ },
36
+ {
37
+ code: `
38
+ <div class="
39
+ m:8
40
+ bg:black
41
+ p:8
42
+ fg:white
43
+ f:24
44
+ ">
45
+ :)
46
+ </div>`,
47
+ output: `
48
+ <div class="
49
+ bg:black
50
+ fg:white
51
+ f:24
52
+ m:8
53
+ p:8
54
+ ">
55
+ :)
56
+ </div>`,
57
+ errors: [{ messageId: 'invalidClassOrder' }],
58
+ parser: require.resolve('@angular-eslint/template-parser'),
59
+ },
60
+ {
61
+ code: `<div class="flex uppercase m:0 m:0>li text-decoration:none>li>a px:4>li align-items:baseline fg:gray-30>li>a gap-x:28 font:12 font:semibold pb:6>li pt:20 pt:10>li {bb:3|solid|black}>li:has(>.router-link-active) {fg:black}>li:has(>.router-link-active)>a fg:gray-10>li>a:hover box-shadow:none>li>a:focus">Group</div>`,
62
+ output: `<div class="flex uppercase align-items:baseline box-shadow:none>li>a:focus fg:gray-30>li>a fg:gray-10>li>a:hover gap-x:28 font:12 font:semibold {bb:3|solid|black}>li:has(>.router-link-active) {fg:black}>li:has(>.router-link-active)>a m:0 m:0>li pb:6>li pt:20 pt:10>li px:4>li text-decoration:none>li>a">Group</div>`,
63
+ errors: [{ messageId: 'invalidClassOrder' }],
64
+ }
65
+ ],
66
+ })
@@ -0,0 +1,69 @@
1
+ 'use strict'
2
+
3
+ const rule = require('../lib/rules/class-validation')
4
+ const RuleTester = require('eslint').RuleTester
5
+
6
+ new RuleTester({
7
+ parserOptions: {
8
+ ecmaFeatures: {
9
+ jsx: true,
10
+ },
11
+ }
12
+ }).run('invalid', rule, {
13
+ valid: [
14
+ {
15
+ code: `<div class="bg:black fg:white f:24 m:8 p:8">Simple, basic</div>`,
16
+ }
17
+ ],
18
+ invalid: [
19
+ {
20
+ code: `<div class="bg:black m:mistake rrr">Simple, basic</div>`,
21
+ errors: [
22
+ { messageId: 'invalidClass' },
23
+ { messageId: 'disallowTraditionalClass' }
24
+ ],
25
+ options: [
26
+ {
27
+ disallowTraditionalClass: true
28
+ }
29
+ ]
30
+ },
31
+ {
32
+ code: `<div class="bg:black m:mistake rrr">Simple, basic</div>`,
33
+ errors: [
34
+ { messageId: 'invalidClass' },
35
+ ]
36
+ }
37
+ ]
38
+ })
39
+
40
+ new RuleTester({
41
+ parserOptions: {
42
+ ecmaFeatures: {
43
+ jsx: true,
44
+ },
45
+ },
46
+ settings: {
47
+ '@master/css': {
48
+ config: {
49
+ styles: { btn: 'block' }
50
+ }
51
+ }
52
+ }
53
+ }).run('invalid', rule, {
54
+ valid: [],
55
+ invalid: [
56
+ {
57
+ code: `<div class="bg:black m:mistake rrr btn">Simple, basic</div>`,
58
+ errors: [
59
+ { messageId: 'invalidClass' },
60
+ { messageId: 'disallowTraditionalClass' }
61
+ ],
62
+ options: [
63
+ {
64
+ disallowTraditionalClass: true
65
+ }
66
+ ]
67
+ },
68
+ ],
69
+ })
package/lib/util/ast.js DELETED
@@ -1,370 +0,0 @@
1
- /**
2
- * @fileoverview Utility functions for AST
3
- */
4
-
5
- 'use strict'
6
-
7
- const { separatorRegEx } = require('./regex')
8
- // context.parserPath
9
- // /.../eslint-plugin-tailwindcss/node_modules/espree/espree.js
10
- // /.../eslint-plugin-tailwindcss/node_modules/@angular-eslint/template-parser/dist/index.js
11
-
12
- const removeDuplicatesFromArray = require('./removeDuplicatesFromArray')
13
-
14
- function calleeToString(calleeNode) {
15
- if (calleeNode.type === 'Identifier') {
16
- return calleeNode.name
17
- }
18
- if (calleeNode.type === 'MemberExpression') {
19
- return `${calleeNode.object.name}.${calleeNode.property.name}`
20
- }
21
- }
22
-
23
- /**
24
- * Find out if node is `class` or `className`
25
- *
26
- * @param {ASTNode} node The AST node being checked
27
- * @param {String} classRegex Regex to test the attribute that is being checked against
28
- * @returns {Boolean}
29
- */
30
- function isClassAttribute(node, classRegex) {
31
- if (!node.name) {
32
- return false
33
- }
34
- let name = ''
35
- switch (node.type) {
36
- case 'TextAttribute':
37
- name = node.name
38
- break
39
- default:
40
- name = node.name.name
41
- }
42
- return new RegExp(classRegex).test(name)
43
- }
44
-
45
- /**
46
- * Find out if node is `class`
47
- *
48
- * @param {ASTNode} node The AST node being checked
49
- * @param {String} classRegex Regex to test the attribute that is being checked against
50
- * @returns {Boolean}
51
- */
52
- function isVueClassAttribute(node, classRegex) {
53
- const re = new RegExp(classRegex)
54
- let name = ''
55
- switch (true) {
56
- case node.key && node.key.name && re.test(node.key.name):
57
- // class="vue-classes-as-litteral"
58
- return true
59
- case node.key &&
60
- node.key.name &&
61
- node.key.name.name &&
62
- node.key.argument &&
63
- node.key.argument.name &&
64
- /^bind$/.test(node.key.name.name) &&
65
- re.test(node.key.argument.name):
66
- // v-bind:class="vue-classes-as-bind"
67
- // :class="vue-classes-as-bind"
68
- return true
69
- default:
70
- return false
71
- }
72
- }
73
-
74
- /**
75
- * Find out if node's value attribute is just simple text
76
- *
77
- * @param {ASTNode} node The AST node being checked
78
- * @returns {Boolean}
79
- */
80
- function isVLiteralValue(node) {
81
- return node.value && node.value.type === 'VLiteral'
82
- }
83
-
84
- /**
85
- * Find out if node's value attribute is an ArrayExpression
86
- *
87
- * @param {ASTNode} node The AST node being checked
88
- * @returns {Boolean}
89
- */
90
- function isArrayExpression(node) {
91
- return node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ArrayExpression'
92
- }
93
-
94
- /**
95
- * Find out if node's value attribute is an ObjectExpression
96
- *
97
- * @param {ASTNode} node The AST node being checked
98
- * @returns {Boolean}
99
- */
100
- function isObjectExpression(node) {
101
- return node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ObjectExpression'
102
- }
103
-
104
- /**
105
- * Find out if node's value attribute is just simple text
106
- *
107
- * @param {ASTNode} node The AST node being checked
108
- * @returns {Boolean}
109
- */
110
- function isVueValidAttributeValue(node) {
111
- switch (true) {
112
- case isVLiteralValue(node): // Simple string
113
- case isArrayExpression(node): // ['tw-unknown-class']
114
- case isObjectExpression(node): // {'tw-unknown-class': true}
115
- return true
116
- default:
117
- return false
118
- }
119
- }
120
-
121
- /**
122
- * Find out if node's value attribute is just simple text
123
- *
124
- * @param {ASTNode} node The AST node being checked
125
- * @returns {Boolean}
126
- */
127
- function isLiteralAttributeValue(node) {
128
- if (node.type === 'TextAttribute' && node.name === 'class' && typeof node.value === 'string') {
129
- return true
130
- }
131
- if (node.value) {
132
- switch (node.value.type) {
133
- case 'Literal':
134
- return true
135
- case 'JSXExpressionContainer':
136
- // className={"..."}
137
- return node.value.expression.type === 'Literal'
138
- }
139
- }
140
- return false
141
- }
142
-
143
- /**
144
- * Find out if the node is a valid candidate for our rules
145
- *
146
- * @param {ASTNode} node The AST node being checked
147
- * @param {String} classRegex Regex to test the attribute that is being checked against
148
- * @returns {Boolean}
149
- */
150
- function isValidJSXAttribute(node, classRegex) {
151
- if (!isClassAttribute(node, classRegex)) {
152
- // Only run for class[Name] attributes
153
- return false
154
- }
155
- if (!isLiteralAttributeValue(node)) {
156
- // No support for dynamic or conditional classnames
157
- return false
158
- }
159
- return true
160
- }
161
-
162
- /**
163
- * Find out if the node is a valid candidate for our rules
164
- *
165
- * @param {ASTNode} node The AST node being checked
166
- * @param {String} classRegex Regex to test the attribute that is being checked against
167
- * @returns {Boolean}
168
- */
169
- function isValidVueAttribute(node, classRegex) {
170
- if (!isVueClassAttribute(node, classRegex)) {
171
- // Only run for class attributes
172
- return false
173
- }
174
- if (!isVueValidAttributeValue(node)) {
175
- // No support for dynamic or conditional classnames
176
- return false
177
- }
178
- return true
179
- }
180
-
181
- function extractRangeFromNode(node) {
182
- if (node.type === 'TextAttribute' && node.name === 'class') {
183
- return [node.valueSpan.fullStart.offset, node.valueSpan.end.offset]
184
- }
185
- switch (node.value.type) {
186
- case 'JSXExpressionContainer':
187
- return node.value.expression.range
188
- default:
189
- return node.value.range
190
- }
191
- }
192
-
193
- function extractValueFromNode(node) {
194
- if (node.type === 'TextAttribute' && node.name === 'class') {
195
- return node.value
196
- }
197
- switch (node.value.type) {
198
- case 'JSXExpressionContainer':
199
- return node.value.expression.value
200
- case 'VExpressionContainer':
201
- switch (node.value.expression.type) {
202
- case 'ArrayExpression':
203
- return node.value.expression.elements
204
- case 'ObjectExpression':
205
- return node.value.expression.properties
206
- }
207
- return node.value.expression.value
208
- default:
209
- return node.value.value
210
- }
211
- }
212
-
213
- function extractClassnamesFromValue(classStr) {
214
- if (typeof classStr !== 'string') {
215
- return { classNames: [], whitespaces: [], headSpace: false, tailSpace: false }
216
- }
217
- let parts = classStr.split(separatorRegEx)
218
- if (parts[0] === '') {
219
- parts.shift()
220
- }
221
- if (parts[parts.length - 1] === '') {
222
- parts.pop()
223
- }
224
- let headSpace = separatorRegEx.test(parts[0])
225
- let tailSpace = separatorRegEx.test(parts[parts.length - 1])
226
- const isClass = (_, i) => (headSpace ? i % 2 !== 0 : i % 2 === 0)
227
- const isNotClass = (_, i) => (headSpace ? i % 2 === 0 : i % 2 !== 0)
228
- let classNames = parts.filter(isClass)
229
- let whitespaces = parts.filter(isNotClass)
230
- return { classNames: classNames, whitespaces: whitespaces, headSpace: headSpace, tailSpace: tailSpace }
231
- }
232
-
233
- /**
234
- * Inspect and parse an abstract syntax node and run a callback function
235
- *
236
- * @param {ASTNode} rootNode The current root node being parsed by eslint
237
- * @param {ASTNode} childNode The AST node child argument being checked
238
- * @param {Function} cb The callback function
239
- * @param {Boolean} skipConditional Optional, indicate distinct parsing for conditional nodes
240
- * @param {Boolean} isolate Optional, set internally to isolate parsing and validation on conditional children
241
- * @param {Array} ignoredKeys Optional, set object keys which should not be parsed e.g. for `cva`
242
- * @returns {void}
243
- */
244
- function parseNodeRecursive(rootNode, childNode, cb, skipConditional = false, isolate = false, ignoredKeys = []) {
245
- // TODO allow vue non litteral
246
- let originalClassNamesValue
247
- let classNames
248
- if (childNode === null) {
249
- originalClassNamesValue = extractValueFromNode(rootNode);
250
- ({ classNames } = extractClassnamesFromValue(originalClassNamesValue))
251
- classNames = removeDuplicatesFromArray(classNames)
252
- if (classNames.length === 0) {
253
- // Don't run for empty className
254
- return
255
- }
256
- cb(classNames, rootNode)
257
- } else if (childNode === undefined) {
258
- // Ignore invalid child candidates (probably inside complex TemplateLiteral)
259
- return
260
- } else {
261
- const forceIsolation = skipConditional ? true : isolate
262
- let trim = false
263
- switch (childNode.type) {
264
- case 'TemplateLiteral':
265
- childNode.expressions.forEach((exp) => {
266
- parseNodeRecursive(rootNode, exp, cb, skipConditional, forceIsolation, ignoredKeys)
267
- })
268
- childNode.quasis.forEach((quasis) => {
269
- parseNodeRecursive(rootNode, quasis, cb, skipConditional, isolate, ignoredKeys)
270
- })
271
- return
272
- case 'ConditionalExpression':
273
- parseNodeRecursive(rootNode, childNode.consequent, cb, skipConditional, forceIsolation, ignoredKeys)
274
- parseNodeRecursive(rootNode, childNode.alternate, cb, skipConditional, forceIsolation, ignoredKeys)
275
- return
276
- case 'LogicalExpression':
277
- parseNodeRecursive(rootNode, childNode.right, cb, skipConditional, forceIsolation, ignoredKeys)
278
- return
279
- case 'ArrayExpression':
280
- childNode.elements.forEach((el) => {
281
- parseNodeRecursive(rootNode, el, cb, skipConditional, forceIsolation, ignoredKeys)
282
- })
283
- return
284
- case 'ObjectExpression':
285
- childNode.properties.forEach((prop) => {
286
- const isUsedByClassNamesPlugin = rootNode.callee && rootNode.callee.name === 'classnames'
287
-
288
- if (prop.type === 'SpreadElement') {
289
- // Ignore spread elements
290
- return
291
- }
292
-
293
- if (prop.key.type === 'Identifier' && ignoredKeys.includes(prop.key.name)) {
294
- // Ignore specific keys defined in settings
295
- return
296
- }
297
-
298
- parseNodeRecursive(
299
- rootNode,
300
- isUsedByClassNamesPlugin ? prop.key : prop.value,
301
- cb,
302
- skipConditional,
303
- forceIsolation,
304
- ignoredKeys
305
- )
306
- })
307
- return
308
- case 'Property':
309
- parseNodeRecursive(rootNode, childNode.key, cb, skipConditional, forceIsolation, ignoredKeys)
310
- return
311
- case 'Literal':
312
- trim = true
313
- originalClassNamesValue = childNode.value
314
- break
315
- case 'TemplateElement':
316
- originalClassNamesValue = childNode.value.raw
317
- break
318
- }
319
- ({ classNames } = extractClassnamesFromValue(originalClassNamesValue))
320
- classNames = removeDuplicatesFromArray(classNames)
321
- if (classNames.length === 0) {
322
- // Don't run for empty className
323
- return
324
- }
325
- const targetNode = isolate ? null : rootNode
326
- cb(classNames, targetNode)
327
- }
328
- }
329
-
330
- function getTemplateElementPrefix(text, raw) {
331
- const idx = text.indexOf(raw)
332
- if (idx === 0) {
333
- return ''
334
- }
335
- return text.split(raw).shift()
336
- }
337
-
338
- function getTemplateElementSuffix(text, raw) {
339
- if (text.indexOf(raw) === -1) {
340
- return ''
341
- }
342
- return text.split(raw).pop()
343
- }
344
-
345
- function getTemplateElementBody(text, prefix, suffix) {
346
- let arr = text.split(prefix)
347
- arr.shift()
348
- let body = arr.join(prefix)
349
- arr = body.split(suffix)
350
- arr.pop()
351
- return arr.join(suffix)
352
- }
353
-
354
- module.exports = {
355
- calleeToString,
356
- extractRangeFromNode,
357
- extractValueFromNode,
358
- extractClassnamesFromValue,
359
- isClassAttribute,
360
- isLiteralAttributeValue,
361
- isArrayExpression,
362
- isObjectExpression,
363
- isValidJSXAttribute,
364
- isValidVueAttribute,
365
- isVLiteralValue,
366
- parseNodeRecursive,
367
- getTemplateElementPrefix,
368
- getTemplateElementSuffix,
369
- getTemplateElementBody,
370
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * @see parserServices https://eslint.org/docs/developer-guide/working-with-rules#the-context-object
3
- * @param {Object} context
4
- * @param {Function} templateBodyVisitor
5
- * @param {Function} scriptVisitor
6
- * @returns
7
- */
8
- function defineTemplateBodyVisitor(context, templateBodyVisitor, scriptVisitor) {
9
- if (context.parserServices == null || context.parserServices.defineTemplateBodyVisitor == null) {
10
- // Default parser
11
- return scriptVisitor
12
- }
13
-
14
- // Using "vue-eslint-parser" requires this setup
15
- // @see https://eslint.org/docs/developer-guide/working-with-rules#the-context-object
16
- return context.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor)
17
- }
18
-
19
- module.exports = {
20
- defineTemplateBodyVisitor,
21
- }
package/lib/util/regex.js DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * Escapes a string to be used in a regular expression
3
- * Copied from https://stackoverflow.com/a/3561711.
4
- * @param {string} input
5
- * @returns {string}
6
- */
7
- function escapeRegex(input) {
8
- return input.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&')
9
- }
10
-
11
- const separatorRegEx = /([\t\n\f\r ]+)/
12
-
13
- module.exports = {
14
- escapeRegex,
15
- separatorRegEx,
16
- }
@@ -1,7 +0,0 @@
1
- 'use strict'
2
-
3
- function removeDuplicatesFromArray(arr) {
4
- return [...new Set(arr)]
5
- }
6
-
7
- module.exports = removeDuplicatesFromArray
@@ -1,18 +0,0 @@
1
- 'use strict'
2
-
3
- function removeDuplicatesFromClassnamesAndWhitespaces(orderedClassNames, whitespaces, headSpace, tailSpace) {
4
- let previous = orderedClassNames[0]
5
- const offset = (!headSpace && !tailSpace) || tailSpace ? -1 : 0
6
- for (let i = 1; i < orderedClassNames.length; i++) {
7
- const cls = orderedClassNames[i]
8
- // This function assumes that the list of classNames is ordered, so just comparing to the previous className is enough
9
- if (cls === previous) {
10
- orderedClassNames.splice(i, 1)
11
- whitespaces.splice(i + offset, 1)
12
- i--
13
- }
14
- previous = cls
15
- }
16
- }
17
-
18
- module.exports = removeDuplicatesFromClassnamesAndWhitespaces
@@ -1,39 +0,0 @@
1
- 'use strict'
2
- const exploreConfig = require('explore-config').default
3
-
4
- function getOption(context, name) {
5
- // Options (defined at rule level)
6
- const options = context.options[0] || {}
7
- if (options[name] != undefined) {
8
- return options[name]
9
- }
10
- // Settings (defined at plugin level, shared accross rules)
11
- if (context.settings && context.settings.mastercss && context.settings.mastercss[name] != undefined) {
12
- return context.settings.mastercss[name]
13
- }
14
- // Fallback to defaults
15
- switch (name) {
16
- case 'callees':
17
- return ['classnames', 'clsx', 'ctl', 'cva']
18
- case 'ignoredKeys':
19
- return ['compoundVariants', 'defaultVariants']
20
- case 'classRegex':
21
- return '^class(Name)?$'
22
- case 'config':
23
- return exploreConfig('master.css.*', {})
24
- case 'cssFiles':
25
- return ['**/*.css', '!**/node_modules', '!**/.*', '!**/dist', '!**/build']
26
- case 'cssFilesRefreshRate':
27
- return 5_000
28
- case 'removeDuplicates':
29
- return true
30
- case 'skipClassAttribute':
31
- return false
32
- case 'tags':
33
- return []
34
- case 'whitelist':
35
- return []
36
- }
37
- }
38
-
39
- module.exports = getOption