@plumeria/eslint-plugin 18.2.28 → 18.2.30

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.
@@ -186,7 +186,9 @@ const minString = 'min\\([^()]*\\)';
186
186
  const maxString = 'max\\([^()]*\\)';
187
187
  const minmaxString = 'minmax\\([^()]*\\)';
188
188
  const dashedIdentString = '--[a-zA-Z_][a-zA-Z0-9_-]*';
189
- const varString = `var\\(${dashedIdentString}(,\\s*[^\\)]+)?\\)`;
189
+ const cssVariablePlaceholder = '\u0001';
190
+ const canonicalCssVariable = (index) => `var(--x${index})`;
191
+ const varString = `(?:var\\(${dashedIdentString}(,\\s*[^\\)]+)?\\)|${cssVariablePlaceholder})`;
190
192
  const varRegex = new RegExp(`^(${varString})$`);
191
193
  const pureNumber = `(-?\\d+(\\.\\d+)?)`;
192
194
  const numberPattern = `(${pureNumber}|${varString})`;
@@ -201,7 +203,7 @@ const anchorString = 'anchor\\([^()]*\\)';
201
203
  const anchorSizeString = 'anchor-size\\([^()]*\\)';
202
204
  const clampString = 'clamp\\([^()]*\\)';
203
205
  const gradientString = '(?:repeating-)?(?:linear|radial|conic)-gradient\\(.*\\)';
204
- const urlString = 'url\\([^\\)]+\\)';
206
+ const urlString = `url\\([^\\)${cssVariablePlaceholder}]+\\)`;
205
207
  const imageSetString = 'image-set\\([^\\)]+\\)';
206
208
  const attrString = 'attr\\([^\\)]+\\)';
207
209
  const addString = `add\\(${integerPattern}\\)`;
@@ -210,7 +212,8 @@ const countersString = 'counters\\([^\\)]+\\)';
210
212
  const doubleQuoteString = '"[^"]*"';
211
213
  const singleQuoteString = "'[^']*'";
212
214
  const stringString = `(?:${doubleQuoteString}|${singleQuoteString})`;
213
- const repeatString = 'repeat\\([^\\)]+\\)';
215
+ const functionContentsString = '(?=[^)]*[^\\s()])(?:[^()]|\\([^()]*\\))*';
216
+ const repeatString = `repeat\\(${functionContentsString}\\)`;
214
217
  const colorSpaces = 'srgb|srgb-linear|display-p3|a98-rgb|prophoto-rgb|rec2020|lab|oklab|xyz|xyz-d50|xyz-d65|hsl|hwb|lch|oklch';
215
218
  const hueModifiers = '(?:\\s+(?:shorter|longer|increasing|decreasing)\\s+hue)?';
216
219
  const colorSpacePattern = `in\\s+(?:${colorSpaces})${hueModifiers}`;
@@ -282,6 +285,128 @@ const initialLetterProperties = ['initialLetter'];
282
285
  const hyphenateLimitCharsProperties = ['hyphenateLimitChars'];
283
286
  const shapeImageThresholdProperties = ['shapeImageThreshold'];
284
287
  const columnsProperties = ['columns'];
288
+ function getParenthesisDepth(value, end) {
289
+ let depth = 0;
290
+ let quote = '';
291
+ let escaped = false;
292
+ for (let index = 0; index < end; index++) {
293
+ const char = value[index];
294
+ if (escaped) {
295
+ escaped = false;
296
+ }
297
+ else if (char === '\\') {
298
+ escaped = true;
299
+ }
300
+ else if (quote) {
301
+ if (char === quote)
302
+ quote = '';
303
+ }
304
+ else if (char === '"' || char === "'") {
305
+ quote = char;
306
+ }
307
+ else if (char === '(') {
308
+ depth++;
309
+ }
310
+ else if (char === ')') {
311
+ depth--;
312
+ }
313
+ }
314
+ return depth;
315
+ }
316
+ function findCssVariableStart(value, start) {
317
+ let quote = '';
318
+ let escaped = false;
319
+ for (let index = start; index < value.length; index++) {
320
+ const char = value[index];
321
+ if (escaped) {
322
+ escaped = false;
323
+ }
324
+ else if (char === '\\') {
325
+ escaped = true;
326
+ }
327
+ else if (quote) {
328
+ if (char === quote)
329
+ quote = '';
330
+ }
331
+ else if (char === '"' || char === "'") {
332
+ quote = char;
333
+ }
334
+ else if (value.startsWith('var(', index) &&
335
+ (index === 0 || !/[a-zA-Z0-9_-]/.test(value[index - 1]))) {
336
+ return index;
337
+ }
338
+ }
339
+ return -1;
340
+ }
341
+ function normalizeCssVariables(value) {
342
+ if (value.includes(cssVariablePlaceholder))
343
+ return null;
344
+ let normalized = '';
345
+ let cursor = 0;
346
+ let isStandalone = false;
347
+ let canonicalIndex = 0;
348
+ while (cursor < value.length) {
349
+ const start = findCssVariableStart(value, cursor);
350
+ if (start === -1) {
351
+ return { isStandalone, value: normalized + value.slice(cursor) };
352
+ }
353
+ normalized += value.slice(cursor, start);
354
+ let depth = 1;
355
+ let quote = '';
356
+ let escaped = false;
357
+ let firstComma = -1;
358
+ let end = start + 4;
359
+ for (; end < value.length; end++) {
360
+ const char = value[end];
361
+ if (escaped) {
362
+ escaped = false;
363
+ continue;
364
+ }
365
+ if (char === '\\') {
366
+ escaped = true;
367
+ continue;
368
+ }
369
+ if (quote) {
370
+ if (char === quote)
371
+ quote = '';
372
+ continue;
373
+ }
374
+ if (char === '"' || char === "'") {
375
+ quote = char;
376
+ continue;
377
+ }
378
+ if (char === '(') {
379
+ depth++;
380
+ }
381
+ else if (char === ')') {
382
+ depth--;
383
+ if (depth === 0)
384
+ break;
385
+ }
386
+ else if (char === ',' && depth === 1 && firstComma === -1) {
387
+ firstComma = end;
388
+ }
389
+ }
390
+ if (depth !== 0 || quote)
391
+ return null;
392
+ const nameEnd = firstComma === -1 ? end : firstComma;
393
+ const name = value.slice(start + 4, nameEnd).trim();
394
+ if (!new RegExp(`^${dashedIdentString}$`).test(name))
395
+ return null;
396
+ if (firstComma !== -1) {
397
+ const fallback = value.slice(firstComma + 1, end).trim();
398
+ if (fallback && normalizeCssVariables(fallback) === null)
399
+ return null;
400
+ }
401
+ isStandalone = start === 0 && end === value.length - 1;
402
+ normalized +=
403
+ getParenthesisDepth(value, start) === 0
404
+ ? canonicalCssVariable(canonicalIndex++)
405
+ : cssVariablePlaceholder;
406
+ cursor = end + 1;
407
+ }
408
+ return { isStandalone, value: normalized };
409
+ }
285
410
  const valueCountMap = {
286
411
  inset: 4,
287
412
  gap: 2,
@@ -514,9 +639,9 @@ function isValidTextDecorationLine(value) {
514
639
  return false;
515
640
  const tokens = trimmedValue.split(/\s+/);
516
641
  return tokens.every((token) => {
517
- if (token.startsWith('var(') && varRegex.test(token))
642
+ if (varRegex.test(token))
518
643
  return true;
519
- if (decorationValues.includes(token) || varString.includes(token))
644
+ if (decorationValues.includes(token))
520
645
  return !usedValues.has(token) && usedValues.add(token);
521
646
  return false;
522
647
  });
@@ -531,7 +656,7 @@ function isValidContain(value) {
531
656
  return false;
532
657
  const tokens = trimmedValue.split(/\s+/);
533
658
  return tokens.every((token) => {
534
- if (token.startsWith('var(') && varRegex.test(token))
659
+ if (varRegex.test(token))
535
660
  return true;
536
661
  if (singleValues.includes(token))
537
662
  return tokens.length === 1;
@@ -1391,9 +1516,9 @@ function getValidator(key) {
1391
1516
  }
1392
1517
  else if (['backdropFilter', 'filter'].includes(key)) {
1393
1518
  const filterNumPattern = `(?:brightness|contrast|grayscale|invert|opacity|sepia|saturate)\\(\\s*${numberPattern}%?\\s*\\)`;
1394
- const blurPattern = `blur\\(\\s*(${lengthPattern}|${calcString}|${clampString}|${minString}|${maxString})\\s*\\)`;
1519
+ const blurPattern = `blur\\(\\s*(${lengthPattern}|${calcString}|${clampString}|${minString}|${maxString}|${varString})\\s*\\)`;
1395
1520
  const anglePatternFunc = `hue-rotate\\(\\s*${anglePattern}\\s*\\)`;
1396
- const dropShadowPattern = `drop-shadow\\(\\s*(?:${colorSource}|${lvp})(?:\\s+(?:${colorSource}|${lvp})){2,3}\\s*\\)`;
1521
+ const dropShadowPattern = `drop-shadow\\(\\s*(?:${varString}|(?:${colorSource}|${lvp})(?:\\s+(?:${colorSource}|${lvp})){2,3})\\s*\\)`;
1397
1522
  const r = new RegExp(`^((?:${filterNumPattern}|${blurPattern}|${anglePatternFunc}|${dropShadowPattern}|(?:${urlString}|${gradientString}|${varString}\\s*)?)\\s*)+$`);
1398
1523
  validator = (v) => r.test(v);
1399
1524
  }
@@ -1408,9 +1533,15 @@ function getValidator(key) {
1408
1533
  'step-end',
1409
1534
  ].join('|');
1410
1535
  const zeroToOne = '(0(\\.\\d+)?|1(\\.0+)?|0?\\.\\d+)';
1411
- const cubicBezierPattern = `cubic-bezier\\(\\s*${zeroToOne}\\s*,\\s*(-?\\d+(\\.\\d+)?)\\s*,\\s*${zeroToOne}\\s*,\\s*(-?\\d+(\\.\\d+)?)\\s*\\)`;
1412
- const linearPattern = `linear\\(\\s*(${zeroToOne}(\\s+\\d+(\\.\\d+)?%){0,2}(\\s*,\\s*${zeroToOne}(\\s+\\d+(\\.\\d+)?%){0,2})*)+\\s*\\)`;
1413
- const stepPattern = `steps\\(\\s*(\\d+)\\s*,\\s*(jump-start|jump-end|jump-none|jump-both|start|end)\\s*\\)`;
1536
+ const progressPattern = `(?:${zeroToOne}|${varString})`;
1537
+ const controlPointPattern = `(?:-?\\d+(\\.\\d+)?|${varString})`;
1538
+ const cubicBezierPattern = `cubic-bezier\\(\\s*(?:${varString}|${progressPattern}\\s*,\\s*${controlPointPattern}\\s*,\\s*${progressPattern}\\s*,\\s*${controlPointPattern})\\s*\\)`;
1539
+ const linearStopPattern = `${progressPattern}(?:\\s+(?:\\d+(\\.\\d+)?%|${varString})){0,2}`;
1540
+ const linearPattern = `linear\\(\\s*(?:${varString}|${linearStopPattern}(?:\\s*,\\s*${linearStopPattern})*)\\s*\\)`;
1541
+ const positiveIntegerPattern = '[1-9]\\d*';
1542
+ const atLeastTwoIntegerPattern = '(?:[2-9]|[1-9]\\d+)';
1543
+ const stepPositionPattern = `(?:jump-start|jump-end|jump-both|start|end|${varString})`;
1544
+ const stepPattern = `steps\\(\\s*(?:${varString}|(?:${positiveIntegerPattern}|${varString})(?:\\s*,\\s*${stepPositionPattern})?|(?:${atLeastTwoIntegerPattern}|${varString})\\s*,\\s*jump-none)\\s*\\)`;
1414
1545
  const singlePat = `(${easingPattern}|${cubicBezierPattern}|${linearPattern}|${stepPattern}|${varString})`;
1415
1546
  const r = new RegExp(`^${singlePat}(\\s*,\\s*${singlePat})*$`);
1416
1547
  validator = (v) => r.test(v);
@@ -1607,13 +1738,14 @@ exports.validateValues = {
1607
1738
  if (typeof rawValue !== 'string')
1608
1739
  return;
1609
1740
  const value = rawValue;
1741
+ const normalized = normalizeCssVariables(value);
1610
1742
  const globalValue = !validData_1.validData[key].includes(value) &&
1611
1743
  !globalValues.includes(value) &&
1612
- !varRegex.test(value);
1744
+ !normalized?.isStandalone;
1613
1745
  if (!globalValue)
1614
1746
  return;
1615
1747
  const validator = getValidator(key);
1616
- if (validator && !validator(value)) {
1748
+ if (validator && (!normalized || !validator(normalized.value))) {
1617
1749
  context.report({
1618
1750
  node: property.value,
1619
1751
  messageId: 'validateValue',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumeria/eslint-plugin",
3
- "version": "18.2.28",
3
+ "version": "18.2.30",
4
4
  "description": "Plumeria ESLint plugin",
5
5
  "author": "Refirst 11",
6
6
  "license": "MIT",