@bamboocss/eslint-plugin 1.15.0 → 1.16.1

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
@@ -8,7 +8,7 @@ require("@typescript-eslint/utils/ts-eslint");
8
8
  let _bamboocss_shared = require("@bamboocss/shared");
9
9
  //#region package.json
10
10
  var name = "@bamboocss/eslint-plugin";
11
- var version = "1.15.0";
11
+ var version = "1.16.1";
12
12
  //#endregion
13
13
  //#region src/utils/index.ts
14
14
  const createRule = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/bamboocss/bamboo/blob/main/packages/eslint-plugin/docs/rules/${name}.md`);
@@ -110,8 +110,6 @@ const matchFile = (name, imports, context) => {
110
110
  const isBambooIsh = (name, context) => {
111
111
  const imports = getImports(context);
112
112
  if (imports.length === 0) return false;
113
- const jsxFactory = syncAction("getJsxFactory", getSyncOptions(context));
114
- if (jsxFactory && name === jsxFactory) return imports.some((imp) => imp.name === name || imp.alias === name);
115
113
  return matchFile(name, imports, context);
116
114
  };
117
115
  const scopeCache = /* @__PURE__ */ new WeakMap();
@@ -309,8 +307,8 @@ function isRecipeVariant(node, context) {
309
307
  }
310
308
  //#endregion
311
309
  //#region src/rules/file-not-included.ts
312
- const RULE_NAME$18 = "file-not-included";
313
- const rule$18 = createRule({
310
+ const RULE_NAME$19 = "file-not-included";
311
+ const rule$19 = createRule({
314
312
  create(context) {
315
313
  if (isValidFile(context)) return {};
316
314
  let hasReported = false;
@@ -331,11 +329,11 @@ const rule$18 = createRule({
331
329
  schema: [],
332
330
  type: "problem"
333
331
  },
334
- name: RULE_NAME$18
332
+ name: RULE_NAME$19
335
333
  });
336
334
  //#endregion
337
335
  //#region src/rules/no-config-function-in-source.ts
338
- const RULE_NAME$17 = "no-config-function-in-source";
336
+ const RULE_NAME$18 = "no-config-function-in-source";
339
337
  const CONFIG_FUNCTIONS = new Set([
340
338
  "defineConfig",
341
339
  "defineGlobalStyles",
@@ -352,7 +350,7 @@ const CONFIG_FUNCTIONS = new Set([
352
350
  "defineTokens",
353
351
  "defineUtility"
354
352
  ]);
355
- const rule$17 = createRule({
353
+ const rule$18 = createRule({
356
354
  create(context) {
357
355
  if (!hasPkgImport(context)) return {};
358
356
  if (!isValidFile(context)) return {};
@@ -392,12 +390,12 @@ const rule$17 = createRule({
392
390
  schema: [],
393
391
  type: "problem"
394
392
  },
395
- name: RULE_NAME$17
393
+ name: RULE_NAME$18
396
394
  });
397
395
  //#endregion
398
396
  //#region src/rules/no-debug.ts
399
- const RULE_NAME$16 = "no-debug";
400
- const rule$16 = createRule({
397
+ const RULE_NAME$17 = "no-debug";
398
+ const rule$17 = createRule({
401
399
  create(context) {
402
400
  const processedNodes = /* @__PURE__ */ new WeakSet();
403
401
  const checkObjectForDebug = (object) => {
@@ -466,12 +464,12 @@ const rule$16 = createRule({
466
464
  schema: [],
467
465
  type: "problem"
468
466
  },
469
- name: RULE_NAME$16
467
+ name: RULE_NAME$17
470
468
  });
471
469
  //#endregion
472
470
  //#region src/rules/no-deprecated-tokens.ts
473
- const RULE_NAME$15 = "no-deprecated-tokens";
474
- const rule$15 = createRule({
471
+ const RULE_NAME$16 = "no-deprecated-tokens";
472
+ const rule$16 = createRule({
475
473
  create(context) {
476
474
  const deprecatedTokensCache = /* @__PURE__ */ new Map();
477
475
  const sendReport = (property, node, value) => {
@@ -525,12 +523,12 @@ const rule$15 = createRule({
525
523
  schema: [],
526
524
  type: "problem"
527
525
  },
528
- name: RULE_NAME$15
526
+ name: RULE_NAME$16
529
527
  });
530
528
  //#endregion
531
529
  //#region src/rules/no-dynamic-styling.ts
532
- const RULE_NAME$14 = "no-dynamic-styling";
533
- const rule$14 = createRule({
530
+ const RULE_NAME$15 = "no-dynamic-styling";
531
+ const rule$15 = createRule({
534
532
  create(context) {
535
533
  function isStaticValue(node) {
536
534
  if (!node) return false;
@@ -601,12 +599,12 @@ const rule$14 = createRule({
601
599
  schema: [],
602
600
  type: "problem"
603
601
  },
604
- name: RULE_NAME$14
602
+ name: RULE_NAME$15
605
603
  });
606
604
  //#endregion
607
605
  //#region src/rules/no-escape-hatch.ts
608
- const RULE_NAME$13 = "no-escape-hatch";
609
- const rule$13 = createRule({
606
+ const RULE_NAME$14 = "no-escape-hatch";
607
+ const rule$14 = createRule({
610
608
  create(context) {
611
609
  const removeBrackets = (range) => {
612
610
  const [start, end] = range;
@@ -679,12 +677,12 @@ const rule$13 = createRule({
679
677
  schema: [],
680
678
  type: "problem"
681
679
  },
682
- name: RULE_NAME$13
680
+ name: RULE_NAME$14
683
681
  });
684
682
  //#endregion
685
683
  //#region src/rules/no-hardcoded-color.ts
686
- const RULE_NAME$12 = "no-hardcoded-color";
687
- const rule$12 = createRule({
684
+ const RULE_NAME$13 = "no-hardcoded-color";
685
+ const rule$13 = createRule({
688
686
  create(context) {
689
687
  const noOpacity = context.options[0]?.noOpacity;
690
688
  const whitelist = context.options[0]?.whitelist ?? [];
@@ -780,14 +778,14 @@ const rule$12 = createRule({
780
778
  }],
781
779
  type: "problem"
782
780
  },
783
- name: RULE_NAME$12
781
+ name: RULE_NAME$13
784
782
  });
785
783
  //#endregion
786
784
  //#region src/rules/no-important.ts
787
785
  const exclamationRegex = /\s*!$/;
788
786
  const importantRegex = /\s*!important\s*$/;
789
- const RULE_NAME$11 = "no-important";
790
- const rule$11 = createRule({
787
+ const RULE_NAME$12 = "no-important";
788
+ const rule$12 = createRule({
791
789
  create(context) {
792
790
  const removeQuotes = (range) => {
793
791
  const [start, end] = range;
@@ -891,12 +889,12 @@ const rule$11 = createRule({
891
889
  schema: [],
892
890
  type: "problem"
893
891
  },
894
- name: RULE_NAME$11
892
+ name: RULE_NAME$12
895
893
  });
896
894
  //#endregion
897
895
  //#region src/rules/no-invalid-nesting.ts
898
- const RULE_NAME$10 = "no-invalid-nesting";
899
- const rule$10 = createRule({
896
+ const RULE_NAME$11 = "no-invalid-nesting";
897
+ const rule$11 = createRule({
900
898
  create(context) {
901
899
  const bambooFunctionCache = /* @__PURE__ */ new WeakMap();
902
900
  const jsxPropertyCache = /* @__PURE__ */ new WeakMap();
@@ -951,12 +949,12 @@ const rule$10 = createRule({
951
949
  schema: [],
952
950
  type: "problem"
953
951
  },
954
- name: RULE_NAME$10
952
+ name: RULE_NAME$11
955
953
  });
956
954
  //#endregion
957
955
  //#region src/rules/no-invalid-token-paths.ts
958
- const RULE_NAME$9 = "no-invalid-token-paths";
959
- const rule$9 = createRule({
956
+ const RULE_NAME$10 = "no-invalid-token-paths";
957
+ const rule$10 = createRule({
960
958
  create(context) {
961
959
  const invalidTokensCache = /* @__PURE__ */ new Map();
962
960
  const sendReport = (node, value) => {
@@ -1033,12 +1031,12 @@ const rule$9 = createRule({
1033
1031
  schema: [],
1034
1032
  type: "problem"
1035
1033
  },
1036
- name: RULE_NAME$9
1034
+ name: RULE_NAME$10
1037
1035
  });
1038
1036
  //#endregion
1039
1037
  //#region src/rules/no-margin-properties.ts
1040
- const RULE_NAME$8 = "no-margin-properties";
1041
- const rule$8 = createRule({
1038
+ const RULE_NAME$9 = "no-margin-properties";
1039
+ const rule$9 = createRule({
1042
1040
  create(context) {
1043
1041
  const whitelist = context.options[0]?.whitelist ?? [];
1044
1042
  const longhandCache = /* @__PURE__ */ new Map();
@@ -1114,7 +1112,7 @@ const rule$8 = createRule({
1114
1112
  }],
1115
1113
  type: "suggestion"
1116
1114
  },
1117
- name: RULE_NAME$8
1115
+ name: RULE_NAME$9
1118
1116
  });
1119
1117
  //#endregion
1120
1118
  //#region src/utils/physical-properties.ts
@@ -1158,7 +1156,7 @@ const physicalPropertyValues = { textAlign: {
1158
1156
  } };
1159
1157
  //#endregion
1160
1158
  //#region src/rules/no-physical-properties.ts
1161
- const RULE_NAME$7 = "no-physical-properties";
1159
+ const RULE_NAME$8 = "no-physical-properties";
1162
1160
  const MESSAGES = {
1163
1161
  physical: "Use logical property instead of {{physical}}. Prefer `{{logical}}`.",
1164
1162
  physicalValue: "Use logical value instead of {{physical}}. Prefer `{{logical}}`.",
@@ -1240,7 +1238,7 @@ const createValueReport = (valueNode, valueText, logical, context) => {
1240
1238
  }]
1241
1239
  });
1242
1240
  };
1243
- const rule$7 = createRule({
1241
+ const rule$8 = createRule({
1244
1242
  create(context) {
1245
1243
  const whitelist = context.options[0]?.whitelist ?? [];
1246
1244
  const cache = new PropertyCache();
@@ -1296,12 +1294,12 @@ const rule$7 = createRule({
1296
1294
  }],
1297
1295
  type: "suggestion"
1298
1296
  },
1299
- name: RULE_NAME$7
1297
+ name: RULE_NAME$8
1300
1298
  });
1301
1299
  //#endregion
1302
1300
  //#region src/rules/no-property-renaming.ts
1303
- const RULE_NAME$6 = "no-property-renaming";
1304
- const rule$6 = createRule({
1301
+ const RULE_NAME$7 = "no-property-renaming";
1302
+ const rule$7 = createRule({
1305
1303
  create(context) {
1306
1304
  const bambooPropertyCache = /* @__PURE__ */ new WeakMap();
1307
1305
  const bambooAttributeCache = /* @__PURE__ */ new WeakMap();
@@ -1365,6 +1363,65 @@ const rule$6 = createRule({
1365
1363
  schema: [],
1366
1364
  type: "problem"
1367
1365
  },
1366
+ name: RULE_NAME$7
1367
+ });
1368
+ //#endregion
1369
+ //#region src/rules/no-unlayered-override.ts
1370
+ const RULE_NAME$6 = "no-unlayered-override";
1371
+ /**
1372
+ * The call whose result is a class string in the `utilities` layer — the same layer a
1373
+ * consumer's `css()` is in, so neither can win over the other by cascade.
1374
+ *
1375
+ * `cva` and `sva` are deliberately absent. Their output is named semantically and emitted
1376
+ * into `recipes`, whether they are declared inline or in `theme.recipes`, so a consumer's
1377
+ * `css()` beats them by layer in every build. That is the fix this rule points at, and it
1378
+ * would be incoherent to report it.
1379
+ */
1380
+ const STYLING_CALLS = new Set(["css"]);
1381
+ const calleeName = (node) => {
1382
+ if (!isCallExpression(node)) return void 0;
1383
+ if (isIdentifier(node.callee)) return node.callee.name;
1384
+ if (isMemberExpression(node.callee) && isIdentifier(node.callee.property)) return void 0;
1385
+ };
1386
+ /**
1387
+ * An argument the rule cannot see the styles behind: a prop, a parameter, anything whose
1388
+ * value arrives at runtime. `props.className` is the shape this exists for.
1389
+ */
1390
+ const isOpaque = (node) => {
1391
+ if (isMemberExpression(node)) return true;
1392
+ if (isIdentifier(node) && node.name !== "undefined") return true;
1393
+ return false;
1394
+ };
1395
+ const rule$6 = createRule({
1396
+ create(context) {
1397
+ if (!isValidFile(context)) return {};
1398
+ const isOwnStyles = (node) => {
1399
+ const name = calleeName(node);
1400
+ return name !== void 0 && STYLING_CALLS.has(name);
1401
+ };
1402
+ return { CallExpression(node) {
1403
+ if (!isIdentifier(node.callee) || node.callee.name !== "cx") return;
1404
+ if (node.arguments.length < 2) return;
1405
+ const own = node.arguments.find((argument) => isOwnStyles(argument));
1406
+ if (!own) return;
1407
+ if (!node.arguments.find((argument) => argument !== own && isOpaque(argument))) return;
1408
+ context.report({
1409
+ messageId: "unlayeredOverride",
1410
+ node: own
1411
+ });
1412
+ } };
1413
+ },
1414
+ defaultOptions: [],
1415
+ meta: {
1416
+ docs: { description: "Disallow joining a class this file styled with a class it cannot see, where neither can win by cascade layer." },
1417
+ messages: { unlayeredOverride: [
1418
+ "`cx` joins class names, it does not resolve conflicts between them.",
1419
+ "These styles and the ones being joined are both in the `utilities` layer, so which applies is decided by stylesheet order rather than by the caller.",
1420
+ "Declare the component styles with `cva` so they land in the `recipes` layer, or accept a style object and merge it with `css(base, props.css)`."
1421
+ ].join(" ") },
1422
+ schema: [],
1423
+ type: "problem"
1424
+ },
1368
1425
  name: RULE_NAME$6
1369
1426
  });
1370
1427
  //#endregion
@@ -2215,6 +2272,7 @@ const rule = createRule({
2215
2272
  //#endregion
2216
2273
  //#region src/rules/index.ts
2217
2274
  const rules = {
2275
+ [RULE_NAME$19]: rule$19,
2218
2276
  [RULE_NAME$18]: rule$18,
2219
2277
  [RULE_NAME$17]: rule$17,
2220
2278
  [RULE_NAME$16]: rule$16,
@@ -2238,9 +2296,9 @@ const rules = {
2238
2296
  //#endregion
2239
2297
  //#region src/configs/all.ts
2240
2298
  const errorRules = [
2299
+ RULE_NAME$19,
2241
2300
  RULE_NAME$18,
2242
- RULE_NAME$17,
2243
- RULE_NAME$9
2301
+ RULE_NAME$10
2244
2302
  ];
2245
2303
  //#endregion
2246
2304
  //#region src/index.ts
@@ -2268,6 +2326,7 @@ const plugin = {
2268
2326
  "bamboo/no-invalid-nesting": "error",
2269
2327
  "bamboo/no-invalid-token-paths": "error",
2270
2328
  "bamboo/no-property-renaming": "warn",
2329
+ "bamboo/no-unlayered-override": "warn",
2271
2330
  "bamboo/no-unsafe-token-fn-usage": "warn"
2272
2331
  }
2273
2332
  }
package/dist/index.d.cts CHANGED
@@ -27,6 +27,7 @@ declare const plugin: {
27
27
  'bamboo/no-invalid-nesting': string;
28
28
  'bamboo/no-invalid-token-paths': string;
29
29
  'bamboo/no-property-renaming': string;
30
+ 'bamboo/no-unlayered-override': string;
30
31
  'bamboo/no-unsafe-token-fn-usage': string;
31
32
  };
32
33
  };
package/dist/index.d.mts CHANGED
@@ -27,6 +27,7 @@ declare const plugin: {
27
27
  'bamboo/no-invalid-nesting': string;
28
28
  'bamboo/no-invalid-token-paths': string;
29
29
  'bamboo/no-property-renaming': string;
30
+ 'bamboo/no-unlayered-override': string;
30
31
  'bamboo/no-unsafe-token-fn-usage': string;
31
32
  };
32
33
  };
package/dist/index.mjs CHANGED
@@ -8,7 +8,7 @@ import "@typescript-eslint/utils/ts-eslint";
8
8
  import { getArbitraryValue, parseFallbackValue } from "@bamboocss/shared";
9
9
  //#region package.json
10
10
  var name = "@bamboocss/eslint-plugin";
11
- var version = "1.15.0";
11
+ var version = "1.16.1";
12
12
  //#endregion
13
13
  //#region src/utils/index.ts
14
14
  const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/bamboocss/bamboo/blob/main/packages/eslint-plugin/docs/rules/${name}.md`);
@@ -110,8 +110,6 @@ const matchFile = (name, imports, context) => {
110
110
  const isBambooIsh = (name, context) => {
111
111
  const imports = getImports(context);
112
112
  if (imports.length === 0) return false;
113
- const jsxFactory = syncAction("getJsxFactory", getSyncOptions(context));
114
- if (jsxFactory && name === jsxFactory) return imports.some((imp) => imp.name === name || imp.alias === name);
115
113
  return matchFile(name, imports, context);
116
114
  };
117
115
  const scopeCache = /* @__PURE__ */ new WeakMap();
@@ -309,8 +307,8 @@ function isRecipeVariant(node, context) {
309
307
  }
310
308
  //#endregion
311
309
  //#region src/rules/file-not-included.ts
312
- const RULE_NAME$18 = "file-not-included";
313
- const rule$18 = createRule({
310
+ const RULE_NAME$19 = "file-not-included";
311
+ const rule$19 = createRule({
314
312
  create(context) {
315
313
  if (isValidFile(context)) return {};
316
314
  let hasReported = false;
@@ -331,11 +329,11 @@ const rule$18 = createRule({
331
329
  schema: [],
332
330
  type: "problem"
333
331
  },
334
- name: RULE_NAME$18
332
+ name: RULE_NAME$19
335
333
  });
336
334
  //#endregion
337
335
  //#region src/rules/no-config-function-in-source.ts
338
- const RULE_NAME$17 = "no-config-function-in-source";
336
+ const RULE_NAME$18 = "no-config-function-in-source";
339
337
  const CONFIG_FUNCTIONS = new Set([
340
338
  "defineConfig",
341
339
  "defineGlobalStyles",
@@ -352,7 +350,7 @@ const CONFIG_FUNCTIONS = new Set([
352
350
  "defineTokens",
353
351
  "defineUtility"
354
352
  ]);
355
- const rule$17 = createRule({
353
+ const rule$18 = createRule({
356
354
  create(context) {
357
355
  if (!hasPkgImport(context)) return {};
358
356
  if (!isValidFile(context)) return {};
@@ -392,12 +390,12 @@ const rule$17 = createRule({
392
390
  schema: [],
393
391
  type: "problem"
394
392
  },
395
- name: RULE_NAME$17
393
+ name: RULE_NAME$18
396
394
  });
397
395
  //#endregion
398
396
  //#region src/rules/no-debug.ts
399
- const RULE_NAME$16 = "no-debug";
400
- const rule$16 = createRule({
397
+ const RULE_NAME$17 = "no-debug";
398
+ const rule$17 = createRule({
401
399
  create(context) {
402
400
  const processedNodes = /* @__PURE__ */ new WeakSet();
403
401
  const checkObjectForDebug = (object) => {
@@ -466,12 +464,12 @@ const rule$16 = createRule({
466
464
  schema: [],
467
465
  type: "problem"
468
466
  },
469
- name: RULE_NAME$16
467
+ name: RULE_NAME$17
470
468
  });
471
469
  //#endregion
472
470
  //#region src/rules/no-deprecated-tokens.ts
473
- const RULE_NAME$15 = "no-deprecated-tokens";
474
- const rule$15 = createRule({
471
+ const RULE_NAME$16 = "no-deprecated-tokens";
472
+ const rule$16 = createRule({
475
473
  create(context) {
476
474
  const deprecatedTokensCache = /* @__PURE__ */ new Map();
477
475
  const sendReport = (property, node, value) => {
@@ -525,12 +523,12 @@ const rule$15 = createRule({
525
523
  schema: [],
526
524
  type: "problem"
527
525
  },
528
- name: RULE_NAME$15
526
+ name: RULE_NAME$16
529
527
  });
530
528
  //#endregion
531
529
  //#region src/rules/no-dynamic-styling.ts
532
- const RULE_NAME$14 = "no-dynamic-styling";
533
- const rule$14 = createRule({
530
+ const RULE_NAME$15 = "no-dynamic-styling";
531
+ const rule$15 = createRule({
534
532
  create(context) {
535
533
  function isStaticValue(node) {
536
534
  if (!node) return false;
@@ -601,12 +599,12 @@ const rule$14 = createRule({
601
599
  schema: [],
602
600
  type: "problem"
603
601
  },
604
- name: RULE_NAME$14
602
+ name: RULE_NAME$15
605
603
  });
606
604
  //#endregion
607
605
  //#region src/rules/no-escape-hatch.ts
608
- const RULE_NAME$13 = "no-escape-hatch";
609
- const rule$13 = createRule({
606
+ const RULE_NAME$14 = "no-escape-hatch";
607
+ const rule$14 = createRule({
610
608
  create(context) {
611
609
  const removeBrackets = (range) => {
612
610
  const [start, end] = range;
@@ -679,12 +677,12 @@ const rule$13 = createRule({
679
677
  schema: [],
680
678
  type: "problem"
681
679
  },
682
- name: RULE_NAME$13
680
+ name: RULE_NAME$14
683
681
  });
684
682
  //#endregion
685
683
  //#region src/rules/no-hardcoded-color.ts
686
- const RULE_NAME$12 = "no-hardcoded-color";
687
- const rule$12 = createRule({
684
+ const RULE_NAME$13 = "no-hardcoded-color";
685
+ const rule$13 = createRule({
688
686
  create(context) {
689
687
  const noOpacity = context.options[0]?.noOpacity;
690
688
  const whitelist = context.options[0]?.whitelist ?? [];
@@ -780,14 +778,14 @@ const rule$12 = createRule({
780
778
  }],
781
779
  type: "problem"
782
780
  },
783
- name: RULE_NAME$12
781
+ name: RULE_NAME$13
784
782
  });
785
783
  //#endregion
786
784
  //#region src/rules/no-important.ts
787
785
  const exclamationRegex = /\s*!$/;
788
786
  const importantRegex = /\s*!important\s*$/;
789
- const RULE_NAME$11 = "no-important";
790
- const rule$11 = createRule({
787
+ const RULE_NAME$12 = "no-important";
788
+ const rule$12 = createRule({
791
789
  create(context) {
792
790
  const removeQuotes = (range) => {
793
791
  const [start, end] = range;
@@ -891,12 +889,12 @@ const rule$11 = createRule({
891
889
  schema: [],
892
890
  type: "problem"
893
891
  },
894
- name: RULE_NAME$11
892
+ name: RULE_NAME$12
895
893
  });
896
894
  //#endregion
897
895
  //#region src/rules/no-invalid-nesting.ts
898
- const RULE_NAME$10 = "no-invalid-nesting";
899
- const rule$10 = createRule({
896
+ const RULE_NAME$11 = "no-invalid-nesting";
897
+ const rule$11 = createRule({
900
898
  create(context) {
901
899
  const bambooFunctionCache = /* @__PURE__ */ new WeakMap();
902
900
  const jsxPropertyCache = /* @__PURE__ */ new WeakMap();
@@ -951,12 +949,12 @@ const rule$10 = createRule({
951
949
  schema: [],
952
950
  type: "problem"
953
951
  },
954
- name: RULE_NAME$10
952
+ name: RULE_NAME$11
955
953
  });
956
954
  //#endregion
957
955
  //#region src/rules/no-invalid-token-paths.ts
958
- const RULE_NAME$9 = "no-invalid-token-paths";
959
- const rule$9 = createRule({
956
+ const RULE_NAME$10 = "no-invalid-token-paths";
957
+ const rule$10 = createRule({
960
958
  create(context) {
961
959
  const invalidTokensCache = /* @__PURE__ */ new Map();
962
960
  const sendReport = (node, value) => {
@@ -1033,12 +1031,12 @@ const rule$9 = createRule({
1033
1031
  schema: [],
1034
1032
  type: "problem"
1035
1033
  },
1036
- name: RULE_NAME$9
1034
+ name: RULE_NAME$10
1037
1035
  });
1038
1036
  //#endregion
1039
1037
  //#region src/rules/no-margin-properties.ts
1040
- const RULE_NAME$8 = "no-margin-properties";
1041
- const rule$8 = createRule({
1038
+ const RULE_NAME$9 = "no-margin-properties";
1039
+ const rule$9 = createRule({
1042
1040
  create(context) {
1043
1041
  const whitelist = context.options[0]?.whitelist ?? [];
1044
1042
  const longhandCache = /* @__PURE__ */ new Map();
@@ -1114,7 +1112,7 @@ const rule$8 = createRule({
1114
1112
  }],
1115
1113
  type: "suggestion"
1116
1114
  },
1117
- name: RULE_NAME$8
1115
+ name: RULE_NAME$9
1118
1116
  });
1119
1117
  //#endregion
1120
1118
  //#region src/utils/physical-properties.ts
@@ -1158,7 +1156,7 @@ const physicalPropertyValues = { textAlign: {
1158
1156
  } };
1159
1157
  //#endregion
1160
1158
  //#region src/rules/no-physical-properties.ts
1161
- const RULE_NAME$7 = "no-physical-properties";
1159
+ const RULE_NAME$8 = "no-physical-properties";
1162
1160
  const MESSAGES = {
1163
1161
  physical: "Use logical property instead of {{physical}}. Prefer `{{logical}}`.",
1164
1162
  physicalValue: "Use logical value instead of {{physical}}. Prefer `{{logical}}`.",
@@ -1240,7 +1238,7 @@ const createValueReport = (valueNode, valueText, logical, context) => {
1240
1238
  }]
1241
1239
  });
1242
1240
  };
1243
- const rule$7 = createRule({
1241
+ const rule$8 = createRule({
1244
1242
  create(context) {
1245
1243
  const whitelist = context.options[0]?.whitelist ?? [];
1246
1244
  const cache = new PropertyCache();
@@ -1296,12 +1294,12 @@ const rule$7 = createRule({
1296
1294
  }],
1297
1295
  type: "suggestion"
1298
1296
  },
1299
- name: RULE_NAME$7
1297
+ name: RULE_NAME$8
1300
1298
  });
1301
1299
  //#endregion
1302
1300
  //#region src/rules/no-property-renaming.ts
1303
- const RULE_NAME$6 = "no-property-renaming";
1304
- const rule$6 = createRule({
1301
+ const RULE_NAME$7 = "no-property-renaming";
1302
+ const rule$7 = createRule({
1305
1303
  create(context) {
1306
1304
  const bambooPropertyCache = /* @__PURE__ */ new WeakMap();
1307
1305
  const bambooAttributeCache = /* @__PURE__ */ new WeakMap();
@@ -1365,6 +1363,65 @@ const rule$6 = createRule({
1365
1363
  schema: [],
1366
1364
  type: "problem"
1367
1365
  },
1366
+ name: RULE_NAME$7
1367
+ });
1368
+ //#endregion
1369
+ //#region src/rules/no-unlayered-override.ts
1370
+ const RULE_NAME$6 = "no-unlayered-override";
1371
+ /**
1372
+ * The call whose result is a class string in the `utilities` layer — the same layer a
1373
+ * consumer's `css()` is in, so neither can win over the other by cascade.
1374
+ *
1375
+ * `cva` and `sva` are deliberately absent. Their output is named semantically and emitted
1376
+ * into `recipes`, whether they are declared inline or in `theme.recipes`, so a consumer's
1377
+ * `css()` beats them by layer in every build. That is the fix this rule points at, and it
1378
+ * would be incoherent to report it.
1379
+ */
1380
+ const STYLING_CALLS = new Set(["css"]);
1381
+ const calleeName = (node) => {
1382
+ if (!isCallExpression(node)) return void 0;
1383
+ if (isIdentifier(node.callee)) return node.callee.name;
1384
+ if (isMemberExpression(node.callee) && isIdentifier(node.callee.property)) return void 0;
1385
+ };
1386
+ /**
1387
+ * An argument the rule cannot see the styles behind: a prop, a parameter, anything whose
1388
+ * value arrives at runtime. `props.className` is the shape this exists for.
1389
+ */
1390
+ const isOpaque = (node) => {
1391
+ if (isMemberExpression(node)) return true;
1392
+ if (isIdentifier(node) && node.name !== "undefined") return true;
1393
+ return false;
1394
+ };
1395
+ const rule$6 = createRule({
1396
+ create(context) {
1397
+ if (!isValidFile(context)) return {};
1398
+ const isOwnStyles = (node) => {
1399
+ const name = calleeName(node);
1400
+ return name !== void 0 && STYLING_CALLS.has(name);
1401
+ };
1402
+ return { CallExpression(node) {
1403
+ if (!isIdentifier(node.callee) || node.callee.name !== "cx") return;
1404
+ if (node.arguments.length < 2) return;
1405
+ const own = node.arguments.find((argument) => isOwnStyles(argument));
1406
+ if (!own) return;
1407
+ if (!node.arguments.find((argument) => argument !== own && isOpaque(argument))) return;
1408
+ context.report({
1409
+ messageId: "unlayeredOverride",
1410
+ node: own
1411
+ });
1412
+ } };
1413
+ },
1414
+ defaultOptions: [],
1415
+ meta: {
1416
+ docs: { description: "Disallow joining a class this file styled with a class it cannot see, where neither can win by cascade layer." },
1417
+ messages: { unlayeredOverride: [
1418
+ "`cx` joins class names, it does not resolve conflicts between them.",
1419
+ "These styles and the ones being joined are both in the `utilities` layer, so which applies is decided by stylesheet order rather than by the caller.",
1420
+ "Declare the component styles with `cva` so they land in the `recipes` layer, or accept a style object and merge it with `css(base, props.css)`."
1421
+ ].join(" ") },
1422
+ schema: [],
1423
+ type: "problem"
1424
+ },
1368
1425
  name: RULE_NAME$6
1369
1426
  });
1370
1427
  //#endregion
@@ -2215,6 +2272,7 @@ const rule = createRule({
2215
2272
  //#endregion
2216
2273
  //#region src/rules/index.ts
2217
2274
  const rules = {
2275
+ [RULE_NAME$19]: rule$19,
2218
2276
  [RULE_NAME$18]: rule$18,
2219
2277
  [RULE_NAME$17]: rule$17,
2220
2278
  [RULE_NAME$16]: rule$16,
@@ -2238,9 +2296,9 @@ const rules = {
2238
2296
  //#endregion
2239
2297
  //#region src/configs/all.ts
2240
2298
  const errorRules = [
2299
+ RULE_NAME$19,
2241
2300
  RULE_NAME$18,
2242
- RULE_NAME$17,
2243
- RULE_NAME$9
2301
+ RULE_NAME$10
2244
2302
  ];
2245
2303
  //#endregion
2246
2304
  //#region src/index.ts
@@ -2268,6 +2326,7 @@ const plugin = {
2268
2326
  "bamboo/no-invalid-nesting": "error",
2269
2327
  "bamboo/no-invalid-token-paths": "error",
2270
2328
  "bamboo/no-property-renaming": "warn",
2329
+ "bamboo/no-unlayered-override": "warn",
2271
2330
  "bamboo/no-unsafe-token-fn-usage": "warn"
2272
2331
  }
2273
2332
  }
@@ -83,7 +83,6 @@ async function runAsync(action, options, ...args) {
83
83
  case "filterDeprecatedTokens": return filterDeprecatedTokens(context, ...args);
84
84
  case "filterImports": return filterImports(context, ...args);
85
85
  case "filterInvalidTokens": return filterInvalidTokens(context, ...args);
86
- case "getJsxFactory": return getJsxFactory(context);
87
86
  case "getPropCategory": return getPropertyCategory(context, ...args);
88
87
  case "isColorAttribute": return isColorAttribute(context, ...args);
89
88
  case "isColorToken": return isColorToken(context, ...args);
@@ -107,8 +106,7 @@ const isValidFile = (context, fileName) => {
107
106
  const isValidProperty = (context, name, patternName) => {
108
107
  if (context.isValidProperty(name)) return true;
109
108
  if (!patternName) return false;
110
- if (patternName === context.config.jsxFactory) return false;
111
- const pattern = context.patterns.details.find((p) => p.baseName === patternName || p.jsx.includes(patternName))?.config.properties;
109
+ const pattern = context.patterns.details.find((p) => p.baseName === patternName)?.config.properties;
112
110
  if (!pattern) return false;
113
111
  return Object.keys(pattern).includes(name);
114
112
  };
@@ -146,9 +144,6 @@ const resolveLongHand = (context, name) => {
146
144
  const resolveShorthands = (context, name) => {
147
145
  return context.utility.getPropShorthandsMap().get(name);
148
146
  };
149
- const getJsxFactory = (context) => {
150
- return context.config.jsxFactory;
151
- };
152
147
  (0, synckit.runAsWorker)(run);
153
148
  //#endregion
154
149
  exports.getContext = getContext;
@@ -33,7 +33,6 @@ declare function run(action: 'matchImports', options: Options, result: MatchImpo
33
33
  declare function run(action: 'filterImports', options: Options, imports: MatchImportResult[]): MatchImportResult[];
34
34
  declare function run(action: 'getPropCategory', options: Options, property: string): string;
35
35
  declare function run(action: 'filterDeprecatedTokens', options: Options, tokens: DeprecatedToken[]): DeprecatedToken[];
36
- declare function run(action: 'getJsxFactory', options: Options): string | undefined;
37
36
  declare function runAsync(action: 'filterInvalidTokens', options: Options, paths: string[]): Promise<string[]>;
38
37
  declare function runAsync(action: 'isColorToken', options: Options, value: string): Promise<boolean>;
39
38
  declare function runAsync(action: 'isColorAttribute', options: Options, attribute: string): Promise<boolean>;
@@ -46,6 +45,5 @@ declare function runAsync(action: 'matchImports', options: Options, result: Matc
46
45
  declare function runAsync(action: 'filterImports', options: Options, imports: MatchImportResult[]): Promise<MatchImportResult[]>;
47
46
  declare function runAsync(action: 'getPropCategory', options: Options, property: string): Promise<string>;
48
47
  declare function runAsync(action: 'filterDeprecatedTokens', options: Options, tokens: DeprecatedToken[]): Promise<DeprecatedToken[]>;
49
- declare function runAsync(action: 'getJsxFactory', options: Options): Promise<string | undefined>;
50
48
  //#endregion
51
49
  export { DeprecatedToken, getContext, run, runAsync };
@@ -33,7 +33,6 @@ declare function run(action: 'matchImports', options: Options, result: MatchImpo
33
33
  declare function run(action: 'filterImports', options: Options, imports: MatchImportResult[]): MatchImportResult[];
34
34
  declare function run(action: 'getPropCategory', options: Options, property: string): string;
35
35
  declare function run(action: 'filterDeprecatedTokens', options: Options, tokens: DeprecatedToken[]): DeprecatedToken[];
36
- declare function run(action: 'getJsxFactory', options: Options): string | undefined;
37
36
  declare function runAsync(action: 'filterInvalidTokens', options: Options, paths: string[]): Promise<string[]>;
38
37
  declare function runAsync(action: 'isColorToken', options: Options, value: string): Promise<boolean>;
39
38
  declare function runAsync(action: 'isColorAttribute', options: Options, attribute: string): Promise<boolean>;
@@ -46,6 +45,5 @@ declare function runAsync(action: 'matchImports', options: Options, result: Matc
46
45
  declare function runAsync(action: 'filterImports', options: Options, imports: MatchImportResult[]): Promise<MatchImportResult[]>;
47
46
  declare function runAsync(action: 'getPropCategory', options: Options, property: string): Promise<string>;
48
47
  declare function runAsync(action: 'filterDeprecatedTokens', options: Options, tokens: DeprecatedToken[]): Promise<DeprecatedToken[]>;
49
- declare function runAsync(action: 'getJsxFactory', options: Options): Promise<string | undefined>;
50
48
  //#endregion
51
49
  export { DeprecatedToken, getContext, run, runAsync };
@@ -58,7 +58,6 @@ async function runAsync(action, options, ...args) {
58
58
  case "filterDeprecatedTokens": return filterDeprecatedTokens(context, ...args);
59
59
  case "filterImports": return filterImports(context, ...args);
60
60
  case "filterInvalidTokens": return filterInvalidTokens(context, ...args);
61
- case "getJsxFactory": return getJsxFactory(context);
62
61
  case "getPropCategory": return getPropertyCategory(context, ...args);
63
62
  case "isColorAttribute": return isColorAttribute(context, ...args);
64
63
  case "isColorToken": return isColorToken(context, ...args);
@@ -82,8 +81,7 @@ const isValidFile = (context, fileName) => {
82
81
  const isValidProperty = (context, name, patternName) => {
83
82
  if (context.isValidProperty(name)) return true;
84
83
  if (!patternName) return false;
85
- if (patternName === context.config.jsxFactory) return false;
86
- const pattern = context.patterns.details.find((p) => p.baseName === patternName || p.jsx.includes(patternName))?.config.properties;
84
+ const pattern = context.patterns.details.find((p) => p.baseName === patternName)?.config.properties;
87
85
  if (!pattern) return false;
88
86
  return Object.keys(pattern).includes(name);
89
87
  };
@@ -121,9 +119,6 @@ const resolveLongHand = (context, name) => {
121
119
  const resolveShorthands = (context, name) => {
122
120
  return context.utility.getPropShorthandsMap().get(name);
123
121
  };
124
- const getJsxFactory = (context) => {
125
- return context.config.jsxFactory;
126
- };
127
122
  runAsWorker(run);
128
123
  //#endregion
129
124
  export { getContext, run, runAsync };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamboocss/eslint-plugin",
3
- "version": "1.15.0",
3
+ "version": "1.16.1",
4
4
  "description": "ESLint plugin for Bamboo CSS",
5
5
  "homepage": "https://bamboocss.com",
6
6
  "license": "MIT",
@@ -36,9 +36,9 @@
36
36
  "@typescript-eslint/utils": "^8.21.0",
37
37
  "micromatch": "^4.0.8",
38
38
  "synckit": "^0.9.0",
39
- "@bamboocss/config": "1.15.0",
40
- "@bamboocss/generator": "1.15.0",
41
- "@bamboocss/shared": "1.15.0"
39
+ "@bamboocss/config": "1.16.1",
40
+ "@bamboocss/generator": "1.16.1",
41
+ "@bamboocss/shared": "1.16.1"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/micromatch": "^4.0.10",
@@ -46,10 +46,10 @@
46
46
  "eslint": "^9.35.0",
47
47
  "multiline-ts": "^4.0.1",
48
48
  "typescript": "^5.7.2",
49
- "@bamboocss/dev": "1.15.0",
50
- "@bamboocss/preset-bamboo": "1.15.0",
51
- "@bamboocss/preset-base": "1.15.0",
52
- "@bamboocss/types": "1.15.0"
49
+ "@bamboocss/dev": "1.16.1",
50
+ "@bamboocss/preset-bamboo": "1.16.1",
51
+ "@bamboocss/preset-base": "1.16.1",
52
+ "@bamboocss/types": "1.16.1"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "eslint": "*"