@trackunit/eslint-plugin-trackunit 0.6.101-alpha-d0f54ff2967.0 → 0.6.101

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.6.101 (2026-08-12)
2
+
3
+ ### 🧱 Updated Dependencies
4
+
5
+ - Updated css-classname-utils to 0.0.7
6
+ - Updated shared-utils to 1.16.4
7
+
1
8
  ## 0.6.100 (2026-08-11)
2
9
 
3
10
  ### 🩹 Fixes
package/README.md CHANGED
@@ -94,7 +94,7 @@ All custom rules are enabled automatically through the presets under the `@track
94
94
 
95
95
  | Rule | Severity | Auto-fix | Description |
96
96
  | --------------------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
97
- | `@trackunit/no-dynamic-translation-key` | warn | — | Discourages building i18next keys from template strings (`t(`a.${x}`)`). Map values to explicit keys with a `switch`/`Record`. |
97
+ | `@trackunit/no-dynamic-translation-key` | error | — | Discourages building i18next keys from template strings (`t(`a.${x}`)`). Map values to explicit keys with a `switch`/`Record`. |
98
98
  | `@trackunit/no-unused-translation-key` | warn | — | Reports keys in a library's `locales/en/translation.json` that are never referenced in that library's source. |
99
99
 
100
100
  ## Utilities
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/eslint-plugin-trackunit",
3
- "version": "0.6.101-alpha-d0f54ff2967.0",
3
+ "version": "0.6.101",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "repository": "https://github.com/Trackunit/manager",
6
6
  "engines": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@nx/eslint-plugin": "23.1.0",
11
- "@trackunit/css-classname-utils": "0.0.7-alpha-d0f54ff2967.0",
11
+ "@trackunit/css-classname-utils": "0.0.7",
12
12
  "@typescript-eslint/eslint-plugin": "8.58.1",
13
13
  "@typescript-eslint/utils": "8.58.1",
14
14
  "eslint-config-prettier": "^10.1.8",
@@ -107,7 +107,7 @@ exports.base = [
107
107
  "no-restricted-globals": no_direct_storage_access_1.noDirectStorageGlobalsRule,
108
108
  "@trackunit/no-internal-barrel-files": "error",
109
109
  "@trackunit/no-typescript-assertion": "warn",
110
- "@trackunit/no-dynamic-translation-key": "warn",
110
+ "@trackunit/no-dynamic-translation-key": "error",
111
111
  ...import_rules_1.importRules,
112
112
  ...typescript_rules_1.typescriptRules,
113
113
  },
@@ -25,6 +25,26 @@ const translation_key_types_1 = require("../../utils/translation-key-types");
25
25
  const createRule = utils_1.ESLintUtils.RuleCreator(name => `https://github.com/trackunit/manager/blob/main/libs/eslint/plugin-trackunit/src/lib/rules/${name}/${name}.ts`);
26
26
  /** A template literal that actually interpolates a value, e.g. `foo.${bar}` (not a plain `foo`). */
27
27
  const isInterpolatedTemplate = (node) => node.type === utils_1.AST_NODE_TYPES.TemplateLiteral && node.expressions.length > 0;
28
+ /**
29
+ * Strips `as`/`satisfies`/non-null/`<T>`-assertion wrappers to reach the underlying expression.
30
+ *
31
+ * `` t(`a.${x}` as never) `` parses as a `TSAsExpression` whose `.expression` is the real
32
+ * `TemplateLiteral`, so without this the wrapper silently hides the dynamic key from the rule.
33
+ * That is an escape hatch we must not offer: casting a widened interpolation is exactly what this
34
+ * rule exists to forbid, and the sibling `no-unused-translation-key` already unwraps the same
35
+ * wrappers (see its `expand-dynamic-key.ts#unwrapToTemplateExpression`), so leaving them here means
36
+ * one rule sees the key and the other does not.
37
+ */
38
+ const unwrapTypeWrappers = (node) => {
39
+ let current = node;
40
+ while (current.type === utils_1.AST_NODE_TYPES.TSAsExpression ||
41
+ current.type === utils_1.AST_NODE_TYPES.TSSatisfiesExpression ||
42
+ current.type === utils_1.AST_NODE_TYPES.TSNonNullExpression ||
43
+ current.type === utils_1.AST_NODE_TYPES.TSTypeAssertion) {
44
+ current = current.expression;
45
+ }
46
+ return current;
47
+ };
28
48
  /**
29
49
  * Whether a template literal's interpolations should be flagged: true unless every
30
50
  * interpolated expression's TypeScript type is a finite string-literal union (in which
@@ -75,8 +95,12 @@ exports.noDynamicTranslationKey = createRule({
75
95
  return;
76
96
  }
77
97
  const [firstArg] = node.arguments;
78
- if (firstArg && isInterpolatedTemplate(firstArg) && hasWidenedInterpolation(context, firstArg)) {
79
- context.report({ node: firstArg, messageId: "dynamicKey" });
98
+ if (!firstArg) {
99
+ return;
100
+ }
101
+ const key = unwrapTypeWrappers(firstArg);
102
+ if (isInterpolatedTemplate(key) && hasWidenedInterpolation(context, key)) {
103
+ context.report({ node: key, messageId: "dynamicKey" });
80
104
  }
81
105
  },
82
106
  JSXAttribute(node) {
@@ -84,10 +108,12 @@ exports.noDynamicTranslationKey = createRule({
84
108
  return;
85
109
  }
86
110
  const { value } = node;
87
- if (value?.type === utils_1.AST_NODE_TYPES.JSXExpressionContainer &&
88
- isInterpolatedTemplate(value.expression) &&
89
- hasWidenedInterpolation(context, value.expression)) {
90
- context.report({ node: value.expression, messageId: "dynamicKey" });
111
+ if (value?.type !== utils_1.AST_NODE_TYPES.JSXExpressionContainer) {
112
+ return;
113
+ }
114
+ const key = unwrapTypeWrappers(value.expression);
115
+ if (isInterpolatedTemplate(key) && hasWidenedInterpolation(context, key)) {
116
+ context.report({ node: key, messageId: "dynamicKey" });
91
117
  }
92
118
  },
93
119
  };