@generaltranslation/gt-next-lint 14.0.26 → 14.0.28

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.
@@ -1,19 +1,17 @@
1
- "use strict";
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/configs/recommended.ts
2
3
  /**
3
- * Recommended ESLint configuration for GT-Next
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.recommended = void 0;
7
- exports.recommended = {
8
- plugins: ['gt-next'],
9
- rules: {
10
- 'gt-next/no-dynamic-jsx': true,
11
- 'gt-next/no-dynamic-string': true,
12
- },
13
- settings: {
14
- react: {
15
- version: 'detect',
16
- },
17
- },
4
+ * Recommended ESLint configuration for GT-Next
5
+ */
6
+ const recommended = {
7
+ plugins: ["gt-next"],
8
+ rules: {
9
+ "gt-next/no-dynamic-jsx": true,
10
+ "gt-next/no-dynamic-string": true
11
+ },
12
+ settings: { react: { version: "detect" } }
18
13
  };
14
+ //#endregion
15
+ exports.recommended = recommended;
16
+
19
17
  //# sourceMappingURL=recommended.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"recommended.js","sourceRoot":"","sources":["../../src/configs/recommended.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEU,QAAA,WAAW,GAAG;IACzB,OAAO,EAAE,CAAC,SAAS,CAAC;IACpB,KAAK,EAAE;QACL,wBAAwB,EAAE,IAAI;QAC9B,2BAA2B,EAAE,IAAI;KAClC;IACD,QAAQ,EAAE;QACR,KAAK,EAAE;YACL,OAAO,EAAE,QAAQ;SAClB;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"recommended.js","names":[],"sources":["../../src/configs/recommended.ts"],"sourcesContent":["/**\n * Recommended ESLint configuration for GT-Next\n */\n\nexport const recommended = {\n plugins: ['gt-next'],\n rules: {\n 'gt-next/no-dynamic-jsx': true,\n 'gt-next/no-dynamic-string': true,\n },\n settings: {\n react: {\n version: 'detect',\n },\n },\n};\n"],"mappings":";;;;;AAIA,MAAa,cAAc;CACzB,SAAS,CAAC,UAAU;CACpB,OAAO;EACL,0BAA0B;EAC1B,6BAA6B;EAC9B;CACD,UAAU,EACR,OAAO,EACL,SAAS,UACV,EACF;CACF"}
package/dist/index.js CHANGED
@@ -1,26 +1,26 @@
1
- "use strict";
1
+ const require_rules_no_dynamic_jsx = require("./rules/no-dynamic-jsx.js");
2
+ const require_rules_no_dynamic_string = require("./rules/no-dynamic-string.js");
3
+ const require_configs_recommended = require("./configs/recommended.js");
4
+ //#region src/index.ts
2
5
  /**
3
- * GT-Next ESLint Plugin
4
- *
5
- * Provides ESLint rules for General Translation Next.js integration.
6
- * This plugin detects unwrapped dynamic content in translation components
7
- * and provides better error reporting with file locations and line numbers.
8
- */
9
- const no_dynamic_jsx_1 = require("./rules/no-dynamic-jsx");
10
- const no_dynamic_string_1 = require("./rules/no-dynamic-string");
11
- const recommended_1 = require("./configs/recommended");
6
+ * GT-Next ESLint Plugin
7
+ *
8
+ * Provides ESLint rules for General Translation Next.js integration.
9
+ * This plugin detects unwrapped dynamic content in translation components
10
+ * and provides better error reporting with file locations and line numbers.
11
+ */
12
12
  const plugin = {
13
- meta: {
14
- name: '@generaltranslation/gt-next-lint',
15
- version: '1.0.0',
16
- },
17
- rules: {
18
- 'no-dynamic-jsx': no_dynamic_jsx_1.noDynamicJsx,
19
- 'no-dynamic-string': no_dynamic_string_1.noDynamicString,
20
- },
21
- configs: {
22
- recommended: recommended_1.recommended,
23
- },
13
+ meta: {
14
+ name: "@generaltranslation/gt-next-lint",
15
+ version: "1.0.0"
16
+ },
17
+ rules: {
18
+ "no-dynamic-jsx": require_rules_no_dynamic_jsx.noDynamicJsx,
19
+ "no-dynamic-string": require_rules_no_dynamic_string.noDynamicString
20
+ },
21
+ configs: { recommended: require_configs_recommended.recommended }
24
22
  };
25
23
  module.exports = plugin;
24
+ //#endregion
25
+
26
26
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;AAEH,2DAAsD;AACtD,iEAA4D;AAC5D,uDAAoD;AAEpD,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,kCAAkC;QACxC,OAAO,EAAE,OAAO;KACjB;IACD,KAAK,EAAE;QACL,gBAAgB,EAAE,6BAAY;QAC9B,mBAAmB,EAAE,mCAAe;KACrC;IACD,OAAO,EAAE;QACP,WAAW,EAAX,yBAAW;KACZ;CACF,CAAC;AAEF,iBAAS,MAAM,CAAC"}
1
+ {"version":3,"file":"index.js","names":["noDynamicJsx","noDynamicString"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * GT-Next ESLint Plugin\n *\n * Provides ESLint rules for General Translation Next.js integration.\n * This plugin detects unwrapped dynamic content in translation components\n * and provides better error reporting with file locations and line numbers.\n */\n\nimport { noDynamicJsx } from './rules/no-dynamic-jsx';\nimport { noDynamicString } from './rules/no-dynamic-string';\nimport { recommended } from './configs/recommended';\n\nconst plugin = {\n meta: {\n name: '@generaltranslation/gt-next-lint',\n version: '1.0.0',\n },\n rules: {\n 'no-dynamic-jsx': noDynamicJsx,\n 'no-dynamic-string': noDynamicString,\n },\n configs: {\n recommended,\n },\n};\n\nexport = plugin;\n"],"mappings":";;;;;;;;;;;AAYA,MAAM,SAAS;CACb,MAAM;EACJ,MAAM;EACN,SAAS;EACV;CACD,OAAO;EACL,kBAAkBA,6BAAAA;EAClB,qBAAqBC,gCAAAA;EACtB;CACD,SAAS,EACP,aAAA,4BAAA,aACD;CACF;iBAEQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"no-dynamic-jsx.d.ts","sourceRoot":"","sources":["../../src/rules/no-dynamic-jsx.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAkBnC,eAAO,MAAM,YAAY,EAAE,IAAI,CAAC,UAyN/B,CAAC"}
1
+ {"version":3,"file":"no-dynamic-jsx.d.ts","sourceRoot":"","sources":["../../src/rules/no-dynamic-jsx.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAcnC,eAAO,MAAM,YAAY,EAAE,IAAI,CAAC,UAuO/B,CAAC"}
@@ -1,209 +1,153 @@
1
- "use strict";
2
- /**
3
- * ESLint rule: no-dynamic-jsx
4
- *
5
- * Detects unwrapped dynamic content in GT-Next translation components.
6
- * Equivalent to the SWC plugin functionality but with proper ESLint error reporting.
7
- *
8
- * This rule checks for JSX expressions ({dynamic content}) inside <T> components
9
- * that are not wrapped in variable components (<Var>, <DateTime>, <Num>, <Currency>).
10
- */
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.noDynamicJsx = void 0;
13
- const GT_MODULES = ['gt-next', 'gt-next/client', 'gt-next/server'];
14
- const TRANSLATION_COMPONENTS = ['T'];
15
- const VARIABLE_COMPONENTS = ['Var', 'DateTime', 'Num', 'Currency'];
16
- function isGTModule(source) {
17
- return GT_MODULES.includes(source);
18
- }
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_rules_utils = require("./utils.js");
3
+ //#region src/rules/no-dynamic-jsx.ts
4
+ const TRANSLATION_COMPONENTS = ["T"];
5
+ const VARIABLE_COMPONENTS = [
6
+ "Var",
7
+ "DateTime",
8
+ "Num",
9
+ "Currency"
10
+ ];
19
11
  function isTranslationComponent(name) {
20
- return TRANSLATION_COMPONENTS.includes(name);
12
+ return TRANSLATION_COMPONENTS.includes(name);
21
13
  }
22
14
  function isVariableComponent(name) {
23
- return VARIABLE_COMPONENTS.includes(name);
15
+ return VARIABLE_COMPONENTS.includes(name);
24
16
  }
25
- exports.noDynamicJsx = {
26
- meta: {
27
- type: 'problem',
28
- docs: {
29
- description: 'Detect unwrapped dynamic content in GT-Next translation components',
30
- category: 'Best Practices',
31
- recommended: true,
32
- url: 'https://github.com/generaltranslation/gt/tree/main/packages/next-lint#no-dynamic-jsx',
33
- },
34
- fixable: undefined,
35
- schema: [],
36
- messages: {
37
- dynamicJsx: 'Dynamic content in <T> component should be wrapped in a variable component (<Var>, <DateTime>, <Num>, or <Currency>)',
38
- },
39
- },
40
- create(context) {
41
- const state = {
42
- translationStack: 0,
43
- variableStack: 0,
44
- imports: {
45
- translationComponents: new Set(),
46
- variableComponents: new Set(),
47
- namespaceImports: new Set(),
48
- assignedTranslationComponents: new Set(),
49
- assignedVariableComponents: new Set(),
50
- },
51
- };
52
- function getElementName(node) {
53
- const name = node?.openingElement?.name;
54
- if (!name)
55
- return null;
56
- if (name.type === 'JSXIdentifier') {
57
- return name.name;
58
- }
59
- if (name.type === 'JSXMemberExpression') {
60
- const obj = name.object;
61
- const prop = name.property;
62
- if (obj?.type === 'JSXIdentifier' && prop?.type === 'JSXIdentifier') {
63
- return `${obj.name}.${prop.name}`;
64
- }
65
- }
66
- return null;
67
- }
68
- function isNamespaceTranslationComponent(elementName) {
69
- const parts = elementName.split('.');
70
- if (parts.length === 2) {
71
- const [namespace, component] = parts;
72
- return (state.imports.namespaceImports.has(namespace) &&
73
- isTranslationComponent(component));
74
- }
75
- return false;
76
- }
77
- function isNamespaceVariableComponent(elementName) {
78
- const parts = elementName.split('.');
79
- if (parts.length === 2) {
80
- const [namespace, component] = parts;
81
- return (state.imports.namespaceImports.has(namespace) &&
82
- isVariableComponent(component));
83
- }
84
- return false;
85
- }
86
- function isInsideJSXAttribute(node) {
87
- // Walk up the AST to check if this expression is inside a JSX attribute
88
- let currentNode = node.parent;
89
- while (currentNode) {
90
- if (currentNode.type === 'JSXAttribute') {
91
- return true;
92
- }
93
- // If we reach a JSX element, we're in element content, not attributes
94
- if (currentNode.type === 'JSXElement') {
95
- return false;
96
- }
97
- currentNode = currentNode.parent;
98
- }
99
- return false;
100
- }
101
- // Check if the node is a string literal or template literal
102
- function isStringLiteral(expression) {
103
- // For JSXExpressionContainer, check the expression inside
104
- return ((expression.type === 'Literal' &&
105
- typeof expression.value === 'string') ||
106
- (expression.type === 'TemplateLiteral' &&
107
- expression.expressions.length === 0) // No interpolation
108
- );
109
- }
110
- // Check if the node is a comment
111
- function isComment(expression) {
112
- return expression.type === 'Block' || expression.type === 'Line';
113
- }
114
- // Check if empty
115
- function isEmpty(expression) {
116
- return expression.type === 'JSXEmptyExpression';
117
- }
118
- return {
119
- // Track imports from GT-Next modules
120
- ImportDeclaration(node) {
121
- if (node.source?.type === 'Literal' &&
122
- typeof node.source.value === 'string') {
123
- const source = node.source.value;
124
- if (isGTModule(source)) {
125
- for (const specifier of node.specifiers || []) {
126
- if (specifier.type === 'ImportSpecifier') {
127
- const importedName = specifier.imported?.name || '';
128
- const localName = specifier.local?.name || '';
129
- if (isTranslationComponent(importedName)) {
130
- state.imports.translationComponents.add(localName);
131
- }
132
- else if (isVariableComponent(importedName)) {
133
- state.imports.variableComponents.add(localName);
134
- }
135
- }
136
- else if (specifier.type === 'ImportNamespaceSpecifier') {
137
- const localName = specifier.local?.name || '';
138
- state.imports.namespaceImports.add(localName);
139
- }
140
- }
141
- }
142
- }
143
- },
144
- // Track variable assignments from GT components
145
- VariableDeclarator(node) {
146
- if (node.id?.type === 'Identifier' &&
147
- node.init?.type === 'Identifier') {
148
- const varName = node.id.name;
149
- const assignedFrom = node.init.name;
150
- if (state.imports.translationComponents.has(assignedFrom)) {
151
- state.imports.assignedTranslationComponents.add(varName);
152
- }
153
- else if (state.imports.variableComponents.has(assignedFrom)) {
154
- state.imports.assignedVariableComponents.add(varName);
155
- }
156
- }
157
- },
158
- // Detect unwrapped dynamic content
159
- JSXExpressionContainer(node) {
160
- // Skip expressions inside JSX attributes (e.g., <Image width={16} />)
161
- if (isInsideJSXAttribute(node)) {
162
- return;
163
- }
164
- // Skip expressions with just a string literal (e.g., {'Hello'})
165
- // Skip expressions with just a comment
166
- // Skip expressions with just an empty statement
167
- if ((node.expression && isStringLiteral(node.expression)) ||
168
- isComment(node.expression) ||
169
- isEmpty(node.expression)) {
170
- return;
171
- }
172
- // Check if this expression is inside a translation component but not inside a variable component
173
- let inTranslationComponent = false;
174
- let inVariableComponent = false;
175
- // Walk up the AST to find parent JSX elements
176
- let currentNode = node.parent;
177
- while (currentNode) {
178
- if (currentNode.type === 'JSXElement') {
179
- const elementName = getElementName(currentNode);
180
- if (elementName) {
181
- // Check if this is a variable component
182
- if (state.imports.variableComponents.has(elementName) ||
183
- state.imports.assignedVariableComponents.has(elementName) ||
184
- isNamespaceVariableComponent(elementName)) {
185
- inVariableComponent = true;
186
- break; // If we find a variable component, we don't need to check further
187
- }
188
- // Check if this is a translation component
189
- else if (state.imports.translationComponents.has(elementName) ||
190
- state.imports.assignedTranslationComponents.has(elementName) ||
191
- isNamespaceTranslationComponent(elementName)) {
192
- inTranslationComponent = true;
193
- }
194
- }
195
- }
196
- currentNode = currentNode.parent;
197
- }
198
- // Report if we're inside a translation component but not inside a variable component
199
- if (inTranslationComponent && !inVariableComponent) {
200
- context.report({
201
- node,
202
- messageId: 'dynamicJsx',
203
- });
204
- }
205
- },
206
- };
207
- },
17
+ const noDynamicJsx = {
18
+ meta: {
19
+ type: "problem",
20
+ docs: {
21
+ description: "Detect unwrapped dynamic content in GT-Next translation components",
22
+ category: "Best Practices",
23
+ recommended: true,
24
+ url: "https://github.com/generaltranslation/gt/tree/main/packages/next-lint#no-dynamic-jsx"
25
+ },
26
+ fixable: void 0,
27
+ schema: [],
28
+ messages: { dynamicJsx: "Dynamic content in <T> component should be wrapped in a variable component (<Var>, <DateTime>, <Num>, or <Currency>)" }
29
+ },
30
+ create(context) {
31
+ const state = {
32
+ translationStack: 0,
33
+ variableStack: 0,
34
+ imports: {
35
+ translationComponents: /* @__PURE__ */ new Set(),
36
+ variableComponents: /* @__PURE__ */ new Set(),
37
+ namespaceImports: /* @__PURE__ */ new Set(),
38
+ assignedTranslationComponents: /* @__PURE__ */ new Set(),
39
+ assignedVariableComponents: /* @__PURE__ */ new Set()
40
+ }
41
+ };
42
+ function getElementName(node) {
43
+ if (!require_rules_utils.isAstNode(node) || !require_rules_utils.isAstNode(node.openingElement)) return null;
44
+ const name = node.openingElement.name;
45
+ if (!require_rules_utils.isAstNode(name)) return null;
46
+ if (name.type === "JSXIdentifier") return require_rules_utils.getNodeName(name);
47
+ if (name.type === "JSXMemberExpression") {
48
+ const obj = name.object;
49
+ const prop = name.property;
50
+ if (require_rules_utils.isAstNode(obj) && require_rules_utils.isAstNode(prop) && obj.type === "JSXIdentifier" && prop.type === "JSXIdentifier") {
51
+ const objectName = require_rules_utils.getNodeName(obj);
52
+ const propertyName = require_rules_utils.getNodeName(prop);
53
+ return objectName && propertyName ? `${objectName}.${propertyName}` : null;
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ function isNamespaceTranslationComponent(elementName) {
59
+ const parts = elementName.split(".");
60
+ if (parts.length === 2) {
61
+ const [namespace, component] = parts;
62
+ return state.imports.namespaceImports.has(namespace) && isTranslationComponent(component);
63
+ }
64
+ return false;
65
+ }
66
+ function isNamespaceVariableComponent(elementName) {
67
+ const parts = elementName.split(".");
68
+ if (parts.length === 2) {
69
+ const [namespace, component] = parts;
70
+ return state.imports.namespaceImports.has(namespace) && isVariableComponent(component);
71
+ }
72
+ return false;
73
+ }
74
+ function isInsideJSXAttribute(node) {
75
+ if (!require_rules_utils.isAstNode(node)) return false;
76
+ let currentNode = require_rules_utils.isAstNode(node.parent) ? node.parent : null;
77
+ while (currentNode) {
78
+ if (currentNode.type === "JSXAttribute") return true;
79
+ if (currentNode.type === "JSXElement") return false;
80
+ currentNode = require_rules_utils.isAstNode(currentNode.parent) ? currentNode.parent : null;
81
+ }
82
+ return false;
83
+ }
84
+ function isComment(expression) {
85
+ if (!require_rules_utils.isAstNode(expression)) return false;
86
+ return expression.type === "Block" || expression.type === "Line";
87
+ }
88
+ function isEmpty(expression) {
89
+ if (!require_rules_utils.isAstNode(expression)) return false;
90
+ return expression.type === "JSXEmptyExpression";
91
+ }
92
+ return {
93
+ ImportDeclaration(node) {
94
+ if (!require_rules_utils.isAstNode(node) || !require_rules_utils.isAstNode(node.source)) return;
95
+ if (node.source?.type === "Literal" && typeof node.source.value === "string") {
96
+ const source = node.source.value;
97
+ if (require_rules_utils.isGTModule(source)) {
98
+ const specifiers = Array.isArray(node.specifiers) ? node.specifiers : [];
99
+ for (const specifier of specifiers) {
100
+ if (!require_rules_utils.isAstNode(specifier)) continue;
101
+ if (specifier.type === "ImportSpecifier") {
102
+ const importedName = require_rules_utils.getNodeName(specifier.imported) || "";
103
+ const localName = require_rules_utils.getNodeName(specifier.local) || "";
104
+ if (isTranslationComponent(importedName)) state.imports.translationComponents.add(localName);
105
+ else if (isVariableComponent(importedName)) state.imports.variableComponents.add(localName);
106
+ } else if (specifier.type === "ImportNamespaceSpecifier") {
107
+ const localName = require_rules_utils.getNodeName(specifier.local) || "";
108
+ state.imports.namespaceImports.add(localName);
109
+ }
110
+ }
111
+ }
112
+ }
113
+ },
114
+ VariableDeclarator(node) {
115
+ if (require_rules_utils.isAstNode(node) && require_rules_utils.isAstNode(node.id) && require_rules_utils.isAstNode(node.init) && node.id.type === "Identifier" && node.init.type === "Identifier") {
116
+ const varName = require_rules_utils.getNodeName(node.id);
117
+ const assignedFrom = require_rules_utils.getNodeName(node.init);
118
+ if (!varName || !assignedFrom) return;
119
+ if (state.imports.translationComponents.has(assignedFrom)) state.imports.assignedTranslationComponents.add(varName);
120
+ else if (state.imports.variableComponents.has(assignedFrom)) state.imports.assignedVariableComponents.add(varName);
121
+ }
122
+ },
123
+ JSXExpressionContainer(node) {
124
+ if (!require_rules_utils.isAstNode(node)) return;
125
+ if (isInsideJSXAttribute(node)) return;
126
+ if (node.expression && require_rules_utils.isStringLiteral(node.expression) || isComment(node.expression) || isEmpty(node.expression)) return;
127
+ let inTranslationComponent = false;
128
+ let inVariableComponent = false;
129
+ let currentNode = require_rules_utils.isAstNode(node.parent) ? node.parent : null;
130
+ while (currentNode) {
131
+ if (currentNode.type === "JSXElement") {
132
+ const elementName = getElementName(currentNode);
133
+ if (elementName) {
134
+ if (state.imports.variableComponents.has(elementName) || state.imports.assignedVariableComponents.has(elementName) || isNamespaceVariableComponent(elementName)) {
135
+ inVariableComponent = true;
136
+ break;
137
+ } else if (state.imports.translationComponents.has(elementName) || state.imports.assignedTranslationComponents.has(elementName) || isNamespaceTranslationComponent(elementName)) inTranslationComponent = true;
138
+ }
139
+ }
140
+ currentNode = require_rules_utils.isAstNode(currentNode.parent) ? currentNode.parent : null;
141
+ }
142
+ if (inTranslationComponent && !inVariableComponent) context.report({
143
+ node,
144
+ messageId: "dynamicJsx"
145
+ });
146
+ }
147
+ };
148
+ }
208
149
  };
150
+ //#endregion
151
+ exports.noDynamicJsx = noDynamicJsx;
152
+
209
153
  //# sourceMappingURL=no-dynamic-jsx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-dynamic-jsx.js","sourceRoot":"","sources":["../../src/rules/no-dynamic-jsx.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"no-dynamic-jsx.js","names":["isAstNode","getNodeName","isGTModule","isStringLiteral"],"sources":["../../src/rules/no-dynamic-jsx.ts"],"sourcesContent":["/**\n * ESLint rule: no-dynamic-jsx\n *\n * Detects unwrapped dynamic content in GT-Next translation components.\n * Equivalent to the SWC plugin functionality but with proper ESLint error reporting.\n *\n * This rule checks for JSX expressions ({dynamic content}) inside <T> components\n * that are not wrapped in variable components (<Var>, <DateTime>, <Num>, <Currency>).\n */\n\nimport type { Rule } from 'eslint';\nimport { getNodeName, isAstNode, isGTModule, isStringLiteral } from './utils';\n\nconst TRANSLATION_COMPONENTS = ['T'];\nconst VARIABLE_COMPONENTS = ['Var', 'DateTime', 'Num', 'Currency'];\n\nfunction isTranslationComponent(name: string): boolean {\n return TRANSLATION_COMPONENTS.includes(name);\n}\n\nfunction isVariableComponent(name: string): boolean {\n return VARIABLE_COMPONENTS.includes(name);\n}\n\nexport const noDynamicJsx: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Detect unwrapped dynamic content in GT-Next translation components',\n category: 'Best Practices',\n recommended: true,\n url: 'https://github.com/generaltranslation/gt/tree/main/packages/next-lint#no-dynamic-jsx',\n },\n fixable: undefined,\n schema: [],\n messages: {\n dynamicJsx:\n 'Dynamic content in <T> component should be wrapped in a variable component (<Var>, <DateTime>, <Num>, or <Currency>)',\n },\n },\n\n create(context) {\n const state = {\n translationStack: 0,\n variableStack: 0,\n imports: {\n translationComponents: new Set<string>(),\n variableComponents: new Set<string>(),\n namespaceImports: new Set<string>(),\n assignedTranslationComponents: new Set<string>(),\n assignedVariableComponents: new Set<string>(),\n },\n };\n\n function getElementName(node: unknown): string | null {\n if (!isAstNode(node) || !isAstNode(node.openingElement)) return null;\n const name = node.openingElement.name;\n if (!isAstNode(name)) return null;\n\n if (name.type === 'JSXIdentifier') {\n return getNodeName(name);\n }\n\n if (name.type === 'JSXMemberExpression') {\n const obj = name.object;\n const prop = name.property;\n if (\n isAstNode(obj) &&\n isAstNode(prop) &&\n obj.type === 'JSXIdentifier' &&\n prop.type === 'JSXIdentifier'\n ) {\n const objectName = getNodeName(obj);\n const propertyName = getNodeName(prop);\n return objectName && propertyName\n ? `${objectName}.${propertyName}`\n : null;\n }\n }\n\n return null;\n }\n\n function isNamespaceTranslationComponent(elementName: string): boolean {\n const parts = elementName.split('.');\n if (parts.length === 2) {\n const [namespace, component] = parts;\n return (\n state.imports.namespaceImports.has(namespace) &&\n isTranslationComponent(component)\n );\n }\n return false;\n }\n\n function isNamespaceVariableComponent(elementName: string): boolean {\n const parts = elementName.split('.');\n if (parts.length === 2) {\n const [namespace, component] = parts;\n return (\n state.imports.namespaceImports.has(namespace) &&\n isVariableComponent(component)\n );\n }\n return false;\n }\n\n function isInsideJSXAttribute(node: unknown): boolean {\n if (!isAstNode(node)) return false;\n // Walk up the AST to check if this expression is inside a JSX attribute\n let currentNode = isAstNode(node.parent) ? node.parent : null;\n while (currentNode) {\n if (currentNode.type === 'JSXAttribute') {\n return true;\n }\n // If we reach a JSX element, we're in element content, not attributes\n if (currentNode.type === 'JSXElement') {\n return false;\n }\n currentNode = isAstNode(currentNode.parent) ? currentNode.parent : null;\n }\n return false;\n }\n\n // Check if the node is a comment\n function isComment(expression: unknown): boolean {\n if (!isAstNode(expression)) return false;\n return expression.type === 'Block' || expression.type === 'Line';\n }\n\n // Check if empty\n function isEmpty(expression: unknown): boolean {\n if (!isAstNode(expression)) return false;\n return expression.type === 'JSXEmptyExpression';\n }\n\n return {\n // Track imports from GT-Next modules\n ImportDeclaration(node: unknown) {\n if (!isAstNode(node) || !isAstNode(node.source)) return;\n if (\n node.source?.type === 'Literal' &&\n typeof node.source.value === 'string'\n ) {\n const source = node.source.value;\n\n if (isGTModule(source)) {\n const specifiers = Array.isArray(node.specifiers)\n ? node.specifiers\n : [];\n for (const specifier of specifiers) {\n if (!isAstNode(specifier)) continue;\n if (specifier.type === 'ImportSpecifier') {\n const importedName = getNodeName(specifier.imported) || '';\n const localName = getNodeName(specifier.local) || '';\n\n if (isTranslationComponent(importedName)) {\n state.imports.translationComponents.add(localName);\n } else if (isVariableComponent(importedName)) {\n state.imports.variableComponents.add(localName);\n }\n } else if (specifier.type === 'ImportNamespaceSpecifier') {\n const localName = getNodeName(specifier.local) || '';\n state.imports.namespaceImports.add(localName);\n }\n }\n }\n }\n },\n\n // Track variable assignments from GT components\n VariableDeclarator(node: unknown) {\n if (\n isAstNode(node) &&\n isAstNode(node.id) &&\n isAstNode(node.init) &&\n node.id.type === 'Identifier' &&\n node.init.type === 'Identifier'\n ) {\n const varName = getNodeName(node.id);\n const assignedFrom = getNodeName(node.init);\n if (!varName || !assignedFrom) return;\n\n if (state.imports.translationComponents.has(assignedFrom)) {\n state.imports.assignedTranslationComponents.add(varName);\n } else if (state.imports.variableComponents.has(assignedFrom)) {\n state.imports.assignedVariableComponents.add(varName);\n }\n }\n },\n\n // Detect unwrapped dynamic content\n JSXExpressionContainer(node: unknown) {\n if (!isAstNode(node)) return;\n // Skip expressions inside JSX attributes (e.g., <Image width={16} />)\n if (isInsideJSXAttribute(node)) {\n return;\n }\n\n // Skip expressions with just a string literal (e.g., {'Hello'})\n // Skip expressions with just a comment\n // Skip expressions with just an empty statement\n if (\n (node.expression && isStringLiteral(node.expression)) ||\n isComment(node.expression) ||\n isEmpty(node.expression)\n ) {\n return;\n }\n\n // Check if this expression is inside a translation component but not inside a variable component\n let inTranslationComponent = false;\n let inVariableComponent = false;\n\n // Walk up the AST to find parent JSX elements\n let currentNode = isAstNode(node.parent) ? node.parent : null;\n while (currentNode) {\n if (currentNode.type === 'JSXElement') {\n const elementName = getElementName(currentNode);\n if (elementName) {\n // Check if this is a variable component\n if (\n state.imports.variableComponents.has(elementName) ||\n state.imports.assignedVariableComponents.has(elementName) ||\n isNamespaceVariableComponent(elementName)\n ) {\n inVariableComponent = true;\n break; // If we find a variable component, we don't need to check further\n }\n // Check if this is a translation component\n else if (\n state.imports.translationComponents.has(elementName) ||\n state.imports.assignedTranslationComponents.has(elementName) ||\n isNamespaceTranslationComponent(elementName)\n ) {\n inTranslationComponent = true;\n }\n }\n }\n currentNode = isAstNode(currentNode.parent)\n ? currentNode.parent\n : null;\n }\n\n // Report if we're inside a translation component but not inside a variable component\n if (inTranslationComponent && !inVariableComponent) {\n context.report({\n node: node as never,\n messageId: 'dynamicJsx',\n });\n }\n },\n };\n },\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"no-dynamic-string.d.ts","sourceRoot":"","sources":["../../src/rules/no-dynamic-string.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAkBnC,eAAO,MAAM,eAAe,EAAE,IAAI,CAAC,UA8LlC,CAAC"}
1
+ {"version":3,"file":"no-dynamic-string.d.ts","sourceRoot":"","sources":["../../src/rules/no-dynamic-string.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAcnC,eAAO,MAAM,eAAe,EAAE,IAAI,CAAC,UA6NlC,CAAC"}
@@ -1,186 +1,140 @@
1
- "use strict";
2
- /**
3
- * ESLint rule: no-dynamic-string
4
- *
5
- * Ensures translation functions (t, useGT, getGT) only accept string literals
6
- * as their first argument. Dynamic content like template literals or string
7
- * concatenation is prohibited to ensure consistent translation keys.
8
- */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.noDynamicString = void 0;
11
- const GT_MODULES = ['gt-next', 'gt-next/client', 'gt-next/server'];
12
- const TRANSLATION_FUNCTIONS = ['useGT', 'getGT'];
13
- function isGTModule(source) {
14
- return GT_MODULES.includes(source);
15
- }
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_rules_utils = require("./utils.js");
3
+ //#region src/rules/no-dynamic-string.ts
4
+ const TRANSLATION_FUNCTIONS = ["useGT", "getGT"];
16
5
  function isTranslationFunction(name) {
17
- return TRANSLATION_FUNCTIONS.includes(name);
6
+ return TRANSLATION_FUNCTIONS.includes(name);
18
7
  }
19
- exports.noDynamicString = {
20
- meta: {
21
- type: 'problem',
22
- docs: {
23
- description: 'Translation functions must use string literals as the first argument',
24
- category: 'Best Practices',
25
- recommended: true,
26
- url: 'https://github.com/generaltranslation/gt/tree/main/packages/next-lint#no-dynamic-string',
27
- },
28
- fixable: undefined,
29
- schema: [],
30
- messages: {
31
- dynamicString: "Translation function must use a constant string literal as the first argument. Use t('Hello, {name}!', { name: value }) instead of template literals or string concatenation.",
32
- },
33
- },
34
- create(context) {
35
- // Track imported GT functions and their aliases
36
- const trackedFunctions = new Map();
37
- // Track variables assigned from translation function calls
38
- const translationVariables = new Set();
39
- function trackImport(localName, importedName, source) {
40
- if (isGTModule(source) && isTranslationFunction(importedName)) {
41
- trackedFunctions.set(localName, {
42
- name: importedName,
43
- isTranslationFunction: true,
44
- });
45
- }
46
- }
47
- function trackNamespaceImport(localName, source) {
48
- if (isGTModule(source)) {
49
- trackedFunctions.set(localName, {
50
- name: localName,
51
- isTranslationFunction: false, // It's a namespace, not directly callable
52
- });
53
- }
54
- }
55
- function isStringLiteral(node) {
56
- return ((node.type === 'Literal' && typeof node.value === 'string') ||
57
- (node.type === 'TemplateLiteral' && node.expressions.length === 0) // Template literal with no interpolation
58
- );
59
- }
60
- function validateTranslationCall(node) {
61
- const firstArg = node.arguments[0];
62
- if (!firstArg)
63
- return; // No arguments
64
- if (!isStringLiteral(firstArg)) {
65
- context.report({
66
- node: firstArg,
67
- messageId: 'dynamicString',
68
- });
69
- }
70
- }
71
- function handleCallExpression(node) {
72
- if (node.callee.type === 'Identifier') {
73
- // Direct function calls: t(), useGT(), etc.
74
- const functionName = node.callee.name;
75
- if (trackedFunctions.has(functionName)) {
76
- const tracked = trackedFunctions.get(functionName);
77
- if (tracked.isTranslationFunction) {
78
- validateTranslationCall(node);
79
- }
80
- }
81
- else if (translationVariables.has(functionName)) {
82
- // Variable assigned from translation function
83
- validateTranslationCall(node);
84
- }
85
- }
86
- else if (node.callee.type === 'MemberExpression') {
87
- // Member expressions: GT.tx(), namespace.function()
88
- const objectName = node.callee.object.name;
89
- const propertyName = node.callee.property.name;
90
- if (trackedFunctions.has(objectName) &&
91
- isTranslationFunction(propertyName)) {
92
- validateTranslationCall(node);
93
- }
94
- }
95
- }
96
- function handleAssignment(node) {
97
- // Track variables assigned from translation function calls
98
- if (node.type === 'VariableDeclarator' &&
99
- node.id.type === 'Identifier' &&
100
- node.init) {
101
- if (node.init.type === 'CallExpression') {
102
- const callExpression = node.init;
103
- if (callExpression.callee.type === 'Identifier') {
104
- const functionName = callExpression.callee.name;
105
- if (trackedFunctions.has(functionName)) {
106
- const tracked = trackedFunctions.get(functionName);
107
- if (tracked.isTranslationFunction) {
108
- // This variable now holds a translation function
109
- translationVariables.add(node.id.name);
110
- }
111
- }
112
- }
113
- else if (callExpression.callee.type === 'MemberExpression') {
114
- // Handle namespace calls like: const t = GT.useGT();
115
- const objectName = callExpression.callee.object.name;
116
- const propertyName = callExpression.callee.property.name;
117
- if (trackedFunctions.has(objectName) &&
118
- isTranslationFunction(propertyName)) {
119
- // This variable now holds a translation function
120
- translationVariables.add(node.id.name);
121
- }
122
- }
123
- }
124
- else if (node.init.type === 'AwaitExpression' &&
125
- node.init.argument.type === 'CallExpression') {
126
- // Handle await getGT() case
127
- const callExpression = node.init.argument;
128
- if (callExpression.callee.type === 'Identifier') {
129
- const functionName = callExpression.callee.name;
130
- if (trackedFunctions.has(functionName)) {
131
- const tracked = trackedFunctions.get(functionName);
132
- if (tracked.isTranslationFunction) {
133
- // This variable now holds a translation function (from awaited promise)
134
- translationVariables.add(node.id.name);
135
- }
136
- }
137
- }
138
- else if (callExpression.callee.type === 'MemberExpression') {
139
- // Handle namespace calls like: const t = await GT.getGT();
140
- const objectName = callExpression.callee.object.name;
141
- const propertyName = callExpression.callee.property.name;
142
- if (trackedFunctions.has(objectName) &&
143
- isTranslationFunction(propertyName)) {
144
- // This variable now holds a translation function (from awaited promise)
145
- translationVariables.add(node.id.name);
146
- }
147
- }
148
- }
149
- else if (node.init.type === 'Identifier') {
150
- // Handle reassignment: const t = getTranslation;
151
- const assignedFrom = node.init.name;
152
- if (translationVariables.has(assignedFrom)) {
153
- translationVariables.add(node.id.name);
154
- }
155
- }
156
- }
157
- }
158
- return {
159
- ImportDeclaration(node) {
160
- const source = node.source.value;
161
- if (!isGTModule(source))
162
- return;
163
- for (const specifier of node.specifiers) {
164
- if (specifier.type === 'ImportSpecifier') {
165
- // import { useGT, tx as serverTx } from 'gt-next'
166
- const importedName = specifier.imported.name;
167
- const localName = specifier.local.name;
168
- trackImport(localName, importedName, source);
169
- }
170
- else if (specifier.type === 'ImportNamespaceSpecifier') {
171
- // import * as GT from 'gt-next'
172
- const localName = specifier.local.name;
173
- trackNamespaceImport(localName, source);
174
- }
175
- }
176
- },
177
- VariableDeclarator(node) {
178
- handleAssignment(node);
179
- },
180
- CallExpression(node) {
181
- handleCallExpression(node);
182
- },
183
- };
184
- },
8
+ const noDynamicString = {
9
+ meta: {
10
+ type: "problem",
11
+ docs: {
12
+ description: "Translation functions must use string literals as the first argument",
13
+ category: "Best Practices",
14
+ recommended: true,
15
+ url: "https://github.com/generaltranslation/gt/tree/main/packages/next-lint#no-dynamic-string"
16
+ },
17
+ fixable: void 0,
18
+ schema: [],
19
+ messages: { dynamicString: "Translation function must use a constant string literal as the first argument. Use t('Hello, {name}!', { name: value }) instead of template literals or string concatenation." }
20
+ },
21
+ create(context) {
22
+ const trackedFunctions = /* @__PURE__ */ new Map();
23
+ const translationVariables = /* @__PURE__ */ new Set();
24
+ function trackImport(localName, importedName, source) {
25
+ if (require_rules_utils.isGTModule(source) && isTranslationFunction(importedName)) trackedFunctions.set(localName, {
26
+ name: importedName,
27
+ isTranslationFunction: true
28
+ });
29
+ }
30
+ function trackNamespaceImport(localName, source) {
31
+ if (require_rules_utils.isGTModule(source)) trackedFunctions.set(localName, {
32
+ name: localName,
33
+ isTranslationFunction: false
34
+ });
35
+ }
36
+ function validateTranslationCall(node) {
37
+ if (!require_rules_utils.isAstNode(node) || !Array.isArray(node.arguments)) return;
38
+ const firstArg = node.arguments[0];
39
+ if (!firstArg) return;
40
+ if (!require_rules_utils.isStringLiteral(firstArg)) context.report({
41
+ node: firstArg,
42
+ messageId: "dynamicString"
43
+ });
44
+ }
45
+ function handleCallExpression(node) {
46
+ if (!require_rules_utils.isAstNode(node) || !require_rules_utils.isAstNode(node.callee)) return;
47
+ if (node.callee.type === "Identifier") {
48
+ const functionName = require_rules_utils.getNodeName(node.callee);
49
+ if (!functionName) return;
50
+ if (trackedFunctions.has(functionName)) {
51
+ if (trackedFunctions.get(functionName).isTranslationFunction) validateTranslationCall(node);
52
+ } else if (translationVariables.has(functionName)) validateTranslationCall(node);
53
+ } else if (node.callee.type === "MemberExpression") {
54
+ const objectName = require_rules_utils.getNodeName(node.callee.object);
55
+ const propertyName = require_rules_utils.getNodeName(node.callee.property);
56
+ if (!objectName || !propertyName) return;
57
+ if (trackedFunctions.has(objectName) && isTranslationFunction(propertyName)) validateTranslationCall(node);
58
+ }
59
+ }
60
+ function handleAssignment(node) {
61
+ if (require_rules_utils.isAstNode(node) && node.type === "VariableDeclarator" && require_rules_utils.isAstNode(node.id) && node.id.type === "Identifier" && require_rules_utils.isAstNode(node.init)) {
62
+ if (node.init.type === "CallExpression") {
63
+ const callExpression = node.init;
64
+ if (require_rules_utils.isAstNode(callExpression.callee) && callExpression.callee.type === "Identifier") {
65
+ const functionName = require_rules_utils.getNodeName(callExpression.callee);
66
+ if (!functionName) return;
67
+ if (trackedFunctions.has(functionName)) {
68
+ if (trackedFunctions.get(functionName).isTranslationFunction) {
69
+ const variableName = require_rules_utils.getNodeName(node.id);
70
+ if (variableName) translationVariables.add(variableName);
71
+ }
72
+ }
73
+ } else if (require_rules_utils.isAstNode(callExpression.callee) && callExpression.callee.type === "MemberExpression") {
74
+ const objectName = require_rules_utils.getNodeName(callExpression.callee.object);
75
+ const propertyName = require_rules_utils.getNodeName(callExpression.callee.property);
76
+ if (objectName && propertyName && trackedFunctions.has(objectName) && isTranslationFunction(propertyName)) {
77
+ const variableName = require_rules_utils.getNodeName(node.id);
78
+ if (variableName) translationVariables.add(variableName);
79
+ }
80
+ }
81
+ } else if (node.init.type === "AwaitExpression" && require_rules_utils.isAstNode(node.init.argument) && node.init.argument.type === "CallExpression") {
82
+ const callExpression = node.init.argument;
83
+ if (require_rules_utils.isAstNode(callExpression.callee) && callExpression.callee.type === "Identifier") {
84
+ const functionName = require_rules_utils.getNodeName(callExpression.callee);
85
+ if (!functionName) return;
86
+ if (trackedFunctions.has(functionName)) {
87
+ if (trackedFunctions.get(functionName).isTranslationFunction) {
88
+ const variableName = require_rules_utils.getNodeName(node.id);
89
+ if (variableName) translationVariables.add(variableName);
90
+ }
91
+ }
92
+ } else if (require_rules_utils.isAstNode(callExpression.callee) && callExpression.callee.type === "MemberExpression") {
93
+ const objectName = require_rules_utils.getNodeName(callExpression.callee.object);
94
+ const propertyName = require_rules_utils.getNodeName(callExpression.callee.property);
95
+ if (objectName && propertyName && trackedFunctions.has(objectName) && isTranslationFunction(propertyName)) {
96
+ const variableName = require_rules_utils.getNodeName(node.id);
97
+ if (variableName) translationVariables.add(variableName);
98
+ }
99
+ }
100
+ } else if (node.init.type === "Identifier") {
101
+ const assignedFrom = require_rules_utils.getNodeName(node.init);
102
+ if (assignedFrom && translationVariables.has(assignedFrom)) {
103
+ const variableName = require_rules_utils.getNodeName(node.id);
104
+ if (variableName) translationVariables.add(variableName);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ return {
110
+ ImportDeclaration(node) {
111
+ if (!require_rules_utils.isAstNode(node) || !require_rules_utils.isAstNode(node.source)) return;
112
+ const source = node.source.value;
113
+ if (typeof source !== "string") return;
114
+ if (!require_rules_utils.isGTModule(source)) return;
115
+ const specifiers = Array.isArray(node.specifiers) ? node.specifiers : [];
116
+ for (const specifier of specifiers) {
117
+ if (!require_rules_utils.isAstNode(specifier)) continue;
118
+ if (specifier.type === "ImportSpecifier") {
119
+ const importedName = require_rules_utils.getNodeName(specifier.imported);
120
+ const localName = require_rules_utils.getNodeName(specifier.local);
121
+ if (importedName && localName) trackImport(localName, importedName, source);
122
+ } else if (specifier.type === "ImportNamespaceSpecifier") {
123
+ const localName = require_rules_utils.getNodeName(specifier.local);
124
+ if (localName) trackNamespaceImport(localName, source);
125
+ }
126
+ }
127
+ },
128
+ VariableDeclarator(node) {
129
+ handleAssignment(node);
130
+ },
131
+ CallExpression(node) {
132
+ handleCallExpression(node);
133
+ }
134
+ };
135
+ }
185
136
  };
137
+ //#endregion
138
+ exports.noDynamicString = noDynamicString;
139
+
186
140
  //# sourceMappingURL=no-dynamic-string.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-dynamic-string.js","sourceRoot":"","sources":["../../src/rules/no-dynamic-string.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"no-dynamic-string.js","names":["isGTModule","isAstNode","isStringLiteral","getNodeName"],"sources":["../../src/rules/no-dynamic-string.ts"],"sourcesContent":["/**\n * ESLint rule: no-dynamic-string\n *\n * Ensures translation functions (t, useGT, getGT) only accept string literals\n * as their first argument. Dynamic content like template literals or string\n * concatenation is prohibited to ensure consistent translation keys.\n */\n\nimport type { Rule } from 'eslint';\nimport { getNodeName, isAstNode, isGTModule, isStringLiteral } from './utils';\n\nconst TRANSLATION_FUNCTIONS = ['useGT', 'getGT'];\n\ninterface TrackedFunction {\n name: string;\n isTranslationFunction: boolean;\n}\n\nfunction isTranslationFunction(name: string): boolean {\n return TRANSLATION_FUNCTIONS.includes(name);\n}\n\nexport const noDynamicString: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Translation functions must use string literals as the first argument',\n category: 'Best Practices',\n recommended: true,\n url: 'https://github.com/generaltranslation/gt/tree/main/packages/next-lint#no-dynamic-string',\n },\n fixable: undefined,\n schema: [],\n messages: {\n dynamicString:\n \"Translation function must use a constant string literal as the first argument. Use t('Hello, {name}!', { name: value }) instead of template literals or string concatenation.\",\n },\n },\n\n create(context) {\n // Track imported GT functions and their aliases\n const trackedFunctions = new Map<string, TrackedFunction>();\n // Track variables assigned from translation function calls\n const translationVariables = new Set<string>();\n\n function trackImport(\n localName: string,\n importedName: string,\n source: string\n ) {\n if (isGTModule(source) && isTranslationFunction(importedName)) {\n trackedFunctions.set(localName, {\n name: importedName,\n isTranslationFunction: true,\n });\n }\n }\n\n function trackNamespaceImport(localName: string, source: string) {\n if (isGTModule(source)) {\n trackedFunctions.set(localName, {\n name: localName,\n isTranslationFunction: false, // It's a namespace, not directly callable\n });\n }\n }\n\n function validateTranslationCall(node: unknown) {\n if (!isAstNode(node) || !Array.isArray(node.arguments)) return;\n const firstArg = node.arguments[0];\n if (!firstArg) return; // No arguments\n\n if (!isStringLiteral(firstArg)) {\n context.report({\n node: firstArg as never,\n messageId: 'dynamicString',\n });\n }\n }\n\n function handleCallExpression(node: unknown) {\n if (!isAstNode(node) || !isAstNode(node.callee)) return;\n if (node.callee.type === 'Identifier') {\n // Direct function calls: t(), useGT(), etc.\n const functionName = getNodeName(node.callee);\n if (!functionName) return;\n\n if (trackedFunctions.has(functionName)) {\n const tracked = trackedFunctions.get(functionName)!;\n if (tracked.isTranslationFunction) {\n validateTranslationCall(node);\n }\n } else if (translationVariables.has(functionName)) {\n // Variable assigned from translation function\n validateTranslationCall(node);\n }\n } else if (node.callee.type === 'MemberExpression') {\n // Member expressions: GT.tx(), namespace.function()\n const objectName = getNodeName(node.callee.object);\n const propertyName = getNodeName(node.callee.property);\n if (!objectName || !propertyName) return;\n\n if (\n trackedFunctions.has(objectName) &&\n isTranslationFunction(propertyName)\n ) {\n validateTranslationCall(node);\n }\n }\n }\n\n function handleAssignment(node: unknown) {\n // Track variables assigned from translation function calls\n if (\n isAstNode(node) &&\n node.type === 'VariableDeclarator' &&\n isAstNode(node.id) &&\n node.id.type === 'Identifier' &&\n isAstNode(node.init)\n ) {\n if (node.init.type === 'CallExpression') {\n const callExpression = node.init;\n\n if (\n isAstNode(callExpression.callee) &&\n callExpression.callee.type === 'Identifier'\n ) {\n const functionName = getNodeName(callExpression.callee);\n if (!functionName) return;\n if (trackedFunctions.has(functionName)) {\n const tracked = trackedFunctions.get(functionName)!;\n if (tracked.isTranslationFunction) {\n // This variable now holds a translation function\n const variableName = getNodeName(node.id);\n if (variableName) translationVariables.add(variableName);\n }\n }\n } else if (\n isAstNode(callExpression.callee) &&\n callExpression.callee.type === 'MemberExpression'\n ) {\n // Handle namespace calls like: const t = GT.useGT();\n const objectName = getNodeName(callExpression.callee.object);\n const propertyName = getNodeName(callExpression.callee.property);\n if (\n objectName &&\n propertyName &&\n trackedFunctions.has(objectName) &&\n isTranslationFunction(propertyName)\n ) {\n // This variable now holds a translation function\n const variableName = getNodeName(node.id);\n if (variableName) translationVariables.add(variableName);\n }\n }\n } else if (\n node.init.type === 'AwaitExpression' &&\n isAstNode(node.init.argument) &&\n node.init.argument.type === 'CallExpression'\n ) {\n // Handle await getGT() case\n const callExpression = node.init.argument;\n\n if (\n isAstNode(callExpression.callee) &&\n callExpression.callee.type === 'Identifier'\n ) {\n const functionName = getNodeName(callExpression.callee);\n if (!functionName) return;\n if (trackedFunctions.has(functionName)) {\n const tracked = trackedFunctions.get(functionName)!;\n if (tracked.isTranslationFunction) {\n // This variable now holds a translation function (from awaited promise)\n const variableName = getNodeName(node.id);\n if (variableName) translationVariables.add(variableName);\n }\n }\n } else if (\n isAstNode(callExpression.callee) &&\n callExpression.callee.type === 'MemberExpression'\n ) {\n // Handle namespace calls like: const t = await GT.getGT();\n const objectName = getNodeName(callExpression.callee.object);\n const propertyName = getNodeName(callExpression.callee.property);\n if (\n objectName &&\n propertyName &&\n trackedFunctions.has(objectName) &&\n isTranslationFunction(propertyName)\n ) {\n // This variable now holds a translation function (from awaited promise)\n const variableName = getNodeName(node.id);\n if (variableName) translationVariables.add(variableName);\n }\n }\n } else if (node.init.type === 'Identifier') {\n // Handle reassignment: const t = getTranslation;\n const assignedFrom = getNodeName(node.init);\n if (assignedFrom && translationVariables.has(assignedFrom)) {\n const variableName = getNodeName(node.id);\n if (variableName) translationVariables.add(variableName);\n }\n }\n }\n }\n\n return {\n ImportDeclaration(node: unknown) {\n if (!isAstNode(node) || !isAstNode(node.source)) return;\n const source = node.source.value;\n if (typeof source !== 'string') return;\n if (!isGTModule(source)) return;\n\n const specifiers = Array.isArray(node.specifiers)\n ? node.specifiers\n : [];\n for (const specifier of specifiers) {\n if (!isAstNode(specifier)) continue;\n if (specifier.type === 'ImportSpecifier') {\n // import { useGT, tx as serverTx } from 'gt-next'\n const importedName = getNodeName(specifier.imported);\n const localName = getNodeName(specifier.local);\n if (importedName && localName) {\n trackImport(localName, importedName, source);\n }\n } else if (specifier.type === 'ImportNamespaceSpecifier') {\n // import * as GT from 'gt-next'\n const localName = getNodeName(specifier.local);\n if (localName) trackNamespaceImport(localName, source);\n }\n }\n },\n\n VariableDeclarator(node: unknown) {\n handleAssignment(node);\n },\n\n CallExpression(node: unknown) {\n handleCallExpression(node);\n },\n };\n },\n};\n"],"mappings":";;;AAWA,MAAM,wBAAwB,CAAC,SAAS,QAAQ;AAOhD,SAAS,sBAAsB,MAAuB;AACpD,QAAO,sBAAsB,SAAS,KAAK;;AAG7C,MAAa,kBAAmC;CAC9C,MAAM;EACJ,MAAM;EACN,MAAM;GACJ,aACE;GACF,UAAU;GACV,aAAa;GACb,KAAK;GACN;EACD,SAAS,KAAA;EACT,QAAQ,EAAE;EACV,UAAU,EACR,eACE,iLACH;EACF;CAED,OAAO,SAAS;EAEd,MAAM,mCAAmB,IAAI,KAA8B;EAE3D,MAAM,uCAAuB,IAAI,KAAa;EAE9C,SAAS,YACP,WACA,cACA,QACA;AACA,OAAIA,oBAAAA,WAAW,OAAO,IAAI,sBAAsB,aAAa,CAC3D,kBAAiB,IAAI,WAAW;IAC9B,MAAM;IACN,uBAAuB;IACxB,CAAC;;EAIN,SAAS,qBAAqB,WAAmB,QAAgB;AAC/D,OAAIA,oBAAAA,WAAW,OAAO,CACpB,kBAAiB,IAAI,WAAW;IAC9B,MAAM;IACN,uBAAuB;IACxB,CAAC;;EAIN,SAAS,wBAAwB,MAAe;AAC9C,OAAI,CAACC,oBAAAA,UAAU,KAAK,IAAI,CAAC,MAAM,QAAQ,KAAK,UAAU,CAAE;GACxD,MAAM,WAAW,KAAK,UAAU;AAChC,OAAI,CAAC,SAAU;AAEf,OAAI,CAACC,oBAAAA,gBAAgB,SAAS,CAC5B,SAAQ,OAAO;IACb,MAAM;IACN,WAAW;IACZ,CAAC;;EAIN,SAAS,qBAAqB,MAAe;AAC3C,OAAI,CAACD,oBAAAA,UAAU,KAAK,IAAI,CAACA,oBAAAA,UAAU,KAAK,OAAO,CAAE;AACjD,OAAI,KAAK,OAAO,SAAS,cAAc;IAErC,MAAM,eAAeE,oBAAAA,YAAY,KAAK,OAAO;AAC7C,QAAI,CAAC,aAAc;AAEnB,QAAI,iBAAiB,IAAI,aAAa;SACpB,iBAAiB,IAAI,aAC1B,CAAC,sBACV,yBAAwB,KAAK;eAEtB,qBAAqB,IAAI,aAAa,CAE/C,yBAAwB,KAAK;cAEtB,KAAK,OAAO,SAAS,oBAAoB;IAElD,MAAM,aAAaA,oBAAAA,YAAY,KAAK,OAAO,OAAO;IAClD,MAAM,eAAeA,oBAAAA,YAAY,KAAK,OAAO,SAAS;AACtD,QAAI,CAAC,cAAc,CAAC,aAAc;AAElC,QACE,iBAAiB,IAAI,WAAW,IAChC,sBAAsB,aAAa,CAEnC,yBAAwB,KAAK;;;EAKnC,SAAS,iBAAiB,MAAe;AAEvC,OACEF,oBAAAA,UAAU,KAAK,IACf,KAAK,SAAS,wBACdA,oBAAAA,UAAU,KAAK,GAAG,IAClB,KAAK,GAAG,SAAS,gBACjBA,oBAAAA,UAAU,KAAK,KAAK;QAEhB,KAAK,KAAK,SAAS,kBAAkB;KACvC,MAAM,iBAAiB,KAAK;AAE5B,SACEA,oBAAAA,UAAU,eAAe,OAAO,IAChC,eAAe,OAAO,SAAS,cAC/B;MACA,MAAM,eAAeE,oBAAAA,YAAY,eAAe,OAAO;AACvD,UAAI,CAAC,aAAc;AACnB,UAAI,iBAAiB,IAAI,aAAa;WACpB,iBAAiB,IAAI,aAC1B,CAAC,uBAAuB;QAEjC,MAAM,eAAeA,oBAAAA,YAAY,KAAK,GAAG;AACzC,YAAI,aAAc,sBAAqB,IAAI,aAAa;;;gBAI5DF,oBAAAA,UAAU,eAAe,OAAO,IAChC,eAAe,OAAO,SAAS,oBAC/B;MAEA,MAAM,aAAaE,oBAAAA,YAAY,eAAe,OAAO,OAAO;MAC5D,MAAM,eAAeA,oBAAAA,YAAY,eAAe,OAAO,SAAS;AAChE,UACE,cACA,gBACA,iBAAiB,IAAI,WAAW,IAChC,sBAAsB,aAAa,EACnC;OAEA,MAAM,eAAeA,oBAAAA,YAAY,KAAK,GAAG;AACzC,WAAI,aAAc,sBAAqB,IAAI,aAAa;;;eAI5D,KAAK,KAAK,SAAS,qBACnBF,oBAAAA,UAAU,KAAK,KAAK,SAAS,IAC7B,KAAK,KAAK,SAAS,SAAS,kBAC5B;KAEA,MAAM,iBAAiB,KAAK,KAAK;AAEjC,SACEA,oBAAAA,UAAU,eAAe,OAAO,IAChC,eAAe,OAAO,SAAS,cAC/B;MACA,MAAM,eAAeE,oBAAAA,YAAY,eAAe,OAAO;AACvD,UAAI,CAAC,aAAc;AACnB,UAAI,iBAAiB,IAAI,aAAa;WACpB,iBAAiB,IAAI,aAC1B,CAAC,uBAAuB;QAEjC,MAAM,eAAeA,oBAAAA,YAAY,KAAK,GAAG;AACzC,YAAI,aAAc,sBAAqB,IAAI,aAAa;;;gBAI5DF,oBAAAA,UAAU,eAAe,OAAO,IAChC,eAAe,OAAO,SAAS,oBAC/B;MAEA,MAAM,aAAaE,oBAAAA,YAAY,eAAe,OAAO,OAAO;MAC5D,MAAM,eAAeA,oBAAAA,YAAY,eAAe,OAAO,SAAS;AAChE,UACE,cACA,gBACA,iBAAiB,IAAI,WAAW,IAChC,sBAAsB,aAAa,EACnC;OAEA,MAAM,eAAeA,oBAAAA,YAAY,KAAK,GAAG;AACzC,WAAI,aAAc,sBAAqB,IAAI,aAAa;;;eAGnD,KAAK,KAAK,SAAS,cAAc;KAE1C,MAAM,eAAeA,oBAAAA,YAAY,KAAK,KAAK;AAC3C,SAAI,gBAAgB,qBAAqB,IAAI,aAAa,EAAE;MAC1D,MAAM,eAAeA,oBAAAA,YAAY,KAAK,GAAG;AACzC,UAAI,aAAc,sBAAqB,IAAI,aAAa;;;;;AAMhE,SAAO;GACL,kBAAkB,MAAe;AAC/B,QAAI,CAACF,oBAAAA,UAAU,KAAK,IAAI,CAACA,oBAAAA,UAAU,KAAK,OAAO,CAAE;IACjD,MAAM,SAAS,KAAK,OAAO;AAC3B,QAAI,OAAO,WAAW,SAAU;AAChC,QAAI,CAACD,oBAAAA,WAAW,OAAO,CAAE;IAEzB,MAAM,aAAa,MAAM,QAAQ,KAAK,WAAW,GAC7C,KAAK,aACL,EAAE;AACN,SAAK,MAAM,aAAa,YAAY;AAClC,SAAI,CAACC,oBAAAA,UAAU,UAAU,CAAE;AAC3B,SAAI,UAAU,SAAS,mBAAmB;MAExC,MAAM,eAAeE,oBAAAA,YAAY,UAAU,SAAS;MACpD,MAAM,YAAYA,oBAAAA,YAAY,UAAU,MAAM;AAC9C,UAAI,gBAAgB,UAClB,aAAY,WAAW,cAAc,OAAO;gBAErC,UAAU,SAAS,4BAA4B;MAExD,MAAM,YAAYA,oBAAAA,YAAY,UAAU,MAAM;AAC9C,UAAI,UAAW,sBAAqB,WAAW,OAAO;;;;GAK5D,mBAAmB,MAAe;AAChC,qBAAiB,KAAK;;GAGxB,eAAe,MAAe;AAC5B,yBAAqB,KAAK;;GAE7B;;CAEJ"}
@@ -0,0 +1,9 @@
1
+ export type AstNode = {
2
+ type: string;
3
+ [key: string]: unknown;
4
+ };
5
+ export declare function isAstNode(value: unknown): value is AstNode;
6
+ export declare function getNodeName(value: unknown): string | null;
7
+ export declare function isGTModule(source: string): boolean;
8
+ export declare function isStringLiteral(node: unknown): boolean;
9
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/rules/utils.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAE1D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEzD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAQtD"}
@@ -0,0 +1,27 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/rules/utils.ts
3
+ const GT_MODULES = [
4
+ "gt-next",
5
+ "gt-next/client",
6
+ "gt-next/server"
7
+ ];
8
+ function isAstNode(value) {
9
+ return typeof value === "object" && value !== null && "type" in value;
10
+ }
11
+ function getNodeName(value) {
12
+ return isAstNode(value) && typeof value.name === "string" ? value.name : null;
13
+ }
14
+ function isGTModule(source) {
15
+ return GT_MODULES.includes(source);
16
+ }
17
+ function isStringLiteral(node) {
18
+ if (!isAstNode(node)) return false;
19
+ return node.type === "Literal" && typeof node.value === "string" || node.type === "TemplateLiteral" && Array.isArray(node.expressions) && node.expressions.length === 0;
20
+ }
21
+ //#endregion
22
+ exports.getNodeName = getNodeName;
23
+ exports.isAstNode = isAstNode;
24
+ exports.isGTModule = isGTModule;
25
+ exports.isStringLiteral = isStringLiteral;
26
+
27
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../../src/rules/utils.ts"],"sourcesContent":["const GT_MODULES = ['gt-next', 'gt-next/client', 'gt-next/server'];\n\nexport type AstNode = {\n type: string;\n [key: string]: unknown;\n};\n\nexport function isAstNode(value: unknown): value is AstNode {\n return typeof value === 'object' && value !== null && 'type' in value;\n}\n\nexport function getNodeName(value: unknown): string | null {\n return isAstNode(value) && typeof value.name === 'string' ? value.name : null;\n}\n\nexport function isGTModule(source: string): boolean {\n return GT_MODULES.includes(source);\n}\n\nexport function isStringLiteral(node: unknown): boolean {\n if (!isAstNode(node)) return false;\n return (\n (node.type === 'Literal' && typeof node.value === 'string') ||\n (node.type === 'TemplateLiteral' &&\n Array.isArray(node.expressions) &&\n node.expressions.length === 0)\n );\n}\n"],"mappings":";;AAAA,MAAM,aAAa;CAAC;CAAW;CAAkB;CAAiB;AAOlE,SAAgB,UAAU,OAAkC;AAC1D,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU;;AAGlE,SAAgB,YAAY,OAA+B;AACzD,QAAO,UAAU,MAAM,IAAI,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;;AAG3E,SAAgB,WAAW,QAAyB;AAClD,QAAO,WAAW,SAAS,OAAO;;AAGpC,SAAgB,gBAAgB,MAAwB;AACtD,KAAI,CAAC,UAAU,KAAK,CAAE,QAAO;AAC7B,QACG,KAAK,SAAS,aAAa,OAAO,KAAK,UAAU,YACjD,KAAK,SAAS,qBACb,MAAM,QAAQ,KAAK,YAAY,IAC/B,KAAK,YAAY,WAAW"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@generaltranslation/gt-next-lint",
3
- "version": "14.0.26",
3
+ "version": "14.0.28",
4
4
  "description": "ESLint plugin for General Translation Next.js integration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  "eslint": "^8.0.0 || ^9.0.0",
38
38
  "@typescript-eslint/eslint-plugin": "^8.0.0",
39
39
  "@typescript-eslint/parser": "^8.0.0",
40
- "gt-next": "6.16.26"
40
+ "gt-next": "6.16.28"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/eslint": "^8.56.0",
@@ -45,16 +45,18 @@
45
45
  "@typescript-eslint/eslint-plugin": "^8.0.0",
46
46
  "@typescript-eslint/parser": "^8.0.0",
47
47
  "eslint": "^9.0.0",
48
+ "tsdown": "^0.21.10",
48
49
  "typescript": "^5.9.2",
49
50
  "vitest": "^3.2.4"
50
51
  },
51
52
  "scripts": {
52
53
  "patch": "pnpm version patch",
53
- "transpile": "tsc",
54
+ "emit-types": "sh ../../scripts/emit-types.sh",
55
+ "transpile": "tsdown && pnpm run emit-types",
54
56
  "build": "pnpm run transpile",
55
57
  "build:clean": "sh ../../scripts/clean.sh && pnpm run build",
56
58
  "build:release": "pnpm run build:clean",
57
- "dev": "tsc --watch",
59
+ "dev": "tsdown --watch",
58
60
  "release": "pnpm run build:clean && pnpm publish",
59
61
  "release:alpha": "pnpm run build:clean && pnpm publish --tag alpha",
60
62
  "release:beta": "pnpm run build:clean && pnpm publish --tag beta",