@primer/stylelint-config 13.0.0-rc.864dd2a → 13.0.0-rc.99be5f2
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 +105 -69
- package/dist/index.mjs +105 -69
- package/package.json +9 -3
- package/plugins/lib/primitives.js +33 -0
- package/plugins/spacing.js +68 -63
package/dist/index.cjs
CHANGED
|
@@ -7,8 +7,8 @@ var valueParser = require('postcss-value-parser');
|
|
|
7
7
|
var TapMap = require('tap-map');
|
|
8
8
|
var variables = require('@primer/css/dist/variables.json');
|
|
9
9
|
var declarationValueIndex = require('stylelint/lib/utils/declarationValueIndex.cjs');
|
|
10
|
-
var matchAll = require('string.prototype.matchall');
|
|
11
10
|
var node_module = require('node:module');
|
|
11
|
+
var matchAll = require('string.prototype.matchall');
|
|
12
12
|
|
|
13
13
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
14
14
|
var propertyOrder = [
|
|
@@ -422,7 +422,7 @@ function closest(node, test) {
|
|
|
422
422
|
function createVariableRule(ruleName, rules, url) {
|
|
423
423
|
const plugin = stylelint.createPlugin(ruleName, (enabled, options = {}, context) => {
|
|
424
424
|
if (enabled === false) {
|
|
425
|
-
return noop$
|
|
425
|
+
return noop$3
|
|
426
426
|
}
|
|
427
427
|
|
|
428
428
|
let actualRules = rules;
|
|
@@ -499,7 +499,7 @@ function createVariableRule(ruleName, rules, url) {
|
|
|
499
499
|
return plugin
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
-
function noop$
|
|
502
|
+
function noop$3() {}
|
|
503
503
|
|
|
504
504
|
var borders = createVariableRule(
|
|
505
505
|
'primer/borders',
|
|
@@ -651,7 +651,7 @@ const walkGroups$1 = (root, validate) => {
|
|
|
651
651
|
// eslint-disable-next-line no-unused-vars
|
|
652
652
|
var responsiveWidths = stylelint.createPlugin(ruleName$3, (enabled, options = {}, context) => {
|
|
653
653
|
if (!enabled) {
|
|
654
|
-
return noop$
|
|
654
|
+
return noop$2
|
|
655
655
|
}
|
|
656
656
|
|
|
657
657
|
const lintResult = (root, result) => {
|
|
@@ -662,7 +662,7 @@ var responsiveWidths = stylelint.createPlugin(ruleName$3, (enabled, options = {}
|
|
|
662
662
|
}
|
|
663
663
|
|
|
664
664
|
if (decl.type !== 'decl' || !decl.prop.match(/^(min-width|width)/)) {
|
|
665
|
-
return noop$
|
|
665
|
+
return noop$2
|
|
666
666
|
}
|
|
667
667
|
|
|
668
668
|
const problems = [];
|
|
@@ -717,40 +717,44 @@ var responsiveWidths = stylelint.createPlugin(ruleName$3, (enabled, options = {}
|
|
|
717
717
|
return lintResult
|
|
718
718
|
});
|
|
719
719
|
|
|
720
|
-
function noop$
|
|
720
|
+
function noop$2() {}
|
|
721
721
|
|
|
722
|
-
|
|
723
|
-
const spacerValues = {
|
|
724
|
-
'$spacer-1': '4px',
|
|
725
|
-
'$spacer-2': '8px',
|
|
726
|
-
'$spacer-3': '16px',
|
|
727
|
-
'$spacer-4': '24px',
|
|
728
|
-
'$spacer-5': '32px',
|
|
729
|
-
'$spacer-6': '40px',
|
|
730
|
-
'$spacer-7': '48px',
|
|
731
|
-
'$spacer-8': '64px',
|
|
732
|
-
'$spacer-9': '80px',
|
|
733
|
-
'$spacer-10': '96px',
|
|
734
|
-
'$spacer-11': '112px',
|
|
735
|
-
'$spacer-12': '128px',
|
|
736
|
-
'$em-spacer-1': '0.0625em',
|
|
737
|
-
'$em-spacer-2': '0.125em',
|
|
738
|
-
'$em-spacer-3': '0.25em',
|
|
739
|
-
'$em-spacer-4': '0.375em',
|
|
740
|
-
'$em-spacer-5': '0.5em',
|
|
741
|
-
'$em-spacer-6': '0.75em',
|
|
742
|
-
};
|
|
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)));
|
|
743
723
|
|
|
744
|
-
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
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
|
+
values.push(`${parseInt(size['original']['value']) + 1}px`);
|
|
742
|
+
values.push(`${parseInt(size['original']['value']) - 1}px`);
|
|
743
|
+
|
|
744
|
+
variables.push({
|
|
745
|
+
name: `--${size['name']}`,
|
|
746
|
+
values,
|
|
747
|
+
});
|
|
749
748
|
}
|
|
749
|
+
}
|
|
750
750
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
751
|
+
return variables
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
const {
|
|
755
|
+
createPlugin,
|
|
756
|
+
utils: {report, ruleMessages, validateOptions},
|
|
757
|
+
} = stylelint;
|
|
754
758
|
|
|
755
759
|
const walkGroups = (root, validate) => {
|
|
756
760
|
for (const node of root.nodes) {
|
|
@@ -763,24 +767,47 @@ const walkGroups = (root, validate) => {
|
|
|
763
767
|
return root
|
|
764
768
|
};
|
|
765
769
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
770
|
+
const ruleName$2 = 'primer/spacing';
|
|
771
|
+
const messages$2 = ruleMessages(ruleName$2, {
|
|
772
|
+
rejected: (value, replacement) => {
|
|
773
|
+
if (!replacement) {
|
|
774
|
+
return `Please use a primer size variable instead of '${value}'. Consult the primer docs for a suitable replacement. https://primer.style/foundations/primitives/size`
|
|
775
|
+
}
|
|
771
776
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
return noop$2
|
|
776
|
-
}
|
|
777
|
+
return `Please replace '${value}' with size variable '${replacement['name']}'. https://primer.style/foundations/primitives/size`
|
|
778
|
+
},
|
|
779
|
+
});
|
|
777
780
|
|
|
778
|
-
|
|
781
|
+
const meta = {
|
|
782
|
+
fixable: true,
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
/** @type {import('stylelint').Rule} */
|
|
786
|
+
const ruleFunction = (primary, secondaryOptions, context) => {
|
|
787
|
+
return async (root, result) => {
|
|
788
|
+
// Props that we want to check
|
|
789
|
+
const propList = ['padding', 'margin', 'top', 'right', 'bottom', 'left'];
|
|
790
|
+
// Values that we want to ignore
|
|
791
|
+
const valueList = ['${'];
|
|
792
|
+
|
|
793
|
+
const sizes = await primitivesVariables('size');
|
|
794
|
+
|
|
795
|
+
const validOptions = validateOptions(result, ruleName$2, {
|
|
796
|
+
actual: primary,
|
|
797
|
+
possible: [true],
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
if (!validOptions) return
|
|
801
|
+
|
|
802
|
+
root.walkDecls(declNode => {
|
|
803
|
+
const {prop, value} = declNode;
|
|
779
804
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
const cleanValue = node.value.replace(/^-/g, '');
|
|
805
|
+
if (!propList.some(spacingProp => prop.startsWith(spacingProp))) return
|
|
806
|
+
if (valueList.some(valueToIgnore => value.includes(valueToIgnore))) return
|
|
783
807
|
|
|
808
|
+
const problems = [];
|
|
809
|
+
|
|
810
|
+
const parsedValue = walkGroups(valueParser(value), node => {
|
|
784
811
|
// Only check word types. https://github.com/TrySound/postcss-value-parser#word
|
|
785
812
|
if (node.type !== 'word') {
|
|
786
813
|
return
|
|
@@ -791,30 +818,36 @@ var spacing = stylelint.createPlugin(ruleName$2, (enabled, options = {}, context
|
|
|
791
818
|
return
|
|
792
819
|
}
|
|
793
820
|
|
|
794
|
-
const valueUnit = valueParser.unit(
|
|
821
|
+
const valueUnit = valueParser.unit(node.value);
|
|
795
822
|
|
|
796
|
-
if (valueUnit && (valueUnit.unit === '' ||
|
|
823
|
+
if (valueUnit && (valueUnit.unit === '' || !/^-?[0-9.]+$/.test(valueUnit.number))) {
|
|
797
824
|
return
|
|
798
825
|
}
|
|
799
826
|
|
|
800
|
-
//
|
|
827
|
+
// Skip if the value unit isn't a supported unit.
|
|
828
|
+
if (valueUnit && !['px', 'rem', 'em'].includes(valueUnit.unit)) {
|
|
829
|
+
return
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// If the variable is found in the value, skip it.
|
|
801
833
|
if (
|
|
802
|
-
|
|
803
|
-
new RegExp(`${variable.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(
|
|
834
|
+
sizes.some(variable =>
|
|
835
|
+
new RegExp(`${variable['name'].replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(node.value),
|
|
804
836
|
)
|
|
805
837
|
) {
|
|
806
838
|
return
|
|
807
839
|
}
|
|
808
840
|
|
|
809
|
-
const replacement =
|
|
810
|
-
const
|
|
841
|
+
const replacement = sizes.find(variable => variable.values.includes(node.value.replace('-', '')));
|
|
842
|
+
const fixable = replacement && valueUnit && !valueUnit.number.includes('-');
|
|
811
843
|
|
|
812
|
-
if (
|
|
813
|
-
node.value = node.value.replace(
|
|
844
|
+
if (fixable && context.fix) {
|
|
845
|
+
node.value = node.value.replace(node.value, `var(${replacement['name']})`);
|
|
814
846
|
} else {
|
|
815
847
|
problems.push({
|
|
816
|
-
index: declarationValueIndex(
|
|
817
|
-
|
|
848
|
+
index: declarationValueIndex(declNode) + node.sourceIndex,
|
|
849
|
+
endIndex: declarationValueIndex(declNode) + node.sourceIndex + node.value.length,
|
|
850
|
+
message: messages$2.rejected(node.value, replacement),
|
|
818
851
|
});
|
|
819
852
|
}
|
|
820
853
|
|
|
@@ -822,27 +855,30 @@ var spacing = stylelint.createPlugin(ruleName$2, (enabled, options = {}, context
|
|
|
822
855
|
});
|
|
823
856
|
|
|
824
857
|
if (context.fix) {
|
|
825
|
-
|
|
858
|
+
declNode.value = parsedValue.toString();
|
|
826
859
|
}
|
|
827
860
|
|
|
828
861
|
if (problems.length) {
|
|
829
862
|
for (const err of problems) {
|
|
830
|
-
|
|
863
|
+
report({
|
|
831
864
|
index: err.index,
|
|
865
|
+
endIndex: err.endIndex,
|
|
832
866
|
message: err.message,
|
|
833
|
-
node:
|
|
867
|
+
node: declNode,
|
|
834
868
|
result,
|
|
835
869
|
ruleName: ruleName$2,
|
|
836
870
|
});
|
|
837
871
|
}
|
|
838
872
|
}
|
|
839
873
|
});
|
|
840
|
-
}
|
|
874
|
+
}
|
|
875
|
+
};
|
|
841
876
|
|
|
842
|
-
|
|
843
|
-
|
|
877
|
+
ruleFunction.ruleName = ruleName$2;
|
|
878
|
+
ruleFunction.messages = messages$2;
|
|
879
|
+
ruleFunction.meta = meta;
|
|
844
880
|
|
|
845
|
-
|
|
881
|
+
var spacing = createPlugin(ruleName$2, ruleFunction);
|
|
846
882
|
|
|
847
883
|
var typography = createVariableRule(
|
|
848
884
|
'primer/typography',
|
|
@@ -1628,7 +1664,6 @@ var index = {
|
|
|
1628
1664
|
'comment-empty-line-before': null,
|
|
1629
1665
|
'length-zero-no-unit': null,
|
|
1630
1666
|
'selector-max-type': null,
|
|
1631
|
-
'primer/spacing': null,
|
|
1632
1667
|
'primer/colors': null,
|
|
1633
1668
|
'primer/borders': null,
|
|
1634
1669
|
'primer/typography': null,
|
|
@@ -1658,6 +1693,7 @@ var index = {
|
|
|
1658
1693
|
},
|
|
1659
1694
|
{
|
|
1660
1695
|
files: ['**/*.module.css'],
|
|
1696
|
+
plugins: ['stylelint-css-modules-no-global-scoped-selector'],
|
|
1661
1697
|
rules: {
|
|
1662
1698
|
'property-no-unknown': [
|
|
1663
1699
|
true,
|
|
@@ -1682,8 +1718,8 @@ var index = {
|
|
|
1682
1718
|
ignoreFunctions: ['global'],
|
|
1683
1719
|
},
|
|
1684
1720
|
],
|
|
1721
|
+
'css-modules/no-global-scoped-selector': true,
|
|
1685
1722
|
// temporarily disabiling Primer plugins while we work on upgrades https://github.com/github/primer/issues/3165
|
|
1686
|
-
'primer/spacing': null,
|
|
1687
1723
|
'primer/borders': null,
|
|
1688
1724
|
'primer/typography': null,
|
|
1689
1725
|
'primer/box-shadow': null,
|
package/dist/index.mjs
CHANGED
|
@@ -5,8 +5,8 @@ import valueParser from 'postcss-value-parser';
|
|
|
5
5
|
import TapMap from 'tap-map';
|
|
6
6
|
import variables from '@primer/css/dist/variables.json' assert { type: 'json' };
|
|
7
7
|
import declarationValueIndex from 'stylelint/lib/utils/declarationValueIndex.cjs';
|
|
8
|
-
import matchAll from 'string.prototype.matchall';
|
|
9
8
|
import { createRequire } from 'node:module';
|
|
9
|
+
import matchAll from 'string.prototype.matchall';
|
|
10
10
|
|
|
11
11
|
var propertyOrder = [
|
|
12
12
|
'all',
|
|
@@ -419,7 +419,7 @@ function closest(node, test) {
|
|
|
419
419
|
function createVariableRule(ruleName, rules, url) {
|
|
420
420
|
const plugin = stylelint.createPlugin(ruleName, (enabled, options = {}, context) => {
|
|
421
421
|
if (enabled === false) {
|
|
422
|
-
return noop$
|
|
422
|
+
return noop$3
|
|
423
423
|
}
|
|
424
424
|
|
|
425
425
|
let actualRules = rules;
|
|
@@ -496,7 +496,7 @@ function createVariableRule(ruleName, rules, url) {
|
|
|
496
496
|
return plugin
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
-
function noop$
|
|
499
|
+
function noop$3() {}
|
|
500
500
|
|
|
501
501
|
var borders = createVariableRule(
|
|
502
502
|
'primer/borders',
|
|
@@ -648,7 +648,7 @@ const walkGroups$1 = (root, validate) => {
|
|
|
648
648
|
// eslint-disable-next-line no-unused-vars
|
|
649
649
|
var responsiveWidths = stylelint.createPlugin(ruleName$3, (enabled, options = {}, context) => {
|
|
650
650
|
if (!enabled) {
|
|
651
|
-
return noop$
|
|
651
|
+
return noop$2
|
|
652
652
|
}
|
|
653
653
|
|
|
654
654
|
const lintResult = (root, result) => {
|
|
@@ -659,7 +659,7 @@ var responsiveWidths = stylelint.createPlugin(ruleName$3, (enabled, options = {}
|
|
|
659
659
|
}
|
|
660
660
|
|
|
661
661
|
if (decl.type !== 'decl' || !decl.prop.match(/^(min-width|width)/)) {
|
|
662
|
-
return noop$
|
|
662
|
+
return noop$2
|
|
663
663
|
}
|
|
664
664
|
|
|
665
665
|
const problems = [];
|
|
@@ -714,40 +714,44 @@ var responsiveWidths = stylelint.createPlugin(ruleName$3, (enabled, options = {}
|
|
|
714
714
|
return lintResult
|
|
715
715
|
});
|
|
716
716
|
|
|
717
|
-
function noop$
|
|
717
|
+
function noop$2() {}
|
|
718
718
|
|
|
719
|
-
|
|
720
|
-
const spacerValues = {
|
|
721
|
-
'$spacer-1': '4px',
|
|
722
|
-
'$spacer-2': '8px',
|
|
723
|
-
'$spacer-3': '16px',
|
|
724
|
-
'$spacer-4': '24px',
|
|
725
|
-
'$spacer-5': '32px',
|
|
726
|
-
'$spacer-6': '40px',
|
|
727
|
-
'$spacer-7': '48px',
|
|
728
|
-
'$spacer-8': '64px',
|
|
729
|
-
'$spacer-9': '80px',
|
|
730
|
-
'$spacer-10': '96px',
|
|
731
|
-
'$spacer-11': '112px',
|
|
732
|
-
'$spacer-12': '128px',
|
|
733
|
-
'$em-spacer-1': '0.0625em',
|
|
734
|
-
'$em-spacer-2': '0.125em',
|
|
735
|
-
'$em-spacer-3': '0.25em',
|
|
736
|
-
'$em-spacer-4': '0.375em',
|
|
737
|
-
'$em-spacer-5': '0.5em',
|
|
738
|
-
'$em-spacer-6': '0.75em',
|
|
739
|
-
};
|
|
719
|
+
const require$1 = createRequire(import.meta.url);
|
|
740
720
|
|
|
741
|
-
|
|
742
|
-
const
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
721
|
+
async function primitivesVariables(type) {
|
|
722
|
+
const variables = [];
|
|
723
|
+
|
|
724
|
+
const files = [];
|
|
725
|
+
switch (type) {
|
|
726
|
+
case 'size':
|
|
727
|
+
files.push('base/size/size.json');
|
|
728
|
+
break
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
for (const file of files) {
|
|
732
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
733
|
+
const data = require$1(`@primer/primitives/dist/styleLint/${file}`);
|
|
734
|
+
|
|
735
|
+
for (const key of Object.keys(data)) {
|
|
736
|
+
const size = data[key];
|
|
737
|
+
const values = size['value'];
|
|
738
|
+
values.push(`${parseInt(size['original']['value']) + 1}px`);
|
|
739
|
+
values.push(`${parseInt(size['original']['value']) - 1}px`);
|
|
740
|
+
|
|
741
|
+
variables.push({
|
|
742
|
+
name: `--${size['name']}`,
|
|
743
|
+
values,
|
|
744
|
+
});
|
|
746
745
|
}
|
|
746
|
+
}
|
|
747
747
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
748
|
+
return variables
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const {
|
|
752
|
+
createPlugin,
|
|
753
|
+
utils: {report, ruleMessages, validateOptions},
|
|
754
|
+
} = stylelint;
|
|
751
755
|
|
|
752
756
|
const walkGroups = (root, validate) => {
|
|
753
757
|
for (const node of root.nodes) {
|
|
@@ -760,24 +764,47 @@ const walkGroups = (root, validate) => {
|
|
|
760
764
|
return root
|
|
761
765
|
};
|
|
762
766
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
767
|
+
const ruleName$2 = 'primer/spacing';
|
|
768
|
+
const messages$2 = ruleMessages(ruleName$2, {
|
|
769
|
+
rejected: (value, replacement) => {
|
|
770
|
+
if (!replacement) {
|
|
771
|
+
return `Please use a primer size variable instead of '${value}'. Consult the primer docs for a suitable replacement. https://primer.style/foundations/primitives/size`
|
|
772
|
+
}
|
|
768
773
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
return noop$2
|
|
773
|
-
}
|
|
774
|
+
return `Please replace '${value}' with size variable '${replacement['name']}'. https://primer.style/foundations/primitives/size`
|
|
775
|
+
},
|
|
776
|
+
});
|
|
774
777
|
|
|
775
|
-
|
|
778
|
+
const meta = {
|
|
779
|
+
fixable: true,
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
/** @type {import('stylelint').Rule} */
|
|
783
|
+
const ruleFunction = (primary, secondaryOptions, context) => {
|
|
784
|
+
return async (root, result) => {
|
|
785
|
+
// Props that we want to check
|
|
786
|
+
const propList = ['padding', 'margin', 'top', 'right', 'bottom', 'left'];
|
|
787
|
+
// Values that we want to ignore
|
|
788
|
+
const valueList = ['${'];
|
|
789
|
+
|
|
790
|
+
const sizes = await primitivesVariables('size');
|
|
791
|
+
|
|
792
|
+
const validOptions = validateOptions(result, ruleName$2, {
|
|
793
|
+
actual: primary,
|
|
794
|
+
possible: [true],
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
if (!validOptions) return
|
|
798
|
+
|
|
799
|
+
root.walkDecls(declNode => {
|
|
800
|
+
const {prop, value} = declNode;
|
|
776
801
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
const cleanValue = node.value.replace(/^-/g, '');
|
|
802
|
+
if (!propList.some(spacingProp => prop.startsWith(spacingProp))) return
|
|
803
|
+
if (valueList.some(valueToIgnore => value.includes(valueToIgnore))) return
|
|
780
804
|
|
|
805
|
+
const problems = [];
|
|
806
|
+
|
|
807
|
+
const parsedValue = walkGroups(valueParser(value), node => {
|
|
781
808
|
// Only check word types. https://github.com/TrySound/postcss-value-parser#word
|
|
782
809
|
if (node.type !== 'word') {
|
|
783
810
|
return
|
|
@@ -788,30 +815,36 @@ var spacing = stylelint.createPlugin(ruleName$2, (enabled, options = {}, context
|
|
|
788
815
|
return
|
|
789
816
|
}
|
|
790
817
|
|
|
791
|
-
const valueUnit = valueParser.unit(
|
|
818
|
+
const valueUnit = valueParser.unit(node.value);
|
|
792
819
|
|
|
793
|
-
if (valueUnit && (valueUnit.unit === '' ||
|
|
820
|
+
if (valueUnit && (valueUnit.unit === '' || !/^-?[0-9.]+$/.test(valueUnit.number))) {
|
|
794
821
|
return
|
|
795
822
|
}
|
|
796
823
|
|
|
797
|
-
//
|
|
824
|
+
// Skip if the value unit isn't a supported unit.
|
|
825
|
+
if (valueUnit && !['px', 'rem', 'em'].includes(valueUnit.unit)) {
|
|
826
|
+
return
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// If the variable is found in the value, skip it.
|
|
798
830
|
if (
|
|
799
|
-
|
|
800
|
-
new RegExp(`${variable.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(
|
|
831
|
+
sizes.some(variable =>
|
|
832
|
+
new RegExp(`${variable['name'].replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(node.value),
|
|
801
833
|
)
|
|
802
834
|
) {
|
|
803
835
|
return
|
|
804
836
|
}
|
|
805
837
|
|
|
806
|
-
const replacement =
|
|
807
|
-
const
|
|
838
|
+
const replacement = sizes.find(variable => variable.values.includes(node.value.replace('-', '')));
|
|
839
|
+
const fixable = replacement && valueUnit && !valueUnit.number.includes('-');
|
|
808
840
|
|
|
809
|
-
if (
|
|
810
|
-
node.value = node.value.replace(
|
|
841
|
+
if (fixable && context.fix) {
|
|
842
|
+
node.value = node.value.replace(node.value, `var(${replacement['name']})`);
|
|
811
843
|
} else {
|
|
812
844
|
problems.push({
|
|
813
|
-
index: declarationValueIndex(
|
|
814
|
-
|
|
845
|
+
index: declarationValueIndex(declNode) + node.sourceIndex,
|
|
846
|
+
endIndex: declarationValueIndex(declNode) + node.sourceIndex + node.value.length,
|
|
847
|
+
message: messages$2.rejected(node.value, replacement),
|
|
815
848
|
});
|
|
816
849
|
}
|
|
817
850
|
|
|
@@ -819,27 +852,30 @@ var spacing = stylelint.createPlugin(ruleName$2, (enabled, options = {}, context
|
|
|
819
852
|
});
|
|
820
853
|
|
|
821
854
|
if (context.fix) {
|
|
822
|
-
|
|
855
|
+
declNode.value = parsedValue.toString();
|
|
823
856
|
}
|
|
824
857
|
|
|
825
858
|
if (problems.length) {
|
|
826
859
|
for (const err of problems) {
|
|
827
|
-
|
|
860
|
+
report({
|
|
828
861
|
index: err.index,
|
|
862
|
+
endIndex: err.endIndex,
|
|
829
863
|
message: err.message,
|
|
830
|
-
node:
|
|
864
|
+
node: declNode,
|
|
831
865
|
result,
|
|
832
866
|
ruleName: ruleName$2,
|
|
833
867
|
});
|
|
834
868
|
}
|
|
835
869
|
}
|
|
836
870
|
});
|
|
837
|
-
}
|
|
871
|
+
}
|
|
872
|
+
};
|
|
838
873
|
|
|
839
|
-
|
|
840
|
-
|
|
874
|
+
ruleFunction.ruleName = ruleName$2;
|
|
875
|
+
ruleFunction.messages = messages$2;
|
|
876
|
+
ruleFunction.meta = meta;
|
|
841
877
|
|
|
842
|
-
|
|
878
|
+
var spacing = createPlugin(ruleName$2, ruleFunction);
|
|
843
879
|
|
|
844
880
|
var typography = createVariableRule(
|
|
845
881
|
'primer/typography',
|
|
@@ -1625,7 +1661,6 @@ var index = {
|
|
|
1625
1661
|
'comment-empty-line-before': null,
|
|
1626
1662
|
'length-zero-no-unit': null,
|
|
1627
1663
|
'selector-max-type': null,
|
|
1628
|
-
'primer/spacing': null,
|
|
1629
1664
|
'primer/colors': null,
|
|
1630
1665
|
'primer/borders': null,
|
|
1631
1666
|
'primer/typography': null,
|
|
@@ -1655,6 +1690,7 @@ var index = {
|
|
|
1655
1690
|
},
|
|
1656
1691
|
{
|
|
1657
1692
|
files: ['**/*.module.css'],
|
|
1693
|
+
plugins: ['stylelint-css-modules-no-global-scoped-selector'],
|
|
1658
1694
|
rules: {
|
|
1659
1695
|
'property-no-unknown': [
|
|
1660
1696
|
true,
|
|
@@ -1679,8 +1715,8 @@ var index = {
|
|
|
1679
1715
|
ignoreFunctions: ['global'],
|
|
1680
1716
|
},
|
|
1681
1717
|
],
|
|
1718
|
+
'css-modules/no-global-scoped-selector': true,
|
|
1682
1719
|
// temporarily disabiling Primer plugins while we work on upgrades https://github.com/github/primer/issues/3165
|
|
1683
|
-
'primer/spacing': null,
|
|
1684
1720
|
'primer/borders': null,
|
|
1685
1721
|
'primer/typography': null,
|
|
1686
1722
|
'primer/box-shadow': null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primer/stylelint-config",
|
|
3
|
-
"version": "13.0.0-rc.
|
|
3
|
+
"version": "13.0.0-rc.99be5f2",
|
|
4
4
|
"description": "Sharable stylelint config used by GitHub's CSS",
|
|
5
5
|
"author": "GitHub, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@github/browserslist-config": "^1.0.0",
|
|
47
47
|
"@primer/css": "^21.0.8",
|
|
48
|
-
"@primer/primitives": "^7.
|
|
48
|
+
"@primer/primitives": "^7.17.1",
|
|
49
49
|
"anymatch": "^3.1.1",
|
|
50
50
|
"postcss-scss": "^4.0.2",
|
|
51
51
|
"postcss-styled-syntax": "^0.6.4",
|
|
@@ -53,16 +53,22 @@
|
|
|
53
53
|
"string.prototype.matchall": "^4.0.2",
|
|
54
54
|
"stylelint": "^16.3.1",
|
|
55
55
|
"stylelint-config-standard": "^36.0.0",
|
|
56
|
+
"stylelint-css-modules-no-global-scoped-selector": "^1.0.2",
|
|
56
57
|
"stylelint-no-unsupported-browser-features": "^8.0.0",
|
|
57
58
|
"stylelint-order": "^6.0.4",
|
|
58
59
|
"stylelint-scss": "^6.2.0",
|
|
59
60
|
"stylelint-value-no-unknown-custom-properties": "^6.0.1",
|
|
60
61
|
"tap-map": "^1.0.0"
|
|
61
62
|
},
|
|
63
|
+
"overrides": {
|
|
64
|
+
"stylelint-css-modules-no-global-scoped-selector": {
|
|
65
|
+
"stylelint": "$stylelint"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
62
68
|
"prettier": "@github/prettier-config",
|
|
63
69
|
"devDependencies": {
|
|
64
70
|
"@changesets/changelog-github": "^0.5.0",
|
|
65
|
-
"@changesets/cli": "2.
|
|
71
|
+
"@changesets/cli": "2.27.1",
|
|
66
72
|
"@github/prettier-config": "^0.0.6",
|
|
67
73
|
"@rollup/plugin-commonjs": "^25.0.7",
|
|
68
74
|
"@rollup/plugin-json": "^6.1.0",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {createRequire} from 'node:module'
|
|
2
|
+
|
|
3
|
+
const require = createRequire(import.meta.url)
|
|
4
|
+
|
|
5
|
+
export async function primitivesVariables(type) {
|
|
6
|
+
const variables = []
|
|
7
|
+
|
|
8
|
+
const files = []
|
|
9
|
+
switch (type) {
|
|
10
|
+
case 'size':
|
|
11
|
+
files.push('base/size/size.json')
|
|
12
|
+
break
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
for (const file of files) {
|
|
16
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
17
|
+
const data = require(`@primer/primitives/dist/styleLint/${file}`)
|
|
18
|
+
|
|
19
|
+
for (const key of Object.keys(data)) {
|
|
20
|
+
const size = data[key]
|
|
21
|
+
const values = size['value']
|
|
22
|
+
values.push(`${parseInt(size['original']['value']) + 1}px`)
|
|
23
|
+
values.push(`${parseInt(size['original']['value']) - 1}px`)
|
|
24
|
+
|
|
25
|
+
variables.push({
|
|
26
|
+
name: `--${size['name']}`,
|
|
27
|
+
values,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return variables
|
|
33
|
+
}
|
package/plugins/spacing.js
CHANGED
|
@@ -1,39 +1,12 @@
|
|
|
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} from './lib/primitives.js'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
}
|
|
26
|
-
|
|
27
|
-
export const ruleName = 'primer/spacing'
|
|
28
|
-
export const messages = stylelint.utils.ruleMessages(ruleName, {
|
|
29
|
-
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`
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return `Please replace ${value} with spacing variable '${replacement}'.`
|
|
35
|
-
},
|
|
36
|
-
})
|
|
6
|
+
const {
|
|
7
|
+
createPlugin,
|
|
8
|
+
utils: {report, ruleMessages, validateOptions},
|
|
9
|
+
} = stylelint
|
|
37
10
|
|
|
38
11
|
const walkGroups = (root, validate) => {
|
|
39
12
|
for (const node of root.nodes) {
|
|
@@ -46,24 +19,47 @@ const walkGroups = (root, validate) => {
|
|
|
46
19
|
return root
|
|
47
20
|
}
|
|
48
21
|
|
|
49
|
-
|
|
50
|
-
export
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
22
|
+
export const ruleName = 'primer/spacing'
|
|
23
|
+
export const messages = ruleMessages(ruleName, {
|
|
24
|
+
rejected: (value, replacement) => {
|
|
25
|
+
if (!replacement) {
|
|
26
|
+
return `Please use a primer size variable instead of '${value}'. Consult the primer docs for a suitable replacement. https://primer.style/foundations/primitives/size`
|
|
27
|
+
}
|
|
54
28
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return noop
|
|
59
|
-
}
|
|
29
|
+
return `Please replace '${value}' with size variable '${replacement['name']}'. https://primer.style/foundations/primitives/size`
|
|
30
|
+
},
|
|
31
|
+
})
|
|
60
32
|
|
|
61
|
-
|
|
33
|
+
const meta = {
|
|
34
|
+
fixable: true,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** @type {import('stylelint').Rule} */
|
|
38
|
+
const ruleFunction = (primary, secondaryOptions, context) => {
|
|
39
|
+
return async (root, result) => {
|
|
40
|
+
// Props that we want to check
|
|
41
|
+
const propList = ['padding', 'margin', 'top', 'right', 'bottom', 'left']
|
|
42
|
+
// Values that we want to ignore
|
|
43
|
+
const valueList = ['${']
|
|
44
|
+
|
|
45
|
+
const sizes = await primitivesVariables('size')
|
|
46
|
+
|
|
47
|
+
const validOptions = validateOptions(result, ruleName, {
|
|
48
|
+
actual: primary,
|
|
49
|
+
possible: [true],
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
if (!validOptions) return
|
|
53
|
+
|
|
54
|
+
root.walkDecls(declNode => {
|
|
55
|
+
const {prop, value} = declNode
|
|
62
56
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const cleanValue = node.value.replace(/^-/g, '')
|
|
57
|
+
if (!propList.some(spacingProp => prop.startsWith(spacingProp))) return
|
|
58
|
+
if (valueList.some(valueToIgnore => value.includes(valueToIgnore))) return
|
|
66
59
|
|
|
60
|
+
const problems = []
|
|
61
|
+
|
|
62
|
+
const parsedValue = walkGroups(valueParser(value), node => {
|
|
67
63
|
// Only check word types. https://github.com/TrySound/postcss-value-parser#word
|
|
68
64
|
if (node.type !== 'word') {
|
|
69
65
|
return
|
|
@@ -74,30 +70,36 @@ export default stylelint.createPlugin(ruleName, (enabled, options = {}, context)
|
|
|
74
70
|
return
|
|
75
71
|
}
|
|
76
72
|
|
|
77
|
-
const valueUnit = valueParser.unit(
|
|
73
|
+
const valueUnit = valueParser.unit(node.value)
|
|
78
74
|
|
|
79
|
-
if (valueUnit && (valueUnit.unit === '' ||
|
|
75
|
+
if (valueUnit && (valueUnit.unit === '' || !/^-?[0-9.]+$/.test(valueUnit.number))) {
|
|
80
76
|
return
|
|
81
77
|
}
|
|
82
78
|
|
|
83
|
-
//
|
|
79
|
+
// Skip if the value unit isn't a supported unit.
|
|
80
|
+
if (valueUnit && !['px', 'rem', 'em'].includes(valueUnit.unit)) {
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// If the variable is found in the value, skip it.
|
|
84
85
|
if (
|
|
85
|
-
|
|
86
|
-
new RegExp(`${variable.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(
|
|
86
|
+
sizes.some(variable =>
|
|
87
|
+
new RegExp(`${variable['name'].replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).test(node.value),
|
|
87
88
|
)
|
|
88
89
|
) {
|
|
89
90
|
return
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
const replacement =
|
|
93
|
-
const
|
|
93
|
+
const replacement = sizes.find(variable => variable.values.includes(node.value.replace('-', '')))
|
|
94
|
+
const fixable = replacement && valueUnit && !valueUnit.number.includes('-')
|
|
94
95
|
|
|
95
|
-
if (
|
|
96
|
-
node.value = node.value.replace(
|
|
96
|
+
if (fixable && context.fix) {
|
|
97
|
+
node.value = node.value.replace(node.value, `var(${replacement['name']})`)
|
|
97
98
|
} else {
|
|
98
99
|
problems.push({
|
|
99
|
-
index: declarationValueIndex(
|
|
100
|
-
|
|
100
|
+
index: declarationValueIndex(declNode) + node.sourceIndex,
|
|
101
|
+
endIndex: declarationValueIndex(declNode) + node.sourceIndex + node.value.length,
|
|
102
|
+
message: messages.rejected(node.value, replacement),
|
|
101
103
|
})
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -105,15 +107,16 @@ export default stylelint.createPlugin(ruleName, (enabled, options = {}, context)
|
|
|
105
107
|
})
|
|
106
108
|
|
|
107
109
|
if (context.fix) {
|
|
108
|
-
|
|
110
|
+
declNode.value = parsedValue.toString()
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
if (problems.length) {
|
|
112
114
|
for (const err of problems) {
|
|
113
|
-
|
|
115
|
+
report({
|
|
114
116
|
index: err.index,
|
|
117
|
+
endIndex: err.endIndex,
|
|
115
118
|
message: err.message,
|
|
116
|
-
node:
|
|
119
|
+
node: declNode,
|
|
117
120
|
result,
|
|
118
121
|
ruleName,
|
|
119
122
|
})
|
|
@@ -121,8 +124,10 @@ export default stylelint.createPlugin(ruleName, (enabled, options = {}, context)
|
|
|
121
124
|
}
|
|
122
125
|
})
|
|
123
126
|
}
|
|
127
|
+
}
|
|
124
128
|
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
ruleFunction.ruleName = ruleName
|
|
130
|
+
ruleFunction.messages = messages
|
|
131
|
+
ruleFunction.meta = meta
|
|
127
132
|
|
|
128
|
-
|
|
133
|
+
export default createPlugin(ruleName, ruleFunction)
|