@primer/stylelint-config 13.0.0-rc.35215da → 13.0.0-rc.3727b0c

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,69 +1,60 @@
1
1
  import stylelint from 'stylelint'
2
2
  import declarationValueIndex from 'stylelint/lib/utils/declarationValueIndex.cjs'
3
3
  import valueParser from 'postcss-value-parser'
4
+ import {primitivesVariables, walkGroups} from './lib/utils.js'
4
5
 
5
- // TODO: Pull this in from primer/primitives
6
- const spacerValues = {
7
- '$spacer-1': '4px',
8
- '$spacer-2': '8px',
9
- '$spacer-3': '16px',
10
- '$spacer-4': '24px',
11
- '$spacer-5': '32px',
12
- '$spacer-6': '40px',
13
- '$spacer-7': '48px',
14
- '$spacer-8': '64px',
15
- '$spacer-9': '80px',
16
- '$spacer-10': '96px',
17
- '$spacer-11': '112px',
18
- '$spacer-12': '128px',
19
- '$em-spacer-1': '0.0625em',
20
- '$em-spacer-2': '0.125em',
21
- '$em-spacer-3': '0.25em',
22
- '$em-spacer-4': '0.375em',
23
- '$em-spacer-5': '0.5em',
24
- '$em-spacer-6': '0.75em',
25
- }
6
+ const {
7
+ createPlugin,
8
+ utils: {report, ruleMessages, validateOptions},
9
+ } = stylelint
26
10
 
27
11
  export const ruleName = 'primer/spacing'
28
- export const messages = stylelint.utils.ruleMessages(ruleName, {
12
+ export const messages = ruleMessages(ruleName, {
29
13
  rejected: (value, replacement) => {
30
- if (replacement === null) {
31
- return `Please use a primer spacer variable instead of '${value}'. Consult the primer docs for a suitable replacement. https://primer.style/css/storybook/?path=/docs/support-spacing--docs`
14
+ if (!replacement) {
15
+ return `Please use a primer size variable instead of '${value}'. Consult the primer docs for a suitable replacement. https://primer.style/foundations/primitives/size`
32
16
  }
33
17
 
34
- return `Please replace ${value} with spacing variable '${replacement}'.`
18
+ return `Please replace '${value}' with size variable '${replacement['name']}'. https://primer.style/foundations/primitives/size`
35
19
  },
36
20
  })
37
21
 
38
- const walkGroups = (root, validate) => {
39
- for (const node of root.nodes) {
40
- if (node.type === 'function') {
41
- walkGroups(node, validate)
42
- } else {
43
- validate(node)
44
- }
22
+ // Props that we want to check
23
+ const propList = ['padding', 'margin', 'top', 'right', 'bottom', 'left']
24
+ // Values that we want to ignore
25
+ const valueList = ['${']
26
+
27
+ const sizes = primitivesVariables('spacing')
28
+
29
+ // Add +-1px to each value
30
+ for (const size of sizes) {
31
+ const values = size['values']
32
+ const px = parseInt(values.find(value => value.includes('px')))
33
+ if (![2, 6].includes(px)) {
34
+ values.push(`${px + 1}px`)
35
+ values.push(`${px - 1}px`)
45
36
  }
46
- return root
47
37
  }
48
38
 
49
- // eslint-disable-next-line no-unused-vars
50
- export default stylelint.createPlugin(ruleName, (enabled, options = {}, context) => {
51
- if (!enabled) {
52
- return noop
53
- }
39
+ /** @type {import('stylelint').Rule} */
40
+ const ruleFunction = (primary, secondaryOptions, context) => {
41
+ return (root, result) => {
42
+ const validOptions = validateOptions(result, ruleName, {
43
+ actual: primary,
44
+ possible: [true],
45
+ })
54
46
 
55
- const lintResult = (root, result) => {
56
- root.walk(decl => {
57
- if (decl.type !== 'decl' || !decl.prop.match(/^(padding|margin)/)) {
58
- return noop
59
- }
47
+ if (!validOptions) return
60
48
 
61
- const problems = []
49
+ root.walkDecls(declNode => {
50
+ const {prop, value} = declNode
62
51
 
63
- const parsedValue = walkGroups(valueParser(decl.value), node => {
64
- // Remove leading negative sign, if any.
65
- const cleanValue = node.value.replace(/^-/g, '')
52
+ if (!propList.some(spacingProp => prop.startsWith(spacingProp))) return
53
+ if (valueList.some(valueToIgnore => value.includes(valueToIgnore))) return
66
54
 
55
+ const problems = []
56
+
57
+ const parsedValue = walkGroups(valueParser(value), node => {
67
58
  // Only check word types. https://github.com/TrySound/postcss-value-parser#word
68
59
  if (node.type !== 'word') {
69
60
  return
@@ -74,30 +65,36 @@ export default stylelint.createPlugin(ruleName, (enabled, options = {}, context)
74
65
  return
75
66
  }
76
67
 
77
- const valueUnit = valueParser.unit(cleanValue)
68
+ const valueUnit = valueParser.unit(node.value)
69
+
70
+ if (valueUnit && (valueUnit.unit === '' || !/^-?[0-9.]+$/.test(valueUnit.number))) {
71
+ return
72
+ }
78
73
 
79
- if (valueUnit && (valueUnit.unit === '' || !/^[0-9.]+$/.test(valueUnit.number))) {
74
+ // Skip if the value unit isn't a supported unit.
75
+ if (valueUnit && !['px', 'rem', 'em'].includes(valueUnit.unit)) {
80
76
  return
81
77
  }
82
78
 
83
- // If the a variable is found in the value, skip it.
79
+ // If the variable is found in the value, skip it.
84
80
  if (
85
- Object.keys(spacerValues).some(variable =>
86
- new RegExp(`${variable.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(cleanValue),
81
+ sizes.some(variable =>
82
+ new RegExp(`${variable['name'].replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(node.value),
87
83
  )
88
84
  ) {
89
85
  return
90
86
  }
91
87
 
92
- const replacement = Object.keys(spacerValues).find(spacer => spacerValues[spacer] === cleanValue) || null
93
- const valueMatch = replacement ? spacerValues[replacement] : node.value
88
+ const replacement = sizes.find(variable => variable.values.includes(node.value.replace('-', '')))
89
+ const fixable = replacement && valueUnit && !valueUnit.number.includes('-')
94
90
 
95
- if (replacement && context.fix) {
96
- node.value = node.value.replace(valueMatch, replacement)
91
+ if (fixable && context.fix) {
92
+ node.value = node.value.replace(node.value, `var(${replacement['name']})`)
97
93
  } else {
98
94
  problems.push({
99
- index: declarationValueIndex(decl) + node.sourceIndex,
100
- message: messages.rejected(valueMatch, replacement),
95
+ index: declarationValueIndex(declNode) + node.sourceIndex,
96
+ endIndex: declarationValueIndex(declNode) + node.sourceIndex + node.value.length,
97
+ message: messages.rejected(node.value, replacement),
101
98
  })
102
99
  }
103
100
 
@@ -105,15 +102,16 @@ export default stylelint.createPlugin(ruleName, (enabled, options = {}, context)
105
102
  })
106
103
 
107
104
  if (context.fix) {
108
- decl.value = parsedValue.toString()
105
+ declNode.value = parsedValue.toString()
109
106
  }
110
107
 
111
108
  if (problems.length) {
112
109
  for (const err of problems) {
113
- stylelint.utils.report({
110
+ report({
114
111
  index: err.index,
112
+ endIndex: err.endIndex,
115
113
  message: err.message,
116
- node: decl,
114
+ node: declNode,
117
115
  result,
118
116
  ruleName,
119
117
  })
@@ -121,8 +119,12 @@ export default stylelint.createPlugin(ruleName, (enabled, options = {}, context)
121
119
  }
122
120
  })
123
121
  }
122
+ }
124
123
 
125
- return lintResult
126
- })
124
+ ruleFunction.ruleName = ruleName
125
+ ruleFunction.messages = messages
126
+ ruleFunction.meta = {
127
+ fixable: true,
128
+ }
127
129
 
128
- function noop() {}
130
+ export default createPlugin(ruleName, ruleFunction)
@@ -1,526 +0,0 @@
1
- // Meant as temp until we can move to primitives or css
2
- const colorTypes = ['accent', 'success', 'attention', 'severe', 'danger', 'open', 'closed', 'done', 'sponsors']
3
-
4
- export default {
5
- color: [
6
- {
7
- value: 'var(--color-fg-default)',
8
- utilityClass: 'color-fg-default',
9
- },
10
- {
11
- value: 'var(--color-fg-muted)',
12
- utilityClass: 'color-fg-muted',
13
- },
14
- {
15
- value: 'var(--color-fg-subtle)',
16
- utilityClass: 'color-fg-subtle',
17
- },
18
- ].concat(
19
- colorTypes.map(type => {
20
- return {
21
- value: `var(--color-${type}-fg)`,
22
- utilityClass: `color-fg-${type}`,
23
- }
24
- }),
25
- ),
26
- 'background-color': [
27
- {
28
- value: 'var(--color-canvas-default)',
29
- utilityClass: 'color-bg-default',
30
- },
31
- {
32
- value: 'var(--color-canvas-overlay)',
33
- utilityClass: 'color-bg-overlay',
34
- },
35
- {
36
- value: 'var(--color-canvas-inset)',
37
- utilityClass: 'color-bg-inset',
38
- },
39
- {
40
- value: 'var(--color-canvas-subtle)',
41
- utilityClass: 'color-bg-subtle',
42
- },
43
- {
44
- value: 'transparent',
45
- utilityClass: 'color-bg-transparent',
46
- },
47
- ]
48
- .concat(
49
- colorTypes.map(type => {
50
- return {
51
- value: `var(--color-${type}-subtle)`,
52
- utilityClass: `color-bg-${type}`,
53
- }
54
- }),
55
- )
56
- .concat(
57
- colorTypes.map(type => {
58
- return {
59
- value: `var(--color-${type}-emphasis)`,
60
- utilityClass: `color-bg-${type}-emphasis`,
61
- }
62
- }),
63
- ),
64
- 'border-color': [
65
- {
66
- value: 'var(--color-border-default',
67
- utilityClass: 'color-border-default',
68
- },
69
- {
70
- value: 'var(--color-border-muted',
71
- utilityClass: 'color-border-muted',
72
- },
73
- {
74
- value: 'var(--color-border-subtle',
75
- utilityClass: 'color-border-subtle',
76
- },
77
- ]
78
- .concat(
79
- colorTypes.map(type => {
80
- return {
81
- value: `var(--color-${type}-muted)`,
82
- utilityClass: `color-border-${type}`,
83
- }
84
- }),
85
- )
86
- .concat(
87
- colorTypes.map(type => {
88
- return {
89
- value: `var(--color-${type}-emphasis)`,
90
- utilityClass: `color-border-${type}-emphasis`,
91
- }
92
- }),
93
- ),
94
- margin: Array.from(new Array(6)).map((_, i) => {
95
- return {
96
- value: `$spacer-${i + 1}`,
97
- utilityClass: `m-${i + 1}`,
98
- }
99
- }),
100
- 'margin-top': Array.from(new Array(6)).map((_, i) => {
101
- return {
102
- value: `$spacer-${i + 1}`,
103
- utilityClass: `mt-${i + 1}`,
104
- }
105
- }),
106
- 'margin-right': Array.from(new Array(6)).map((_, i) => {
107
- return {
108
- value: `$spacer-${i + 1}`,
109
- utilityClass: `mr-${i + 1}`,
110
- }
111
- }),
112
- 'margin-bottom': Array.from(new Array(6)).map((_, i) => {
113
- return {
114
- value: `$spacer-${i + 1}`,
115
- utilityClass: `mb-${i + 1}`,
116
- }
117
- }),
118
- 'margin-left': Array.from(new Array(6)).map((_, i) => {
119
- return {
120
- value: `$spacer-${i + 1}`,
121
- utilityClass: `ml-${i + 1}`,
122
- }
123
- }),
124
- padding: Array.from(new Array(6)).map((_, i) => {
125
- return {
126
- value: `$spacer-${i + 1}`,
127
- utilityClass: `p-${i + 1}`,
128
- }
129
- }),
130
- 'padding-top': Array.from(new Array(6)).map((_, i) => {
131
- return {
132
- value: `$spacer-${i + 1}`,
133
- utilityClass: `pt-${i + 1}`,
134
- }
135
- }),
136
- 'padding-right': Array.from(new Array(6)).map((_, i) => {
137
- return {
138
- value: `$spacer-${i + 1}`,
139
- utilityClass: `pr-${i + 1}`,
140
- }
141
- }),
142
- 'padding-bottom': Array.from(new Array(6)).map((_, i) => {
143
- return {
144
- value: `$spacer-${i + 1}`,
145
- utilityClass: `pb-${i + 1}`,
146
- }
147
- }),
148
- 'padding-left': Array.from(new Array(6)).map((_, i) => {
149
- return {
150
- value: `$spacer-${i + 1}`,
151
- utilityClass: `pl-${i + 1}`,
152
- }
153
- }),
154
- 'line-height': [
155
- {
156
- value: '$lh-condensed-ultra',
157
- utilityClass: 'lh-condensed-ultra',
158
- },
159
- {
160
- value: '$lh-condensed',
161
- utilityClass: 'lh-condensed',
162
- },
163
- {
164
- value: '$lh-default',
165
- utilityClass: 'lh-default',
166
- },
167
- {
168
- value: '0',
169
- utilityClass: 'lh-0',
170
- },
171
- ],
172
- 'text-align': [
173
- {
174
- value: 'left',
175
- utilityClass: 'text-left',
176
- },
177
- {
178
- value: 'right',
179
- utilityClass: 'text-right',
180
- },
181
- {
182
- value: 'center',
183
- utilityClass: 'text-center',
184
- },
185
- ],
186
- 'font-style': [
187
- {
188
- value: 'italic',
189
- utilityClass: 'text-italic',
190
- },
191
- ],
192
- 'text-transform': [
193
- {
194
- value: 'uppercase',
195
- utilityClass: 'text-uppercase',
196
- },
197
- ],
198
- 'text-decoration': [
199
- {
200
- value: 'underline',
201
- utilityClass: 'text-underline',
202
- },
203
- {
204
- value: 'none',
205
- utilityClass: 'no-underline',
206
- },
207
- ],
208
- 'white-space': [
209
- {
210
- value: 'nowrap',
211
- utilityClass: 'no-wrap',
212
- },
213
- {
214
- value: 'normal',
215
- utilityClass: 'ws-normal',
216
- },
217
- ],
218
- 'word-break': [
219
- {
220
- value: 'break-all',
221
- utilityClass: 'wb-break-all',
222
- },
223
- ],
224
- width: [
225
- {
226
- value: '100%',
227
- utilityClass: 'width-full',
228
- },
229
- {
230
- value: 'auto%',
231
- utilityClass: 'width-auto',
232
- },
233
- ],
234
- overflow: [
235
- {
236
- value: 'visible',
237
- utilityClass: 'overflow-visible',
238
- },
239
- {
240
- value: 'hidden',
241
- utilityClass: 'overflow-hidden',
242
- },
243
- {
244
- value: 'auto',
245
- utilityClass: 'overflow-auto',
246
- },
247
- {
248
- value: 'scroll',
249
- utilityClass: 'overflow-scroll',
250
- },
251
- ],
252
- 'overflow-x': [
253
- {
254
- value: 'visible',
255
- utilityClass: 'overflow-x-visible',
256
- },
257
- {
258
- value: 'hidden',
259
- utilityClass: 'overflow-x-hidden',
260
- },
261
- {
262
- value: 'auto',
263
- utilityClass: 'overflow-x-auto',
264
- },
265
- {
266
- value: 'scroll',
267
- utilityClass: 'overflow-x-scroll',
268
- },
269
- ],
270
- 'overflow-y': [
271
- {
272
- value: 'visible',
273
- utilityClass: 'overflow-y-visible',
274
- },
275
- {
276
- value: 'hidden',
277
- utilityClass: 'overflow-y-hidden',
278
- },
279
- {
280
- value: 'auto',
281
- utilityClass: 'overflow-y-auto',
282
- },
283
- {
284
- value: 'scroll',
285
- utilityClass: 'overflow-y-scroll',
286
- },
287
- ],
288
- height: [
289
- {
290
- value: '100%',
291
- utilityClass: 'height-full',
292
- },
293
- ],
294
- 'max-width': [
295
- {
296
- value: '100%',
297
- utilityClass: 'width-fit',
298
- },
299
- ],
300
- 'max-height': [
301
- {
302
- value: '100%',
303
- utilityClass: 'height-fit',
304
- },
305
- ],
306
- 'min-width': [
307
- {
308
- value: '0',
309
- utilityClass: 'min-width-0',
310
- },
311
- ],
312
- float: [
313
- {
314
- value: 'left',
315
- utilityClass: 'float-left',
316
- },
317
- {
318
- value: 'right',
319
- utilityClass: 'float-right',
320
- },
321
- {
322
- value: 'none',
323
- utilityClass: 'float-none',
324
- },
325
- ],
326
- 'list-style': [
327
- {
328
- value: 'none',
329
- utilityClass: 'list-style-none',
330
- },
331
- ],
332
- 'user-select': [
333
- {
334
- value: 'none',
335
- utilityClass: 'user-select-none',
336
- },
337
- ],
338
- visibility: [
339
- {
340
- value: 'hidden',
341
- utilityClass: 'v-hidden',
342
- },
343
- {
344
- value: 'visible',
345
- utilityClass: 'v-visible',
346
- },
347
- ],
348
- 'vertical-align': [
349
- {
350
- value: 'middle',
351
- utilityClass: 'v-align-middle',
352
- },
353
- {
354
- value: 'top',
355
- utilityClass: 'v-align-top',
356
- },
357
- {
358
- value: 'bottom',
359
- utilityClass: 'v-align-bottom',
360
- },
361
- {
362
- value: 'text-top',
363
- utilityClass: 'v-align-text-top',
364
- },
365
- {
366
- value: 'text-bottom',
367
- utilityClass: 'v-align-text-bottom',
368
- },
369
- {
370
- value: 'text-baseline',
371
- utilityClass: 'v-align-baseline',
372
- },
373
- ],
374
- 'font-weight': [
375
- {
376
- value: '$font-weight-normal',
377
- utilityClass: 'text-normal',
378
- },
379
- {
380
- value: '$font-weight-bold',
381
- utilityClass: 'text-bold',
382
- },
383
- {
384
- value: '$font-weight-semibold',
385
- utilityClass: 'text-semibold',
386
- },
387
- {
388
- value: '$font-weight-light',
389
- utilityClass: 'text-light',
390
- },
391
- ],
392
- top: [
393
- {
394
- value: '0',
395
- utilityClass: 'top-0',
396
- },
397
- {
398
- value: 'auto',
399
- utilityClass: 'top-auto',
400
- },
401
- ],
402
- right: [
403
- {
404
- value: '0',
405
- utilityClass: 'right-0',
406
- },
407
- {
408
- value: 'auto',
409
- utilityClass: 'right-auto',
410
- },
411
- ],
412
- bottom: [
413
- {
414
- value: '0',
415
- utilityClass: 'bottom-0',
416
- },
417
- {
418
- value: 'auto',
419
- utilityClass: 'bottom-auto',
420
- },
421
- ],
422
- left: [
423
- {
424
- value: '0',
425
- utilityClass: 'left-0',
426
- },
427
- {
428
- value: 'auto',
429
- utilityClass: 'left-auto',
430
- },
431
- ],
432
- position: [
433
- {
434
- value: 'static',
435
- utilityClass: 'position-static',
436
- },
437
- {
438
- value: 'relative',
439
- utilityClass: 'position-relative',
440
- },
441
- {
442
- value: 'absolute',
443
- utilityClass: 'position-absolute',
444
- },
445
- {
446
- value: 'fixed',
447
- utilityClass: 'position-fixed',
448
- },
449
- {
450
- value: 'sticky',
451
- utilityClass: 'position-sticky',
452
- },
453
- ],
454
- 'box-shadow': [
455
- {
456
- value: 'none',
457
- utilityClass: 'box-shadow-none',
458
- },
459
- {
460
- value: 'var(--color-shadow-small)',
461
- utilityClass: 'box-shadow-small',
462
- },
463
- {
464
- value: 'var(--color-shadow-medium)',
465
- utilityClass: 'box-shadow-medium',
466
- },
467
- {
468
- value: 'var(--color-shadow-large)',
469
- utilityClass: 'box-shadow-large',
470
- },
471
- {
472
- value: 'var(--color-shadow-extra-large)',
473
- utilityClass: 'box-shadow-extra-large',
474
- },
475
- ],
476
- border: [
477
- {
478
- value: '$border',
479
- utilityClass: 'border',
480
- },
481
- {
482
- value: '0',
483
- utilityClass: 'border-0',
484
- },
485
- ],
486
- 'border-top': [
487
- {
488
- value: '$border',
489
- utilityClass: 'border-top',
490
- },
491
- {
492
- value: '0',
493
- utilityClass: 'border-top-0',
494
- },
495
- ],
496
- 'border-right': [
497
- {
498
- value: '$border',
499
- utilityClass: 'border-right',
500
- },
501
- {
502
- value: '0',
503
- utilityClass: 'border-right-0',
504
- },
505
- ],
506
- 'border-bottom': [
507
- {
508
- value: '$border',
509
- utilityClass: 'border-bottom',
510
- },
511
- {
512
- value: '0',
513
- utilityClass: 'border-bottom-0',
514
- },
515
- ],
516
- 'border-left': [
517
- {
518
- value: '$border',
519
- utilityClass: 'border-left',
520
- },
521
- {
522
- value: '0',
523
- utilityClass: 'border-left-0',
524
- },
525
- ],
526
- }