@plumeria/eslint-plugin 18.2.11 → 18.2.13

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.
@@ -97,9 +97,24 @@ exports.expandBorderShorthands = {
97
97
  const kebab = (0, logicalPhysical_1.toKebabCase)(name);
98
98
  if (!BUNDLES.has(kebab))
99
99
  return;
100
- const literal = prop.value.type === 'Literal' && typeof prop.value.value === 'string'
101
- ? prop.value.value
102
- : null;
100
+ let literal = null;
101
+ let expressions = [];
102
+ if (prop.value.type === 'Literal' &&
103
+ typeof prop.value.value === 'string') {
104
+ literal = prop.value.value;
105
+ }
106
+ else if (prop.value.type === 'TemplateLiteral') {
107
+ const template = prop.value;
108
+ expressions = template.expressions.map((expression) => sourceCode.getText(expression));
109
+ literal = template.quasis
110
+ .map((quasi, index) => index < expressions.length
111
+ ? quasi.value.raw +
112
+ borderShorthand_1.EXPRESSION_MARKER +
113
+ index +
114
+ borderShorthand_1.EXPRESSION_MARKER
115
+ : quasi.value.raw)
116
+ .join('');
117
+ }
103
118
  const parts = literal === null ? null : (0, borderShorthand_1.splitBorderValue)(literal);
104
119
  if (!parts) {
105
120
  context.report({
@@ -112,9 +127,20 @@ exports.expandBorderShorthands = {
112
127
  const quote = sourceCode.getText(prop.value).trim().startsWith('"')
113
128
  ? '"'
114
129
  : "'";
130
+ const marker = new RegExp(`${borderShorthand_1.EXPRESSION_MARKER}(\\d+)${borderShorthand_1.EXPRESSION_MARKER}`, 'g');
131
+ const render = (value) => {
132
+ if (!value.includes(borderShorthand_1.EXPRESSION_MARKER)) {
133
+ return `${quote}${value}${quote}`;
134
+ }
135
+ const restored = value.replace(marker, (_, index) => `\${${expressions[Number(index)]}}`);
136
+ const alone = /^\$\{([\s\S]*)\}$/.exec(restored);
137
+ return alone && !alone[1].includes('${')
138
+ ? alone[1]
139
+ : `\`${restored}\``;
140
+ };
115
141
  const indent = ' '.repeat(prop.loc.start.column);
116
142
  const declarations = ['width', 'style', 'color']
117
- .map((part) => `${(0, logicalPhysical_1.toCamelCase)(`${kebab}-${part}`)}: ${quote}${parts[part]}${quote}`)
143
+ .map((part) => `${(0, logicalPhysical_1.toCamelCase)(`${kebab}-${part}`)}: ${render(parts[part])}`)
118
144
  .join(`,\n${indent}`);
119
145
  context.report({
120
146
  node: prop.key,
@@ -1,4 +1,5 @@
1
1
  export declare const BORDER_BUNDLES: string[];
2
+ export declare const EXPRESSION_MARKER = "\0";
2
3
  export declare const splitBorderValue: (value: string) => {
3
4
  width: string;
4
5
  style: string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.splitBorderValue = exports.BORDER_BUNDLES = void 0;
3
+ exports.splitBorderValue = exports.EXPRESSION_MARKER = exports.BORDER_BUNDLES = void 0;
4
4
  exports.BORDER_BUNDLES = [
5
5
  'border',
6
6
  'border-block',
@@ -28,7 +28,8 @@ const STYLES = new Set([
28
28
  ]);
29
29
  const WIDTH_KEYWORDS = new Set(['thin', 'medium', 'thick']);
30
30
  const LENGTH = /^[+-]?(\d+\.?\d*|\.\d+)([a-z%]+)?$/i;
31
- const INITIAL = { width: 'medium', style: 'none', color: 'currentcolor' };
31
+ const INITIAL = { width: 'medium', style: 'none', color: 'currentColor' };
32
+ exports.EXPRESSION_MARKER = '\u0000';
32
33
  const tokenize = (value) => {
33
34
  const tokens = [];
34
35
  let depth = 0;
@@ -53,14 +54,22 @@ const tokenize = (value) => {
53
54
  const isWidth = (token) => WIDTH_KEYWORDS.has(token) || LENGTH.test(token) || /^calc\(/i.test(token);
54
55
  const isColor = (token) => /^(#|rgb|hsl|hwb|lab|lch|oklab|oklch|color\(|light-dark\()/i.test(token) ||
55
56
  /^[a-z-]+$/i.test(token);
57
+ const isExpression = (token) => /\bvar\(/i.test(token) || token.includes(exports.EXPRESSION_MARKER);
56
58
  const splitBorderValue = (value) => {
57
59
  const tokens = tokenize(value);
58
60
  if (!tokens)
59
61
  return null;
60
- if (tokens.some((token) => /\bvar\(|^inherit$|^initial$|^unset$|^revert/i.test(token)))
62
+ if (tokens.some((token) => /^inherit$|^initial$|^unset$|^revert/i.test(token)))
61
63
  return null;
62
64
  const parts = {};
65
+ let expression = null;
63
66
  for (const token of tokens) {
67
+ if (isExpression(token)) {
68
+ if (expression !== null)
69
+ return null;
70
+ expression = token;
71
+ continue;
72
+ }
64
73
  const lower = token.toLowerCase();
65
74
  if (!parts.style && STYLES.has(lower)) {
66
75
  parts.style = token;
@@ -76,6 +85,12 @@ const splitBorderValue = (value) => {
76
85
  }
77
86
  return null;
78
87
  }
88
+ if (expression !== null) {
89
+ const open = ['width', 'style', 'color'].filter((part) => !parts[part]);
90
+ if (open.length !== 1)
91
+ return null;
92
+ parts[open[0]] = expression;
93
+ }
79
94
  return {
80
95
  width: parts.width ?? INITIAL.width,
81
96
  style: parts.style ?? INITIAL.style,
@@ -286,7 +286,7 @@ const validData = {
286
286
  textDecorationColor: [],
287
287
  caretColor: ['auto'],
288
288
  columnRuleColor: [],
289
- borderColor: [],
289
+ borderColor: ['currentColor'],
290
290
  captionSide: ['top', 'bottom'],
291
291
  clear: [
292
292
  'inline-start',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/eslint-plugin",
3
- "version": "18.2.11",
3
+ "version": "18.2.13",
4
4
  "description": "Plumeria ESLint plugin",
5
5
  "author": "Refirst 11",
6
6
  "license": "MIT",