1 | import debug from 'debug'
|
2 |
|
3 | import { configurationError } from './messages.js'
|
4 | import { ConfigEmptyError, ConfigFormatError } from './symbols.js'
|
5 | import { validateBraces } from './validateBraces.js'
|
6 |
|
7 | const debugLog = debug('lint-staged:validateConfig')
|
8 |
|
9 | const isObject = (test) => test && typeof test === 'object' && !Array.isArray(test)
|
10 |
|
11 | const TEST_DEPRECATED_KEYS = new Map([
|
12 | ['concurrent', (key) => typeof key === 'boolean'],
|
13 | ['chunkSize', (key) => typeof key === 'number'],
|
14 | ['globOptions', isObject],
|
15 | ['linters', isObject],
|
16 | ['ignore', (key) => Array.isArray(key)],
|
17 | ['subTaskConcurrency', (key) => typeof key === 'number'],
|
18 | ['renderer', (key) => typeof key === 'string'],
|
19 | ['relative', (key) => typeof key === 'boolean'],
|
20 | ])
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | export const validateConfig = (config, logger) => {
|
28 | debugLog('Validating config')
|
29 |
|
30 | if (!config || (typeof config !== 'object' && typeof config !== 'function')) {
|
31 | throw ConfigFormatError
|
32 | }
|
33 |
|
34 | |
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | if (typeof config === 'function') {
|
42 | return { '*': config }
|
43 | }
|
44 |
|
45 | if (Object.entries(config).length === 0) {
|
46 | throw ConfigEmptyError
|
47 | }
|
48 |
|
49 | const errors = []
|
50 |
|
51 | |
52 |
|
53 |
|
54 |
|
55 |
|
56 | const validatedConfig = Object.entries(config).reduce((collection, [pattern, task]) => {
|
57 |
|
58 | if (TEST_DEPRECATED_KEYS.has(pattern)) {
|
59 | const testFn = TEST_DEPRECATED_KEYS.get(pattern)
|
60 | if (testFn(task)) {
|
61 | errors.push(
|
62 | configurationError(pattern, 'Advanced configuration has been deprecated.', task)
|
63 | )
|
64 | }
|
65 |
|
66 |
|
67 | return collection
|
68 | }
|
69 |
|
70 | if (
|
71 | (!Array.isArray(task) ||
|
72 | task.some((item) => typeof item !== 'string' && typeof item !== 'function')) &&
|
73 | typeof task !== 'string' &&
|
74 | typeof task !== 'function'
|
75 | ) {
|
76 | errors.push(
|
77 | configurationError(
|
78 | pattern,
|
79 | 'Should be a string, a function, or an array of strings and functions.',
|
80 | task
|
81 | )
|
82 | )
|
83 | }
|
84 |
|
85 | |
86 |
|
87 |
|
88 |
|
89 | const fixedPattern = validateBraces(pattern, logger)
|
90 |
|
91 | return { ...collection, [fixedPattern]: task }
|
92 | }, {})
|
93 |
|
94 | if (errors.length) {
|
95 | const message = errors.join('\n\n')
|
96 |
|
97 | logger.error(`Could not parse lint-staged config.
|
98 |
|
99 | ${message}
|
100 |
|
101 | See https://github.com/okonet/lint-staged#configuration.`)
|
102 |
|
103 | throw new Error(message)
|
104 | }
|
105 |
|
106 | return validatedConfig
|
107 | }
|