@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 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$2 = 'primer/responsive-widths';
808
+ const ruleName$3 = 'primer/responsive-widths';
631
809
 
632
- const messages$2 = stylelint.utils.ruleMessages(ruleName$2, {
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$1 = (root, validate) => {
818
+ const walkGroups = (root, validate) => {
641
819
  for (const node of root.nodes) {
642
820
  if (node.type === 'function') {
643
- walkGroups$1(node, validate);
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$2, (enabled, options = {}, context) => {
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$1(valueParser(decl.value), node => {
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$2.rejected(node.value),
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$2.rejected(node.value),
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$2,
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 walkGroups = (root, validate) => {
763
- for (const node of root.nodes) {
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
- const meta = {
785
- fixable: true,
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
- /** @type {import('stylelint').Rule} */
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
- const sizes = await primitivesVariables('size');
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
- const validOptions = validateOptions(result, ruleName$1, {
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$1.rejected(node.value, replacement),
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 = meta;
883
-
884
- var spacing = createPlugin(ruleName$1, ruleFunction);
1203
+ ruleFunction.meta = {
1204
+ fixable: true,
1205
+ };
885
1206
 
886
- var typography = createVariableRule(
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
  },