@plumeria/eslint-plugin 19.14.4 → 19.15.0
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.
|
@@ -80,7 +80,8 @@ exports.noInnerCall = {
|
|
|
80
80
|
propertyName === 'createStatic' ||
|
|
81
81
|
propertyName === 'createTheme' ||
|
|
82
82
|
propertyName === 'keyframes' ||
|
|
83
|
-
propertyName === 'viewTransition'
|
|
83
|
+
propertyName === 'viewTransition' ||
|
|
84
|
+
propertyName === 'varType') {
|
|
84
85
|
context.report({
|
|
85
86
|
node,
|
|
86
87
|
messageId: 'noInnerCall',
|
|
@@ -899,34 +899,35 @@ function getFoldedValues(key) {
|
|
|
899
899
|
foldedValueCache.set(key, folded);
|
|
900
900
|
return folded;
|
|
901
901
|
}
|
|
902
|
+
const transformFunctionString = [
|
|
903
|
+
`matrix\\(${mathContentsString}\\)`,
|
|
904
|
+
`matrix3d\\(${mathContentsString}\\)`,
|
|
905
|
+
`perspective\\(${mathContentsString}\\)`,
|
|
906
|
+
`rotate\\(${mathContentsString}\\)`,
|
|
907
|
+
`rotate3d\\(${mathContentsString}\\)`,
|
|
908
|
+
`rotateX\\(${mathContentsString}\\)`,
|
|
909
|
+
`rotateY\\(${mathContentsString}\\)`,
|
|
910
|
+
`rotateZ\\(${mathContentsString}\\)`,
|
|
911
|
+
`scale\\(${mathContentsString}\\)`,
|
|
912
|
+
`scale3d\\(${mathContentsString}\\)`,
|
|
913
|
+
`scaleX\\(${mathContentsString}\\)`,
|
|
914
|
+
`scaleY\\(${mathContentsString}\\)`,
|
|
915
|
+
`scaleZ\\(${mathContentsString}\\)`,
|
|
916
|
+
`skew\\(${mathContentsString}\\)`,
|
|
917
|
+
`skewX\\(${mathContentsString}\\)`,
|
|
918
|
+
`skewY\\(${mathContentsString}\\)`,
|
|
919
|
+
`translate\\(${mathContentsString}\\)`,
|
|
920
|
+
`translate3d\\(${mathContentsString}\\)`,
|
|
921
|
+
`translateX\\(${mathContentsString}\\)`,
|
|
922
|
+
`translateY\\(${mathContentsString}\\)`,
|
|
923
|
+
`translateZ\\(${mathContentsString}\\)`,
|
|
924
|
+
].join('|');
|
|
902
925
|
function getValidator(key) {
|
|
903
926
|
if (validatorCache.has(key))
|
|
904
927
|
return validatorCache.get(key);
|
|
905
928
|
let validator = null;
|
|
906
929
|
const lvp = getLengthValuePattern(key);
|
|
907
|
-
const getTransformFunctions = () =>
|
|
908
|
-
`matrix\\(${mathContentsString}\\)`,
|
|
909
|
-
`matrix3d\\(${mathContentsString}\\)`,
|
|
910
|
-
`perspective\\(${mathContentsString}\\)`,
|
|
911
|
-
`rotate\\(${mathContentsString}\\)`,
|
|
912
|
-
`rotate3d\\(${mathContentsString}\\)`,
|
|
913
|
-
`rotateX\\(${mathContentsString}\\)`,
|
|
914
|
-
`rotateY\\(${mathContentsString}\\)`,
|
|
915
|
-
`rotateZ\\(${mathContentsString}\\)`,
|
|
916
|
-
`scale\\(${mathContentsString}\\)`,
|
|
917
|
-
`scale3d\\(${mathContentsString}\\)`,
|
|
918
|
-
`scaleX\\(${mathContentsString}\\)`,
|
|
919
|
-
`scaleY\\(${mathContentsString}\\)`,
|
|
920
|
-
`scaleZ\\(${mathContentsString}\\)`,
|
|
921
|
-
`skew\\(${mathContentsString}\\)`,
|
|
922
|
-
`skewX\\(${mathContentsString}\\)`,
|
|
923
|
-
`skewY\\(${mathContentsString}\\)`,
|
|
924
|
-
`translate\\(${mathContentsString}\\)`,
|
|
925
|
-
`translate3d\\(${mathContentsString}\\)`,
|
|
926
|
-
`translateX\\(${mathContentsString}\\)`,
|
|
927
|
-
`translateY\\(${mathContentsString}\\)`,
|
|
928
|
-
`translateZ\\(${mathContentsString}\\)`,
|
|
929
|
-
].join('|');
|
|
930
|
+
const getTransformFunctions = () => transformFunctionString;
|
|
930
931
|
const getGeometryBaseSet = () => 'content-box|padding-box|border-box|fill-box|stroke-box|view-box';
|
|
931
932
|
if (['translate'].includes(key)) {
|
|
932
933
|
const r = new RegExp(`^(${lvp}|${percentagePattern})(\\s(${lvp}|${percentagePattern}))?(\\s(${lvp}))?$`);
|
|
@@ -1848,6 +1849,109 @@ function getValidator(key) {
|
|
|
1848
1849
|
validatorCache.set(key, validator);
|
|
1849
1850
|
return validator;
|
|
1850
1851
|
}
|
|
1852
|
+
const contextDependentUnits = [
|
|
1853
|
+
'cap',
|
|
1854
|
+
'ch',
|
|
1855
|
+
'em',
|
|
1856
|
+
'ex',
|
|
1857
|
+
'ic',
|
|
1858
|
+
'lh',
|
|
1859
|
+
'rcap',
|
|
1860
|
+
'rch',
|
|
1861
|
+
'rem',
|
|
1862
|
+
'rex',
|
|
1863
|
+
'ric',
|
|
1864
|
+
'rlh',
|
|
1865
|
+
'cqw',
|
|
1866
|
+
'cqh',
|
|
1867
|
+
'cqi',
|
|
1868
|
+
'cqb',
|
|
1869
|
+
'cqmin',
|
|
1870
|
+
'cqmax',
|
|
1871
|
+
];
|
|
1872
|
+
const contextDependentRegex = new RegExp(`(?:var\\(|[\\d.](?:${contextDependentUnits.join('|')})(?![a-zA-Z0-9_-]))`, 'i');
|
|
1873
|
+
const quotedStringRegex = new RegExp(stringString, 'g');
|
|
1874
|
+
const timeString = `${pureNumber}(?:ms|s)`;
|
|
1875
|
+
const resolutionString = `${pureNumber}(?:dpi|dpcm|dppx|x)`;
|
|
1876
|
+
const customIdentRegex = /^-?[a-zA-Z_][a-zA-Z0-9_-]*$/;
|
|
1877
|
+
const exactly = (pattern) => {
|
|
1878
|
+
const r = new RegExp(`^(?:${pattern})$`);
|
|
1879
|
+
return (v) => r.test(v);
|
|
1880
|
+
};
|
|
1881
|
+
const varTypeValidators = {
|
|
1882
|
+
'<length>': exactly(`${lengthPattern}|${calcString}`),
|
|
1883
|
+
'<number>': exactly(`${pureNumber}|${calcString}`),
|
|
1884
|
+
'<integer>': exactly(`${pureInteger}|${calcString}`),
|
|
1885
|
+
'<percentage>': exactly(`${percentagePattern}|${calcString}`),
|
|
1886
|
+
'<length-percentage>': exactly(`${lengthPattern}|${percentagePattern}|${calcString}`),
|
|
1887
|
+
'<angle>': exactly(`${pureAngle}|${calcString}`),
|
|
1888
|
+
'<time>': exactly(`${timeString}|${calcString}`),
|
|
1889
|
+
'<resolution>': exactly(`${resolutionString}|${calcString}`),
|
|
1890
|
+
'<color>': isColor,
|
|
1891
|
+
'<image>': exactly(`${urlString}|${gradientString}|${imageSetString}`),
|
|
1892
|
+
'<url>': exactly(urlString),
|
|
1893
|
+
'<string>': exactly(stringString),
|
|
1894
|
+
'<custom-ident>': (v) => customIdentRegex.test(v) &&
|
|
1895
|
+
!globalValues.includes(v.toLowerCase()) &&
|
|
1896
|
+
v.toLowerCase() !== 'default',
|
|
1897
|
+
'<transform-function>': exactly(transformFunctionString),
|
|
1898
|
+
'<transform-list>': exactly(`(?:${transformFunctionString})(?:\\s+(?:${transformFunctionString}))*`),
|
|
1899
|
+
};
|
|
1900
|
+
function splitTopLevelSpaces(value) {
|
|
1901
|
+
const parts = [];
|
|
1902
|
+
let depth = 0;
|
|
1903
|
+
let current = '';
|
|
1904
|
+
for (const char of value) {
|
|
1905
|
+
if (char === '(')
|
|
1906
|
+
depth++;
|
|
1907
|
+
else if (char === ')')
|
|
1908
|
+
depth--;
|
|
1909
|
+
if (depth === 0 && /\s/.test(char)) {
|
|
1910
|
+
if (current)
|
|
1911
|
+
parts.push(current);
|
|
1912
|
+
current = '';
|
|
1913
|
+
}
|
|
1914
|
+
else {
|
|
1915
|
+
current += char;
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
if (current)
|
|
1919
|
+
parts.push(current);
|
|
1920
|
+
return parts;
|
|
1921
|
+
}
|
|
1922
|
+
function matchesSyntaxComponent(component, value) {
|
|
1923
|
+
const multiplier = /[+#]$/.test(component) ? component.slice(-1) : '';
|
|
1924
|
+
const name = multiplier ? component.slice(0, -1) : component;
|
|
1925
|
+
if (!name.startsWith('<'))
|
|
1926
|
+
return multiplier ? null : value === name;
|
|
1927
|
+
const validator = varTypeValidators[name];
|
|
1928
|
+
if (!validator)
|
|
1929
|
+
return null;
|
|
1930
|
+
if (!multiplier)
|
|
1931
|
+
return validator(value);
|
|
1932
|
+
const items = multiplier === '+'
|
|
1933
|
+
? splitTopLevelSpaces(value)
|
|
1934
|
+
: splitTopLevelCommas(value);
|
|
1935
|
+
return items.every((item) => item !== '' && validator(item));
|
|
1936
|
+
}
|
|
1937
|
+
function checkInitialValue(syntax, value) {
|
|
1938
|
+
const trimmedSyntax = syntax.trim();
|
|
1939
|
+
if (trimmedSyntax === '*')
|
|
1940
|
+
return null;
|
|
1941
|
+
if (contextDependentRegex.test(value.replace(quotedStringRegex, ''))) {
|
|
1942
|
+
return 'varTypeDependent';
|
|
1943
|
+
}
|
|
1944
|
+
const trimmedValue = value.trim();
|
|
1945
|
+
let unknown = false;
|
|
1946
|
+
for (const component of trimmedSyntax.split('|')) {
|
|
1947
|
+
const result = matchesSyntaxComponent(component.trim(), trimmedValue);
|
|
1948
|
+
if (result)
|
|
1949
|
+
return null;
|
|
1950
|
+
if (result === null)
|
|
1951
|
+
unknown = true;
|
|
1952
|
+
}
|
|
1953
|
+
return unknown ? null : 'varTypeMismatch';
|
|
1954
|
+
}
|
|
1851
1955
|
exports.validateValues = {
|
|
1852
1956
|
meta: {
|
|
1853
1957
|
type: 'problem',
|
|
@@ -1858,6 +1962,8 @@ exports.validateValues = {
|
|
|
1858
1962
|
validateValue: "'{{key}}' has an invalid value '{{value}}'. Valid values: {{validValues}}",
|
|
1859
1963
|
invalidPrimitive: "'{{key}}' cannot be assigned a {{type}} value ({{value}}). CSS properties require string or number values.",
|
|
1860
1964
|
invalidNumber: "'{{key}}' does not accept numeric values. Expected a string value.",
|
|
1965
|
+
varTypeMismatch: "css.varType initialValue '{{value}}' does not match the syntax '{{syntax}}'.",
|
|
1966
|
+
varTypeDependent: "css.varType initialValue '{{value}}' depends on the font, a container or var(), so the browser drops the @property. Use a value that does not depend on where it is used.",
|
|
1861
1967
|
},
|
|
1862
1968
|
schema: [],
|
|
1863
1969
|
},
|
|
@@ -1947,6 +2053,43 @@ exports.validateValues = {
|
|
|
1947
2053
|
}
|
|
1948
2054
|
});
|
|
1949
2055
|
}
|
|
2056
|
+
function checkVarType(arg) {
|
|
2057
|
+
if (!arg || arg.type !== 'ObjectExpression')
|
|
2058
|
+
return;
|
|
2059
|
+
let syntax = '*';
|
|
2060
|
+
let initialValue = null;
|
|
2061
|
+
for (const prop of arg.properties) {
|
|
2062
|
+
if (prop.type !== 'Property' ||
|
|
2063
|
+
prop.computed ||
|
|
2064
|
+
prop.key.type !== 'Identifier') {
|
|
2065
|
+
continue;
|
|
2066
|
+
}
|
|
2067
|
+
if (prop.key.name === 'syntax') {
|
|
2068
|
+
if (prop.value.type !== 'Literal')
|
|
2069
|
+
return;
|
|
2070
|
+
if (typeof prop.value.value !== 'string')
|
|
2071
|
+
return;
|
|
2072
|
+
syntax = prop.value.value;
|
|
2073
|
+
}
|
|
2074
|
+
else if (prop.key.name === 'initialValue') {
|
|
2075
|
+
initialValue = prop.value;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
if (!initialValue || initialValue.type !== 'Literal')
|
|
2079
|
+
return;
|
|
2080
|
+
const raw = initialValue.value;
|
|
2081
|
+
if (typeof raw !== 'string' && typeof raw !== 'number')
|
|
2082
|
+
return;
|
|
2083
|
+
const value = String(raw);
|
|
2084
|
+
const messageId = checkInitialValue(syntax, value);
|
|
2085
|
+
if (messageId) {
|
|
2086
|
+
context.report({
|
|
2087
|
+
node: initialValue,
|
|
2088
|
+
messageId,
|
|
2089
|
+
data: { value, syntax },
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
1950
2093
|
return {
|
|
1951
2094
|
ImportDeclaration(node) {
|
|
1952
2095
|
if (node.source.value === '@plumeria/core') {
|
|
@@ -1966,6 +2109,19 @@ exports.validateValues = {
|
|
|
1966
2109
|
}
|
|
1967
2110
|
},
|
|
1968
2111
|
CallExpression(node) {
|
|
2112
|
+
const calleeName = node.callee.type === 'MemberExpression'
|
|
2113
|
+
? node.callee.object.type === 'Identifier' &&
|
|
2114
|
+
plumeriaAliases[node.callee.object.name] === 'NAMESPACE' &&
|
|
2115
|
+
node.callee.property.type === 'Identifier'
|
|
2116
|
+
? node.callee.property.name
|
|
2117
|
+
: null
|
|
2118
|
+
: node.callee.type === 'Identifier'
|
|
2119
|
+
? plumeriaAliases[node.callee.name]
|
|
2120
|
+
: null;
|
|
2121
|
+
if (calleeName === 'varType') {
|
|
2122
|
+
checkVarType(node.arguments[0]);
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
1969
2125
|
let isCssProperties = false;
|
|
1970
2126
|
if (node.callee.type === 'MemberExpression') {
|
|
1971
2127
|
if (node.callee.object.type === 'Identifier' &&
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumeria/eslint-plugin",
|
|
3
|
-
"version": "19.
|
|
3
|
+
"version": "19.15.0",
|
|
4
4
|
"description": "Plumeria ESLint plugin",
|
|
5
5
|
"author": "Refirst 11",
|
|
6
6
|
"license": "MIT",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"oxlint": "1.87.0",
|
|
61
61
|
"zss-engine": "2.10.0",
|
|
62
|
-
"@plumeria/compiler": "19.
|
|
62
|
+
"@plumeria/compiler": "19.15.0"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"build": "rimraf dist && pnpm cjs",
|