@primer/stylelint-config 13.0.0-rc.77d8c5f → 13.0.0-rc.7a254e8
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.
- package/dist/index.cjs +469 -175
- package/dist/index.mjs +469 -175
- package/package.json +10 -15
- package/plugins/borders.js +196 -63
- package/plugins/lib/utils.js +49 -0
- package/plugins/spacing.js +20 -23
- package/plugins/typography.js +185 -23
- package/plugins/lib/primitives.js +0 -36
package/dist/index.cjs
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
var browsers = require('@github/browserslist-config');
|
|
4
4
|
var stylelint = require('stylelint');
|
|
5
|
-
var anymatch = require('anymatch');
|
|
6
|
-
var valueParser = require('postcss-value-parser');
|
|
7
|
-
var TapMap = require('tap-map');
|
|
8
|
-
var variables = require('@primer/css/dist/variables.json');
|
|
9
5
|
var declarationValueIndex = require('stylelint/lib/utils/declarationValueIndex.cjs');
|
|
6
|
+
var valueParser = require('postcss-value-parser');
|
|
10
7
|
var node_module = require('node:module');
|
|
8
|
+
var anymatch = require('anymatch');
|
|
9
|
+
var TapMap = require('tap-map');
|
|
10
|
+
var variables$2 = require('@primer/css/dist/variables.json');
|
|
11
11
|
var matchAll = require('string.prototype.matchall');
|
|
12
12
|
|
|
13
13
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -184,6 +184,247 @@ var propertyOrder = [
|
|
|
184
184
|
'animation-direction',
|
|
185
185
|
];
|
|
186
186
|
|
|
187
|
+
const require$2 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
188
|
+
|
|
189
|
+
function primitivesVariables(type) {
|
|
190
|
+
const variables = [];
|
|
191
|
+
|
|
192
|
+
const files = [];
|
|
193
|
+
switch (type) {
|
|
194
|
+
case 'spacing':
|
|
195
|
+
files.push('base/size/size.json');
|
|
196
|
+
break
|
|
197
|
+
case 'border':
|
|
198
|
+
files.push('functional/size/border.json');
|
|
199
|
+
break
|
|
200
|
+
case 'typography':
|
|
201
|
+
files.push('base/typography/typography.json');
|
|
202
|
+
files.push('functional/typography/typography.json');
|
|
203
|
+
break
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
for (const file of files) {
|
|
207
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
208
|
+
const data = require$2(`@primer/primitives/dist/styleLint/${file}`);
|
|
209
|
+
|
|
210
|
+
for (const key of Object.keys(data)) {
|
|
211
|
+
const size = data[key];
|
|
212
|
+
const values = typeof size['value'] === 'string' ? [size['value']] : size['value'];
|
|
213
|
+
|
|
214
|
+
variables.push({
|
|
215
|
+
name: `--${size['name']}`,
|
|
216
|
+
values,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return variables
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function walkGroups$1(root, validate) {
|
|
225
|
+
for (const node of root.nodes) {
|
|
226
|
+
if (node.type === 'function') {
|
|
227
|
+
walkGroups$1(node, validate);
|
|
228
|
+
} else {
|
|
229
|
+
validate(node);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return root
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const {
|
|
236
|
+
createPlugin: createPlugin$2,
|
|
237
|
+
utils: {report: report$2, ruleMessages: ruleMessages$2, validateOptions: validateOptions$2},
|
|
238
|
+
} = stylelint;
|
|
239
|
+
|
|
240
|
+
const ruleName$4 = 'primer/borders';
|
|
241
|
+
const messages$4 = ruleMessages$2(ruleName$4, {
|
|
242
|
+
rejected: (value, replacement, propName) => {
|
|
243
|
+
if (propName && propName.includes('radius') && value.includes('borderWidth')) {
|
|
244
|
+
return `Border radius variables can not be used for border widths`
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if ((propName && propName.includes('width')) || (borderShorthand(propName) && value.includes('borderRadius'))) {
|
|
248
|
+
return `Border width variables can not be used for border radii`
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!replacement) {
|
|
252
|
+
return `Please use a Primer border variable instead of '${value}'. Consult the primer docs for a suitable replacement. https://primer.style/foundations/primitives/size#border`
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return `Please replace '${value}' with a Primer border variable '${replacement['name']}'. https://primer.style/foundations/primitives/size#border`
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const variables$1 = primitivesVariables('border');
|
|
260
|
+
const sizes$1 = [];
|
|
261
|
+
const radii = [];
|
|
262
|
+
|
|
263
|
+
// Props that we want to check
|
|
264
|
+
const propList$2 = ['border', 'border-width', 'border-radius'];
|
|
265
|
+
// Values that we want to ignore
|
|
266
|
+
const valueList$1 = ['${'];
|
|
267
|
+
|
|
268
|
+
const borderShorthand = prop =>
|
|
269
|
+
/^border(-(top|right|bottom|left|block-start|block-end|inline-start|inline-end))?$/.test(prop);
|
|
270
|
+
|
|
271
|
+
for (const variable of variables$1) {
|
|
272
|
+
const name = variable['name'];
|
|
273
|
+
|
|
274
|
+
if (name.includes('borderWidth')) {
|
|
275
|
+
const value = variable['values']
|
|
276
|
+
.pop()
|
|
277
|
+
.replace(/max|\(|\)/g, '')
|
|
278
|
+
.split(',')[0];
|
|
279
|
+
sizes$1.push({
|
|
280
|
+
name,
|
|
281
|
+
values: [value],
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (name.includes('borderRadius')) {
|
|
286
|
+
radii.push(variable);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** @type {import('stylelint').Rule} */
|
|
291
|
+
const ruleFunction$2 = (primary, secondaryOptions, context) => {
|
|
292
|
+
return (root, result) => {
|
|
293
|
+
const validOptions = validateOptions$2(result, ruleName$4, {
|
|
294
|
+
actual: primary,
|
|
295
|
+
possible: [true],
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
if (!validOptions) return
|
|
299
|
+
|
|
300
|
+
root.walkDecls(declNode => {
|
|
301
|
+
const {prop, value} = declNode;
|
|
302
|
+
|
|
303
|
+
if (!propList$2.some(borderProp => prop.startsWith(borderProp))) return
|
|
304
|
+
if (/^border(-(top|right|bottom|left|block-start|block-end|inline-start|inline-end))?-color$/.test(prop)) return
|
|
305
|
+
if (valueList$1.some(valueToIgnore => value.includes(valueToIgnore))) return
|
|
306
|
+
|
|
307
|
+
const problems = [];
|
|
308
|
+
|
|
309
|
+
const parsedValue = walkGroups$1(valueParser(value), node => {
|
|
310
|
+
const checkForVariable = (vars, nodeValue) =>
|
|
311
|
+
vars.some(variable =>
|
|
312
|
+
new RegExp(`${variable['name'].replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(nodeValue),
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
// Only check word types. https://github.com/TrySound/postcss-value-parser#word
|
|
316
|
+
if (node.type !== 'word') {
|
|
317
|
+
return
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Exact values to ignore.
|
|
321
|
+
if (
|
|
322
|
+
[
|
|
323
|
+
'*',
|
|
324
|
+
'+',
|
|
325
|
+
'-',
|
|
326
|
+
'/',
|
|
327
|
+
'0',
|
|
328
|
+
'none',
|
|
329
|
+
'inherit',
|
|
330
|
+
'initial',
|
|
331
|
+
'revert',
|
|
332
|
+
'revert-layer',
|
|
333
|
+
'unset',
|
|
334
|
+
'solid',
|
|
335
|
+
'dashed',
|
|
336
|
+
'dotted',
|
|
337
|
+
'transparent',
|
|
338
|
+
].includes(node.value)
|
|
339
|
+
) {
|
|
340
|
+
return
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const valueUnit = valueParser.unit(node.value);
|
|
344
|
+
|
|
345
|
+
if (valueUnit && (valueUnit.unit === '' || !/^-?[0-9.]+$/.test(valueUnit.number))) {
|
|
346
|
+
return
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Skip if the value unit isn't a supported unit.
|
|
350
|
+
if (valueUnit && !['px', 'rem', 'em'].includes(valueUnit.unit)) {
|
|
351
|
+
return
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// if we're looking at the border property that sets color in shorthand, don't bother checking the color
|
|
355
|
+
if (
|
|
356
|
+
// using border shorthand
|
|
357
|
+
borderShorthand(prop) &&
|
|
358
|
+
// includes a color as a third space-separated value
|
|
359
|
+
value.split(' ').length > 2 &&
|
|
360
|
+
// the color in the third space-separated value includes `node.value`
|
|
361
|
+
value
|
|
362
|
+
.split(' ')
|
|
363
|
+
.slice(2)
|
|
364
|
+
.some(color => color.includes(node.value))
|
|
365
|
+
) {
|
|
366
|
+
return
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// If the variable is found in the value, skip it.
|
|
370
|
+
if (prop.includes('width') || borderShorthand(prop)) {
|
|
371
|
+
if (checkForVariable(sizes$1, node.value)) {
|
|
372
|
+
return
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (prop.includes('radius')) {
|
|
377
|
+
if (checkForVariable(radii, node.value)) {
|
|
378
|
+
return
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const replacement = (prop.includes('radius') ? radii : sizes$1).find(variable =>
|
|
383
|
+
variable.values.includes(node.value.replace('-', '')),
|
|
384
|
+
);
|
|
385
|
+
const fixable = replacement && valueUnit && !valueUnit.number.includes('-');
|
|
386
|
+
|
|
387
|
+
if (fixable && context.fix) {
|
|
388
|
+
node.value = node.value.replace(node.value, `var(${replacement['name']})`);
|
|
389
|
+
} else {
|
|
390
|
+
problems.push({
|
|
391
|
+
index: declarationValueIndex(declNode) + node.sourceIndex,
|
|
392
|
+
endIndex: declarationValueIndex(declNode) + node.sourceIndex + node.value.length,
|
|
393
|
+
message: messages$4.rejected(node.value, replacement, prop),
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
if (context.fix) {
|
|
401
|
+
declNode.value = parsedValue.toString();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (problems.length) {
|
|
405
|
+
for (const err of problems) {
|
|
406
|
+
report$2({
|
|
407
|
+
index: err.index,
|
|
408
|
+
endIndex: err.endIndex,
|
|
409
|
+
message: err.message,
|
|
410
|
+
node: declNode,
|
|
411
|
+
result,
|
|
412
|
+
ruleName: ruleName$4,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
ruleFunction$2.ruleName = ruleName$4;
|
|
421
|
+
ruleFunction$2.messages = messages$4;
|
|
422
|
+
ruleFunction$2.meta = {
|
|
423
|
+
fixable: true,
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
var borders = createPlugin$2(ruleName$4, ruleFunction$2);
|
|
427
|
+
|
|
187
428
|
const SKIP_VALUE_NODE_TYPES = new Set(['space', 'div']);
|
|
188
429
|
const SKIP_AT_RULE_NAMES = new Set(['each', 'for', 'function', 'mixin']);
|
|
189
430
|
|
|
@@ -428,18 +669,18 @@ function createVariableRule(ruleName, rules, url) {
|
|
|
428
669
|
let actualRules = rules;
|
|
429
670
|
let overrides = options.rules;
|
|
430
671
|
if (typeof rules === 'function') {
|
|
431
|
-
actualRules = rules({variables, options, ruleName});
|
|
672
|
+
actualRules = rules({variables: variables$2, options, ruleName});
|
|
432
673
|
} else {
|
|
433
674
|
actualRules = Object.assign({}, rules);
|
|
434
675
|
}
|
|
435
676
|
if (typeof overrides === 'function') {
|
|
436
677
|
delete options.rules;
|
|
437
|
-
overrides = overrides({rules: actualRules, options, ruleName, variables});
|
|
678
|
+
overrides = overrides({rules: actualRules, options, ruleName, variables: variables$2});
|
|
438
679
|
}
|
|
439
680
|
if (overrides) {
|
|
440
681
|
Object.assign(actualRules, overrides);
|
|
441
682
|
}
|
|
442
|
-
const validate = declarationValidator(actualRules, {variables});
|
|
683
|
+
const validate = declarationValidator(actualRules, {variables: variables$2});
|
|
443
684
|
|
|
444
685
|
// The stylelint docs suggest respecting a "disableFix" rule option that
|
|
445
686
|
// overrides the "global" context.fix (--fix) linting option.
|
|
@@ -501,69 +742,6 @@ function createVariableRule(ruleName, rules, url) {
|
|
|
501
742
|
|
|
502
743
|
function noop$2() {}
|
|
503
744
|
|
|
504
|
-
var borders = createVariableRule(
|
|
505
|
-
'primer/borders',
|
|
506
|
-
{
|
|
507
|
-
border: {
|
|
508
|
-
expects: 'a border variable',
|
|
509
|
-
props: 'border{,-top,-right,-bottom,-left}',
|
|
510
|
-
values: ['$border', 'none', '0'],
|
|
511
|
-
components: ['border-width', 'border-style', 'border-color'],
|
|
512
|
-
replacements: {
|
|
513
|
-
// because shorthand border properties ¯\_(ツ)_/¯
|
|
514
|
-
'$border-width $border-style $border-gray': '$border',
|
|
515
|
-
'$border-width $border-gray $border-style': '$border',
|
|
516
|
-
'$border-style $border-width $border-gray': '$border',
|
|
517
|
-
'$border-style $border-gray $border-width': '$border',
|
|
518
|
-
'$border-gray $border-width $border-style': '$border',
|
|
519
|
-
'$border-gray $border-style $border-width': '$border',
|
|
520
|
-
'$border-width $border-style $border-color': '$border',
|
|
521
|
-
'$border-width $border-color $border-style': '$border',
|
|
522
|
-
'$border-style $border-width $border-color': '$border',
|
|
523
|
-
'$border-style $border-color $border-width': '$border',
|
|
524
|
-
'$border-color $border-width $border-style': '$border',
|
|
525
|
-
'$border-color $border-style $border-width': '$border',
|
|
526
|
-
},
|
|
527
|
-
},
|
|
528
|
-
'border color': {
|
|
529
|
-
expects: 'a border color variable',
|
|
530
|
-
props: 'border{,-top,-right,-bottom,-left}-color',
|
|
531
|
-
values: [
|
|
532
|
-
'$border-*',
|
|
533
|
-
'transparent',
|
|
534
|
-
'currentColor',
|
|
535
|
-
// Match variables in any of the following formats: --color-border-*, --color-*-border-*, --color-*-border, --borderColor-, *borderColor*
|
|
536
|
-
/var\(--color-(.+-)*border(-.+)*\)/,
|
|
537
|
-
/var\(--color-[^)]+\)/,
|
|
538
|
-
/var\(--borderColor-[^)]+\)/,
|
|
539
|
-
/var\((.+-)*borderColor(-.+)*\)/,
|
|
540
|
-
],
|
|
541
|
-
replacements: {
|
|
542
|
-
'$border-gray': '$border-color',
|
|
543
|
-
},
|
|
544
|
-
},
|
|
545
|
-
'border style': {
|
|
546
|
-
expects: 'a border style variable',
|
|
547
|
-
props: 'border{,-top,-right,-bottom,-left}-style',
|
|
548
|
-
values: ['$border-style', 'none'],
|
|
549
|
-
},
|
|
550
|
-
'border width': {
|
|
551
|
-
expects: 'a border width variable',
|
|
552
|
-
props: 'border{,-top,-right,-bottom,-left}-width',
|
|
553
|
-
values: ['$border-width*', '0'],
|
|
554
|
-
},
|
|
555
|
-
'border radius': {
|
|
556
|
-
expects: 'a border radius variable',
|
|
557
|
-
props: 'border{,-{top,bottom}-{left,right}}-radius',
|
|
558
|
-
values: ['$border-radius', '0', '50%', 'inherit'],
|
|
559
|
-
replacements: {
|
|
560
|
-
'100%': '50%',
|
|
561
|
-
},
|
|
562
|
-
},
|
|
563
|
-
},
|
|
564
|
-
'https://primer.style/css/utilities/borders',
|
|
565
|
-
);
|
|
566
|
-
|
|
567
745
|
var boxShadow = createVariableRule(
|
|
568
746
|
'primer/box-shadow',
|
|
569
747
|
{
|
|
@@ -627,9 +805,9 @@ var colors = createVariableRule(
|
|
|
627
805
|
'https://primer.style/primitives/colors',
|
|
628
806
|
);
|
|
629
807
|
|
|
630
|
-
const ruleName$
|
|
808
|
+
const ruleName$3 = 'primer/responsive-widths';
|
|
631
809
|
|
|
632
|
-
const messages$
|
|
810
|
+
const messages$3 = stylelint.utils.ruleMessages(ruleName$3, {
|
|
633
811
|
rejected: value => {
|
|
634
812
|
return `A value larger than the smallest viewport could break responsive pages. Use a width value smaller than ${value}. https://primer.style/css/support/breakpoints`
|
|
635
813
|
},
|
|
@@ -637,10 +815,10 @@ const messages$2 = stylelint.utils.ruleMessages(ruleName$2, {
|
|
|
637
815
|
|
|
638
816
|
// 320px is the smallest viewport size that we support
|
|
639
817
|
|
|
640
|
-
const walkGroups
|
|
818
|
+
const walkGroups = (root, validate) => {
|
|
641
819
|
for (const node of root.nodes) {
|
|
642
820
|
if (node.type === 'function') {
|
|
643
|
-
walkGroups
|
|
821
|
+
walkGroups(node, validate);
|
|
644
822
|
} else {
|
|
645
823
|
validate(node);
|
|
646
824
|
}
|
|
@@ -649,7 +827,7 @@ const walkGroups$1 = (root, validate) => {
|
|
|
649
827
|
};
|
|
650
828
|
|
|
651
829
|
// eslint-disable-next-line no-unused-vars
|
|
652
|
-
var responsiveWidths = stylelint.createPlugin(ruleName$
|
|
830
|
+
var responsiveWidths = stylelint.createPlugin(ruleName$3, (enabled, options = {}, context) => {
|
|
653
831
|
if (!enabled) {
|
|
654
832
|
return noop$1
|
|
655
833
|
}
|
|
@@ -667,7 +845,7 @@ var responsiveWidths = stylelint.createPlugin(ruleName$2, (enabled, options = {}
|
|
|
667
845
|
|
|
668
846
|
const problems = [];
|
|
669
847
|
|
|
670
|
-
walkGroups
|
|
848
|
+
walkGroups(valueParser(decl.value), node => {
|
|
671
849
|
// Only check word types. https://github.com/TrySound/postcss-value-parser#word
|
|
672
850
|
if (node.type !== 'word') {
|
|
673
851
|
return
|
|
@@ -685,7 +863,7 @@ var responsiveWidths = stylelint.createPlugin(ruleName$2, (enabled, options = {}
|
|
|
685
863
|
if (parseInt(valueUnit.number) > 320) {
|
|
686
864
|
problems.push({
|
|
687
865
|
index: declarationValueIndex(decl) + node.sourceIndex,
|
|
688
|
-
message: messages$
|
|
866
|
+
message: messages$3.rejected(node.value),
|
|
689
867
|
});
|
|
690
868
|
}
|
|
691
869
|
break
|
|
@@ -693,7 +871,7 @@ var responsiveWidths = stylelint.createPlugin(ruleName$2, (enabled, options = {}
|
|
|
693
871
|
if (parseInt(valueUnit.number) > 100) {
|
|
694
872
|
problems.push({
|
|
695
873
|
index: declarationValueIndex(decl) + node.sourceIndex,
|
|
696
|
-
message: messages$
|
|
874
|
+
message: messages$3.rejected(node.value),
|
|
697
875
|
});
|
|
698
876
|
}
|
|
699
877
|
break
|
|
@@ -707,7 +885,7 @@ var responsiveWidths = stylelint.createPlugin(ruleName$2, (enabled, options = {}
|
|
|
707
885
|
message: err.message,
|
|
708
886
|
node: decl,
|
|
709
887
|
result,
|
|
710
|
-
ruleName: ruleName$
|
|
888
|
+
ruleName: ruleName$3,
|
|
711
889
|
});
|
|
712
890
|
}
|
|
713
891
|
}
|
|
@@ -719,59 +897,13 @@ var responsiveWidths = stylelint.createPlugin(ruleName$2, (enabled, options = {}
|
|
|
719
897
|
|
|
720
898
|
function noop$1() {}
|
|
721
899
|
|
|
722
|
-
const require$2 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
723
|
-
|
|
724
|
-
async function primitivesVariables(type) {
|
|
725
|
-
const variables = [];
|
|
726
|
-
|
|
727
|
-
const files = [];
|
|
728
|
-
switch (type) {
|
|
729
|
-
case 'size':
|
|
730
|
-
files.push('base/size/size.json');
|
|
731
|
-
break
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
for (const file of files) {
|
|
735
|
-
// eslint-disable-next-line import/no-dynamic-require
|
|
736
|
-
const data = require$2(`@primer/primitives/dist/styleLint/${file}`);
|
|
737
|
-
|
|
738
|
-
for (const key of Object.keys(data)) {
|
|
739
|
-
const size = data[key];
|
|
740
|
-
const values = size['value'];
|
|
741
|
-
const intValue = parseInt(size['original']['value']);
|
|
742
|
-
if (![2, 6].includes(intValue)) {
|
|
743
|
-
values.push(`${intValue + 1}px`);
|
|
744
|
-
values.push(`${intValue - 1}px`);
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
variables.push({
|
|
748
|
-
name: `--${size['name']}`,
|
|
749
|
-
values,
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
return variables
|
|
755
|
-
}
|
|
756
|
-
|
|
757
900
|
const {
|
|
758
|
-
createPlugin,
|
|
759
|
-
utils: {report, ruleMessages, validateOptions},
|
|
901
|
+
createPlugin: createPlugin$1,
|
|
902
|
+
utils: {report: report$1, ruleMessages: ruleMessages$1, validateOptions: validateOptions$1},
|
|
760
903
|
} = stylelint;
|
|
761
904
|
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
if (node.type === 'function') {
|
|
765
|
-
walkGroups(node, validate);
|
|
766
|
-
} else {
|
|
767
|
-
validate(node);
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
return root
|
|
771
|
-
};
|
|
772
|
-
|
|
773
|
-
const ruleName$1 = 'primer/spacing';
|
|
774
|
-
const messages$1 = ruleMessages(ruleName$1, {
|
|
905
|
+
const ruleName$2 = 'primer/spacing';
|
|
906
|
+
const messages$2 = ruleMessages$1(ruleName$2, {
|
|
775
907
|
rejected: (value, replacement) => {
|
|
776
908
|
if (!replacement) {
|
|
777
909
|
return `Please use a primer size variable instead of '${value}'. Consult the primer docs for a suitable replacement. https://primer.style/foundations/primitives/size`
|
|
@@ -781,21 +913,27 @@ const messages$1 = ruleMessages(ruleName$1, {
|
|
|
781
913
|
},
|
|
782
914
|
});
|
|
783
915
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
916
|
+
// Props that we want to check
|
|
917
|
+
const propList$1 = ['padding', 'margin', 'top', 'right', 'bottom', 'left'];
|
|
918
|
+
// Values that we want to ignore
|
|
919
|
+
const valueList = ['${'];
|
|
787
920
|
|
|
788
|
-
|
|
789
|
-
const ruleFunction = (primary, secondaryOptions, context) => {
|
|
790
|
-
return async (root, result) => {
|
|
791
|
-
// Props that we want to check
|
|
792
|
-
const propList = ['padding', 'margin', 'top', 'right', 'bottom', 'left'];
|
|
793
|
-
// Values that we want to ignore
|
|
794
|
-
const valueList = ['${'];
|
|
921
|
+
const sizes = primitivesVariables('spacing');
|
|
795
922
|
|
|
796
|
-
|
|
923
|
+
// Add +-1px to each value
|
|
924
|
+
for (const size of sizes) {
|
|
925
|
+
const values = size['values'];
|
|
926
|
+
const px = parseInt(values.find(value => value.includes('px')));
|
|
927
|
+
if (![2, 6].includes(px)) {
|
|
928
|
+
values.push(`${px + 1}px`);
|
|
929
|
+
values.push(`${px - 1}px`);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
797
932
|
|
|
798
|
-
|
|
933
|
+
/** @type {import('stylelint').Rule} */
|
|
934
|
+
const ruleFunction$1 = (primary, secondaryOptions, context) => {
|
|
935
|
+
return (root, result) => {
|
|
936
|
+
const validOptions = validateOptions$1(result, ruleName$2, {
|
|
799
937
|
actual: primary,
|
|
800
938
|
possible: [true],
|
|
801
939
|
});
|
|
@@ -805,12 +943,12 @@ const ruleFunction = (primary, secondaryOptions, context) => {
|
|
|
805
943
|
root.walkDecls(declNode => {
|
|
806
944
|
const {prop, value} = declNode;
|
|
807
945
|
|
|
808
|
-
if (!propList.some(spacingProp => prop.startsWith(spacingProp))) return
|
|
946
|
+
if (!propList$1.some(spacingProp => prop.startsWith(spacingProp))) return
|
|
809
947
|
if (valueList.some(valueToIgnore => value.includes(valueToIgnore))) return
|
|
810
948
|
|
|
811
949
|
const problems = [];
|
|
812
950
|
|
|
813
|
-
const parsedValue = walkGroups(valueParser(value), node => {
|
|
951
|
+
const parsedValue = walkGroups$1(valueParser(value), node => {
|
|
814
952
|
// Only check word types. https://github.com/TrySound/postcss-value-parser#word
|
|
815
953
|
if (node.type !== 'word') {
|
|
816
954
|
return
|
|
@@ -850,7 +988,7 @@ const ruleFunction = (primary, secondaryOptions, context) => {
|
|
|
850
988
|
problems.push({
|
|
851
989
|
index: declarationValueIndex(declNode) + node.sourceIndex,
|
|
852
990
|
endIndex: declarationValueIndex(declNode) + node.sourceIndex + node.value.length,
|
|
853
|
-
message: messages$
|
|
991
|
+
message: messages$2.rejected(node.value, replacement),
|
|
854
992
|
});
|
|
855
993
|
}
|
|
856
994
|
|
|
@@ -861,6 +999,189 @@ const ruleFunction = (primary, secondaryOptions, context) => {
|
|
|
861
999
|
declNode.value = parsedValue.toString();
|
|
862
1000
|
}
|
|
863
1001
|
|
|
1002
|
+
if (problems.length) {
|
|
1003
|
+
for (const err of problems) {
|
|
1004
|
+
report$1({
|
|
1005
|
+
index: err.index,
|
|
1006
|
+
endIndex: err.endIndex,
|
|
1007
|
+
message: err.message,
|
|
1008
|
+
node: declNode,
|
|
1009
|
+
result,
|
|
1010
|
+
ruleName: ruleName$2,
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
ruleFunction$1.ruleName = ruleName$2;
|
|
1019
|
+
ruleFunction$1.messages = messages$2;
|
|
1020
|
+
ruleFunction$1.meta = {
|
|
1021
|
+
fixable: true,
|
|
1022
|
+
};
|
|
1023
|
+
|
|
1024
|
+
var spacing = createPlugin$1(ruleName$2, ruleFunction$1);
|
|
1025
|
+
|
|
1026
|
+
const {
|
|
1027
|
+
createPlugin,
|
|
1028
|
+
utils: {report, ruleMessages, validateOptions},
|
|
1029
|
+
} = stylelint;
|
|
1030
|
+
|
|
1031
|
+
const ruleName$1 = 'primer/typography';
|
|
1032
|
+
const messages$1 = ruleMessages(ruleName$1, {
|
|
1033
|
+
rejected: (value, replacement) => {
|
|
1034
|
+
// no possible replacement
|
|
1035
|
+
if (!replacement) {
|
|
1036
|
+
return `Please use a Primer typography variable instead of '${value}'. Consult the primer docs for a suitable replacement. https://primer.style/foundations/primitives/typography`
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
// multiple possible replacements
|
|
1040
|
+
if (replacement.length) {
|
|
1041
|
+
return `Please use one of the following Primer typography variables instead of '${value}': ${replacement.map(replacementObj => `'${replacementObj.name}'`).join(', ')}. https://primer.style/foundations/primitives/typography`
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// one possible replacement
|
|
1045
|
+
return `Please replace '${value}' with Primer typography variable '${replacement['name']}'. https://primer.style/foundations/primitives/typography`
|
|
1046
|
+
},
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
const fontWeightKeywordMap = {
|
|
1050
|
+
normal: 400,
|
|
1051
|
+
bold: 600,
|
|
1052
|
+
bolder: 600,
|
|
1053
|
+
lighter: 300,
|
|
1054
|
+
};
|
|
1055
|
+
const getClosestFontWeight = (goalWeightNumber, fontWeightsTokens) => {
|
|
1056
|
+
return fontWeightsTokens.reduce((prev, curr) =>
|
|
1057
|
+
Math.abs(curr.values - goalWeightNumber) < Math.abs(prev.values - goalWeightNumber) ? curr : prev,
|
|
1058
|
+
).values
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
const variables = primitivesVariables('typography');
|
|
1062
|
+
const fontSizes = [];
|
|
1063
|
+
const fontWeights = [];
|
|
1064
|
+
const lineHeights = [];
|
|
1065
|
+
const fontStacks = [];
|
|
1066
|
+
const fontShorthands = [];
|
|
1067
|
+
|
|
1068
|
+
// Props that we want to check for typography variables
|
|
1069
|
+
const propList = ['font-size', 'font-weight', 'line-height', 'font-family', 'font'];
|
|
1070
|
+
|
|
1071
|
+
for (const variable of variables) {
|
|
1072
|
+
const name = variable['name'];
|
|
1073
|
+
|
|
1074
|
+
if (name.includes('size')) {
|
|
1075
|
+
fontSizes.push(variable);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
if (name.includes('weight')) {
|
|
1079
|
+
fontWeights.push(variable);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
if (name.includes('lineHeight')) {
|
|
1083
|
+
lineHeights.push(variable);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
if (name.includes('fontStack')) {
|
|
1087
|
+
fontStacks.push(variable);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
if (name.includes('shorthand')) {
|
|
1091
|
+
fontShorthands.push(variable);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/** @type {import('stylelint').Rule} */
|
|
1096
|
+
const ruleFunction = (primary, secondaryOptions, context) => {
|
|
1097
|
+
return (root, result) => {
|
|
1098
|
+
const validOptions = validateOptions(result, ruleName$1, {
|
|
1099
|
+
actual: primary,
|
|
1100
|
+
possible: [true],
|
|
1101
|
+
});
|
|
1102
|
+
let validValues = [];
|
|
1103
|
+
|
|
1104
|
+
if (!validOptions) return
|
|
1105
|
+
|
|
1106
|
+
root.walkDecls(declNode => {
|
|
1107
|
+
const {prop, value} = declNode;
|
|
1108
|
+
|
|
1109
|
+
if (!propList.some(typographyProp => prop.startsWith(typographyProp))) return
|
|
1110
|
+
|
|
1111
|
+
const problems = [];
|
|
1112
|
+
|
|
1113
|
+
const checkForVariable = (vars, nodeValue) =>
|
|
1114
|
+
vars.some(variable =>
|
|
1115
|
+
new RegExp(`${variable['name'].replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(nodeValue),
|
|
1116
|
+
);
|
|
1117
|
+
|
|
1118
|
+
// Exact values to ignore.
|
|
1119
|
+
if (value === 'inherit') {
|
|
1120
|
+
return
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
switch (prop) {
|
|
1124
|
+
case 'font-size':
|
|
1125
|
+
validValues = fontSizes;
|
|
1126
|
+
break
|
|
1127
|
+
case 'font-weight':
|
|
1128
|
+
validValues = fontWeights;
|
|
1129
|
+
break
|
|
1130
|
+
case 'line-height':
|
|
1131
|
+
validValues = lineHeights;
|
|
1132
|
+
break
|
|
1133
|
+
case 'font-family':
|
|
1134
|
+
validValues = fontStacks;
|
|
1135
|
+
break
|
|
1136
|
+
case 'font':
|
|
1137
|
+
validValues = fontShorthands;
|
|
1138
|
+
break
|
|
1139
|
+
default:
|
|
1140
|
+
validValues = [];
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
if (checkForVariable(validValues, value)) {
|
|
1144
|
+
return
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
const getReplacements = () => {
|
|
1148
|
+
const replacementTokens = validValues.filter(variable => {
|
|
1149
|
+
if (!(variable.values instanceof Array)) {
|
|
1150
|
+
let nodeValue = value;
|
|
1151
|
+
|
|
1152
|
+
if (prop === 'font-weight') {
|
|
1153
|
+
nodeValue = getClosestFontWeight(fontWeightKeywordMap[value] || value, fontWeights);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
return variable.values.toString() === nodeValue.toString()
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
return variable.values.includes(value.replace('-', ''))
|
|
1160
|
+
});
|
|
1161
|
+
|
|
1162
|
+
if (!replacementTokens.length) {
|
|
1163
|
+
return
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
if (replacementTokens.length > 1) {
|
|
1167
|
+
return replacementTokens
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
return replacementTokens[0]
|
|
1171
|
+
};
|
|
1172
|
+
const replacement = getReplacements();
|
|
1173
|
+
const fixable = replacement && !replacement.length;
|
|
1174
|
+
|
|
1175
|
+
if (fixable && context.fix) {
|
|
1176
|
+
declNode.value = value.replace(value, `var(${replacement['name']})`);
|
|
1177
|
+
} else {
|
|
1178
|
+
problems.push({
|
|
1179
|
+
index: declarationValueIndex(declNode),
|
|
1180
|
+
endIndex: declarationValueIndex(declNode) + value.length,
|
|
1181
|
+
message: messages$1.rejected(value, replacement, prop),
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
|
|
864
1185
|
if (problems.length) {
|
|
865
1186
|
for (const err of problems) {
|
|
866
1187
|
report({
|
|
@@ -879,32 +1200,11 @@ const ruleFunction = (primary, secondaryOptions, context) => {
|
|
|
879
1200
|
|
|
880
1201
|
ruleFunction.ruleName = ruleName$1;
|
|
881
1202
|
ruleFunction.messages = messages$1;
|
|
882
|
-
ruleFunction.meta =
|
|
883
|
-
|
|
884
|
-
|
|
1203
|
+
ruleFunction.meta = {
|
|
1204
|
+
fixable: true,
|
|
1205
|
+
};
|
|
885
1206
|
|
|
886
|
-
var typography =
|
|
887
|
-
'primer/typography',
|
|
888
|
-
{
|
|
889
|
-
'font-size': {
|
|
890
|
-
expects: 'a font-size variable',
|
|
891
|
-
values: ['$body-font-size', '$h{000,00,0,1,2,3,4,5,6}-size', '$font-size-*', '1', '1em', 'inherit'],
|
|
892
|
-
},
|
|
893
|
-
'font-weight': {
|
|
894
|
-
props: 'font-weight',
|
|
895
|
-
values: ['$font-weight-*', 'inherit'],
|
|
896
|
-
replacements: {
|
|
897
|
-
bold: '$font-weight-bold',
|
|
898
|
-
normal: '$font-weight-normal',
|
|
899
|
-
},
|
|
900
|
-
},
|
|
901
|
-
'line-height': {
|
|
902
|
-
props: 'line-height',
|
|
903
|
-
values: ['$body-line-height', '$lh-*', '0', '1', '1em', 'inherit'],
|
|
904
|
-
},
|
|
905
|
-
},
|
|
906
|
-
'https://primer.style/css/utilities/typography',
|
|
907
|
-
);
|
|
1207
|
+
var typography = createPlugin(ruleName$1, ruleFunction);
|
|
908
1208
|
|
|
909
1209
|
const ruleName = 'primer/no-display-colors';
|
|
910
1210
|
const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
@@ -1089,8 +1389,6 @@ var index = {
|
|
|
1089
1389
|
'length-zero-no-unit': null,
|
|
1090
1390
|
'selector-max-type': null,
|
|
1091
1391
|
'primer/colors': null,
|
|
1092
|
-
'primer/borders': null,
|
|
1093
|
-
'primer/typography': null,
|
|
1094
1392
|
'primer/box-shadow': null,
|
|
1095
1393
|
},
|
|
1096
1394
|
},
|
|
@@ -1116,7 +1414,6 @@ var index = {
|
|
|
1116
1414
|
},
|
|
1117
1415
|
{
|
|
1118
1416
|
files: ['**/*.module.css'],
|
|
1119
|
-
plugins: ['stylelint-css-modules-no-global-scoped-selector'],
|
|
1120
1417
|
rules: {
|
|
1121
1418
|
'property-no-unknown': [
|
|
1122
1419
|
true,
|
|
@@ -1141,10 +1438,7 @@ var index = {
|
|
|
1141
1438
|
ignoreFunctions: ['global'],
|
|
1142
1439
|
},
|
|
1143
1440
|
],
|
|
1144
|
-
'css-modules/no-global-scoped-selector': true,
|
|
1145
1441
|
// temporarily disabiling Primer plugins while we work on upgrades https://github.com/github/primer/issues/3165
|
|
1146
|
-
'primer/borders': null,
|
|
1147
|
-
'primer/typography': null,
|
|
1148
1442
|
'primer/box-shadow': null,
|
|
1149
1443
|
},
|
|
1150
1444
|
},
|