source: frontend/node_modules/tailwindcss/src/util/normalizeConfig.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 8.8 KB
Line 
1import { flagEnabled } from '../featureFlags'
2import log, { dim } from './log'
3
4export function normalizeConfig(config) {
5 // Quick structure validation
6 /**
7 * type FilePath = string
8 * type RawFile = { raw: string, extension?: string }
9 * type ExtractorFn = (content: string) => Array<string>
10 * type TransformerFn = (content: string) => string
11 *
12 * type Content =
13 * | Array<FilePath | RawFile>
14 * | {
15 * files: Array<FilePath | RawFile>,
16 * extract?: ExtractorFn | { [extension: string]: ExtractorFn }
17 * transform?: TransformerFn | { [extension: string]: TransformerFn }
18 * }
19 */
20 let valid = (() => {
21 // `config.purge` should not exist anymore
22 if (config.purge) {
23 return false
24 }
25
26 // `config.content` should exist
27 if (!config.content) {
28 return false
29 }
30
31 // `config.content` should be an object or an array
32 if (
33 !Array.isArray(config.content) &&
34 !(typeof config.content === 'object' && config.content !== null)
35 ) {
36 return false
37 }
38
39 // When `config.content` is an array, it should consist of FilePaths or RawFiles
40 if (Array.isArray(config.content)) {
41 return config.content.every((path) => {
42 // `path` can be a string
43 if (typeof path === 'string') return true
44
45 // `path` can be an object { raw: string, extension?: string }
46 // `raw` must be a string
47 if (typeof path?.raw !== 'string') return false
48
49 // `extension` (if provided) should also be a string
50 if (path?.extension && typeof path?.extension !== 'string') {
51 return false
52 }
53
54 return true
55 })
56 }
57
58 // When `config.content` is an object
59 if (typeof config.content === 'object' && config.content !== null) {
60 // Only `files`, `relative`, `extract`, and `transform` can exist in `config.content`
61 if (
62 Object.keys(config.content).some(
63 (key) => !['files', 'relative', 'extract', 'transform'].includes(key)
64 )
65 ) {
66 return false
67 }
68
69 // `config.content.files` should exist of FilePaths or RawFiles
70 if (Array.isArray(config.content.files)) {
71 if (
72 !config.content.files.every((path) => {
73 // `path` can be a string
74 if (typeof path === 'string') return true
75
76 // `path` can be an object { raw: string, extension?: string }
77 // `raw` must be a string
78 if (typeof path?.raw !== 'string') return false
79
80 // `extension` (if provided) should also be a string
81 if (path?.extension && typeof path?.extension !== 'string') {
82 return false
83 }
84
85 return true
86 })
87 ) {
88 return false
89 }
90
91 // `config.content.extract` is optional, and can be a Function or a Record<String, Function>
92 if (typeof config.content.extract === 'object') {
93 for (let value of Object.values(config.content.extract)) {
94 if (typeof value !== 'function') {
95 return false
96 }
97 }
98 } else if (
99 !(config.content.extract === undefined || typeof config.content.extract === 'function')
100 ) {
101 return false
102 }
103
104 // `config.content.transform` is optional, and can be a Function or a Record<String, Function>
105 if (typeof config.content.transform === 'object') {
106 for (let value of Object.values(config.content.transform)) {
107 if (typeof value !== 'function') {
108 return false
109 }
110 }
111 } else if (
112 !(
113 config.content.transform === undefined || typeof config.content.transform === 'function'
114 )
115 ) {
116 return false
117 }
118
119 // `config.content.relative` is optional and can be a boolean
120 if (
121 typeof config.content.relative !== 'boolean' &&
122 typeof config.content.relative !== 'undefined'
123 ) {
124 return false
125 }
126 }
127
128 return true
129 }
130
131 return false
132 })()
133
134 if (!valid) {
135 log.warn('purge-deprecation', [
136 'The `purge`/`content` options have changed in Tailwind CSS v3.0.',
137 'Update your configuration file to eliminate this warning.',
138 'https://tailwindcss.com/docs/upgrade-guide#configure-content-sources',
139 ])
140 }
141
142 // Normalize the `safelist`
143 config.safelist = (() => {
144 let { content, purge, safelist } = config
145
146 if (Array.isArray(safelist)) return safelist
147 if (Array.isArray(content?.safelist)) return content.safelist
148 if (Array.isArray(purge?.safelist)) return purge.safelist
149 if (Array.isArray(purge?.options?.safelist)) return purge.options.safelist
150
151 return []
152 })()
153
154 // Normalize the `blocklist`
155 config.blocklist = (() => {
156 let { blocklist } = config
157
158 if (Array.isArray(blocklist)) {
159 if (blocklist.every((item) => typeof item === 'string')) {
160 return blocklist
161 }
162
163 log.warn('blocklist-invalid', [
164 'The `blocklist` option must be an array of strings.',
165 'https://tailwindcss.com/docs/content-configuration#discarding-classes',
166 ])
167 }
168
169 return []
170 })()
171
172 // Normalize prefix option
173 if (typeof config.prefix === 'function') {
174 log.warn('prefix-function', [
175 'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
176 'Update `prefix` in your configuration to be a string to eliminate this warning.',
177 'https://tailwindcss.com/docs/upgrade-guide#prefix-cannot-be-a-function',
178 ])
179 config.prefix = ''
180 } else {
181 config.prefix = config.prefix ?? ''
182 }
183
184 // Normalize the `content`
185 config.content = {
186 relative: (() => {
187 let { content } = config
188
189 if (content?.relative) {
190 return content.relative
191 }
192
193 return flagEnabled(config, 'relativeContentPathsByDefault')
194 })(),
195
196 files: (() => {
197 let { content, purge } = config
198
199 if (Array.isArray(purge)) return purge
200 if (Array.isArray(purge?.content)) return purge.content
201 if (Array.isArray(content)) return content
202 if (Array.isArray(content?.content)) return content.content
203 if (Array.isArray(content?.files)) return content.files
204
205 return []
206 })(),
207
208 extract: (() => {
209 let extract = (() => {
210 if (config.purge?.extract) return config.purge.extract
211 if (config.content?.extract) return config.content.extract
212
213 if (config.purge?.extract?.DEFAULT) return config.purge.extract.DEFAULT
214 if (config.content?.extract?.DEFAULT) return config.content.extract.DEFAULT
215
216 if (config.purge?.options?.extractors) return config.purge.options.extractors
217 if (config.content?.options?.extractors) return config.content.options.extractors
218
219 return {}
220 })()
221
222 let extractors = {}
223
224 let defaultExtractor = (() => {
225 if (config.purge?.options?.defaultExtractor) {
226 return config.purge.options.defaultExtractor
227 }
228
229 if (config.content?.options?.defaultExtractor) {
230 return config.content.options.defaultExtractor
231 }
232
233 return undefined
234 })()
235
236 if (defaultExtractor !== undefined) {
237 extractors.DEFAULT = defaultExtractor
238 }
239
240 // Functions
241 if (typeof extract === 'function') {
242 extractors.DEFAULT = extract
243 }
244
245 // Arrays
246 else if (Array.isArray(extract)) {
247 for (let { extensions, extractor } of extract ?? []) {
248 for (let extension of extensions) {
249 extractors[extension] = extractor
250 }
251 }
252 }
253
254 // Objects
255 else if (typeof extract === 'object' && extract !== null) {
256 Object.assign(extractors, extract)
257 }
258
259 return extractors
260 })(),
261
262 transform: (() => {
263 let transform = (() => {
264 if (config.purge?.transform) return config.purge.transform
265 if (config.content?.transform) return config.content.transform
266
267 if (config.purge?.transform?.DEFAULT) return config.purge.transform.DEFAULT
268 if (config.content?.transform?.DEFAULT) return config.content.transform.DEFAULT
269
270 return {}
271 })()
272
273 let transformers = {}
274
275 if (typeof transform === 'function') {
276 transformers.DEFAULT = transform
277 } else if (typeof transform === 'object' && transform !== null) {
278 Object.assign(transformers, transform)
279 }
280
281 return transformers
282 })(),
283 }
284
285 // Validate globs to prevent bogus globs.
286 // E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html`
287 for (let file of config.content.files) {
288 if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) {
289 log.warn('invalid-glob-braces', [
290 `The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`,
291 `Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`,
292 // TODO: Add https://tw.wtf/invalid-glob-braces
293 ])
294 break
295 }
296 }
297
298 return config
299}
Note: See TracBrowser for help on using the repository browser.