rtl-shield 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Berkin Duz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,283 @@
1
+ # 🛡️ RTL Shield
2
+
3
+ **Automated ESLint guardrails for robust RTL support in the GCC market.**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/eslint-plugin-rtl-shield.svg)](https://www.npmjs.com/package/eslint-plugin-rtl-shield)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ---
9
+
10
+ ## ⚠️ The Problem
11
+
12
+ In the Middle East and North Africa (MENA) region, Arabic and other RTL (Right-to-Left) languages represent a massive market opportunity. However, **many engineering teams still build with physical CSS properties** like `left`, `right`, `marginLeft`, and `paddingRight`—properties that fundamentally break bidirectional layouts.
13
+
14
+ ### Why This Matters
15
+
16
+ - **Physical properties are direction-specific**: `left: 10px` means "move 10px from the left edge"—in RTL, this is visually incorrect.
17
+ - **Manual reviews are error-prone**: CSS property mapping is tedious and easy to overlook in code reviews.
18
+ - **Scale is impossible**: As codebases grow, maintaining RTL consistency becomes exponentially harder without automation.
19
+ - **Lost revenue**: Poorly localized experiences drive users away from your platform.
20
+
21
+ **RTL Shield solves this at the source**—by enforcing logical CSS properties during development, ensuring your application is RTL-ready before it ships.
22
+
23
+ ---
24
+
25
+ ## ✨ Key Features
26
+
27
+ ### 🎨 **CSS-in-JS & Style Objects**
28
+
29
+ Full support for React, Next.js, and JavaScript style objects (Emotion, Styled Components, inline styles, etc.)
30
+
31
+ - Automatically detects and fixes physical properties
32
+ - Works with object literals in JavaScript
33
+ - Smart autofix saves hundreds of manual hours
34
+
35
+ ### 🌬️ **Tailwind CSS Support**
36
+
37
+ Seamlessly handles Tailwind utility classes in `className` and `class` attributes
38
+
39
+ - Converts `ml-4` → `ms-4`, `text-left` → `text-start`
40
+ - Processes multiple classes in a single string
41
+ - Fully compatible with Next.js and modern React projects
42
+
43
+ ### 🔄 **Comprehensive Property Mapping**
44
+
45
+ Covers the full spectrum of directional CSS:
46
+
47
+ - **Margins & Padding**: `marginLeft` → `marginInlineStart`
48
+ - **Positioning**: `left` → `insetInlineStart`, `right` → `insetInlineEnd`
49
+ - **Borders**: All variants—`borderLeft`, `borderLeftWidth`, `borderLeftColor`, etc.
50
+ - **Border Radius**: Complex radius properties like `borderTopLeftRadius` → `borderStartStartRadius`
51
+
52
+ ### ⚡ **Smart Autofix**
53
+
54
+ One command to fix your entire codebase:
55
+
56
+ ```bash
57
+ eslint --fix
58
+ ```
59
+
60
+ No manual intervention required—just commit and deploy.
61
+
62
+ ### 🎯 **Zero Configuration**
63
+
64
+ The `recommended` preset works out-of-the-box with sensible defaults.
65
+
66
+ ---
67
+
68
+ ## 📦 Installation
69
+
70
+ ### Step 1: Install the Plugin
71
+
72
+ ```bash
73
+ npm install --save-dev eslint-plugin-rtl-shield
74
+ # or
75
+ yarn add --dev eslint-plugin-rtl-shield
76
+ # or
77
+ pnpm add --save-dev eslint-plugin-rtl-shield
78
+ ```
79
+
80
+ ### Step 2: Configure ESLint
81
+
82
+ Add the plugin to your ESLint configuration file (`.eslintrc.json`, `.eslintrc.js`, or `eslint.config.js`):
83
+
84
+ #### Using the Recommended Config (Recommended âś…)
85
+
86
+ ```json
87
+ {
88
+ "extends": ["plugin:rtl-shield/recommended"]
89
+ }
90
+ ```
91
+
92
+ This automatically enables both rules with error-level severity:
93
+
94
+ - `rtl-shield/prefer-logical-properties` — for CSS-in-JS
95
+ - `rtl-shield/prefer-logical-tailwindcss` — for Tailwind CSS
96
+
97
+ #### Manual Configuration
98
+
99
+ If you prefer granular control:
100
+
101
+ ```json
102
+ {
103
+ "plugins": ["rtl-shield"],
104
+ "rules": {
105
+ "rtl-shield/prefer-logical-properties": "error",
106
+ "rtl-shield/prefer-logical-tailwindcss": "error"
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### Step 3: Run ESLint
112
+
113
+ Lint your project:
114
+
115
+ ```bash
116
+ eslint .
117
+ ```
118
+
119
+ Auto-fix issues:
120
+
121
+ ```bash
122
+ eslint --fix .
123
+ ```
124
+
125
+ ---
126
+
127
+ ## 📊 Showcase: Physical vs. Logical
128
+
129
+ ### CSS-in-JS / Style Objects
130
+
131
+ | Physical (❌ Breaks RTL) | Logical (✅ RTL-Ready) | Use Case |
132
+ | ------------------------- | ---------------------------- | --------------- |
133
+ | `marginLeft: 16` | `marginInlineStart: 16` | Outer spacing |
134
+ | `paddingRight: 8` | `paddingInlineEnd: 8` | Inner spacing |
135
+ | `left: 0` | `insetInlineStart: 0` | Positioning |
136
+ | `right: 10` | `insetInlineEnd: 10` | Positioning |
137
+ | `borderLeftWidth: 2` | `borderInlineStartWidth: 2` | Border styling |
138
+ | `borderTopLeftRadius: 12` | `borderStartStartRadius: 12` | Rounded corners |
139
+
140
+ ### Tailwind CSS
141
+
142
+ | Physical (❌ Breaks RTL) | Logical (✅ RTL-Ready) | Use Case |
143
+ | ------------------------ | ---------------------- | ---------------------------- |
144
+ | `ml-4` | `ms-4` | Margin start |
145
+ | `mr-8` | `me-8` | Margin end |
146
+ | `pl-2` | `ps-2` | Padding start |
147
+ | `pr-6` | `pe-6` | Padding end |
148
+ | `text-left` | `text-start` | Text alignment |
149
+ | `text-right` | `text-end` | Text alignment |
150
+ | `rounded-tl-lg` | `rounded-ss-lg` | Border radius (top-left) |
151
+ | `rounded-br-md` | `rounded-ee-md` | Border radius (bottom-right) |
152
+ | `left-0` | `start-0` | Positioning |
153
+ | `right-10` | `end-10` | Positioning |
154
+
155
+ ### Before & After Example
156
+
157
+ **Before (Physical Properties):**
158
+
159
+ ```jsx
160
+ // ❌ Breaks in Arabic/RTL
161
+ const Card = () => (
162
+ <div className="ml-4 p-4 rounded-tl-lg">
163
+ <h1 style={{ paddingLeft: 16, textAlign: "left" }}>Title</h1>
164
+ </div>
165
+ );
166
+ ```
167
+
168
+ **After (Logical Properties):**
169
+
170
+ ```jsx
171
+ // âś… Works perfectly in RTL
172
+ const Card = () => (
173
+ <div className="ms-4 p-4 rounded-ss-lg">
174
+ <h1 style={{ paddingInlineStart: 16, textAlign: "start" }}>Title</h1>
175
+ </div>
176
+ );
177
+ ```
178
+
179
+ ---
180
+
181
+ ## 🌍 Why for the GCC Market?
182
+
183
+ The GCC region (United Arab Emirates, Saudi Arabia, Qatar, Kuwait, Bahrain, and Oman) represents one of the fastest-growing digital markets:
184
+
185
+ - **High-value market**: GCC users have the highest digital spending in the MENA region
186
+ - **Native RTL requirement**: Arabic is a constitutional requirement in government and enterprise apps
187
+ - **Business critical**: Improper RTL support directly impacts user trust and platform adoption
188
+ - **Regulatory compliance**: Many GCC-based companies must meet localization standards
189
+ - **Competitive advantage**: Teams that ship proper RTL support get better retention and market share
190
+
191
+ **RTL Shield enables your engineering team to:**
192
+
193
+ - Ship RTL-ready code from day one
194
+ - Reduce localization QA cycles
195
+ - Avoid expensive refactoring late in the project lifecycle
196
+ - Build products that resonate with users across the MENA region
197
+
198
+ ---
199
+
200
+ ## đź“‹ Rules
201
+
202
+ ### `prefer-logical-properties`
203
+
204
+ Enforces logical CSS properties in JavaScript style objects, preventing physical properties that break bidirectional layouts.
205
+
206
+ **Type:** Suggestion
207
+ **Fixable:** Yes âś…
208
+
209
+ **Example:**
210
+
211
+ ```js
212
+ // ❌ Error
213
+ const styles = { marginLeft: 10, borderRightColor: "red" };
214
+
215
+ // âś… Correct
216
+ const styles = { marginInlineStart: 10, borderInlineEndColor: "red" };
217
+ ```
218
+
219
+ ### `prefer-logical-tailwindcss`
220
+
221
+ Enforces logical Tailwind CSS utility classes in JSX `className` and `class` attributes.
222
+
223
+ **Type:** Suggestion
224
+ **Fixable:** Yes âś…
225
+
226
+ **Example:**
227
+
228
+ ```jsx
229
+ // ❌ Error
230
+ <div className="ml-4 text-left rounded-tl-lg" />
231
+
232
+ // âś… Correct
233
+ <div className="ms-4 text-start rounded-ss-lg" />
234
+ ```
235
+
236
+ ---
237
+
238
+ ## 🚀 Quick Start
239
+
240
+ ```bash
241
+ # 1. Install
242
+ npm install --save-dev eslint-plugin-rtl-shield
243
+
244
+ # 2. Add to .eslintrc.json
245
+ echo '{
246
+ "extends": ["plugin:rtl-shield/recommended"]
247
+ }' > .eslintrc.json
248
+
249
+ # 3. Fix all files
250
+ npx eslint --fix .
251
+
252
+ # 4. Commit and deploy
253
+ git add .
254
+ git commit -m "chore: enforce RTL-safe logical properties"
255
+ ```
256
+
257
+ ---
258
+
259
+ ## 📚 Resources
260
+
261
+ - [MDN: CSS Logical Properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties)
262
+ - [Tailwind CSS: Logical Properties](https://tailwindcss.com/docs/guides/rtl)
263
+ - [W3C: Structural Markup and Right-to-Left Text in HTML](https://www.w3.org/International/questions/qa-html-dir)
264
+
265
+ ---
266
+
267
+ ## 🤝 Contributing
268
+
269
+ We welcome contributions! Please feel free to open issues or submit pull requests on [GitHub](https://github.com/berkinduz/rtl-shield).
270
+
271
+ ---
272
+
273
+ ## đź“„ License
274
+
275
+ MIT © 2025 [Berkin Duz](https://github.com/berkinduz)
276
+
277
+ ---
278
+
279
+ ## đź’ˇ Support
280
+
281
+ Have questions or feedback? Open an issue on our [GitHub repository](https://github.com/berkinduz/rtl-shield/issues).
282
+
283
+ **Built with ❤️ for the GCC market and the broader MENA region.**
@@ -0,0 +1,14 @@
1
+ import type { Rule } from "eslint";
2
+ declare const _default: {
3
+ rules: Record<string, Rule.RuleModule>;
4
+ configs: {
5
+ recommended: {
6
+ plugins: string[];
7
+ rules: {
8
+ "rtl-shield/prefer-logical-properties": string;
9
+ "rtl-shield/prefer-logical-tailwindcss": string;
10
+ };
11
+ };
12
+ };
13
+ };
14
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const prefer_logical_properties_1 = __importDefault(require("./rules/prefer-logical-properties"));
7
+ const prefer_logical_tailwindcss_1 = __importDefault(require("./rules/prefer-logical-tailwindcss"));
8
+ const rules = {
9
+ "prefer-logical-properties": prefer_logical_properties_1.default,
10
+ "prefer-logical-tailwindcss": prefer_logical_tailwindcss_1.default,
11
+ };
12
+ const configs = {
13
+ recommended: {
14
+ plugins: ["rtl-shield"],
15
+ rules: {
16
+ "rtl-shield/prefer-logical-properties": "error",
17
+ "rtl-shield/prefer-logical-tailwindcss": "error",
18
+ },
19
+ },
20
+ };
21
+ exports.default = {
22
+ rules,
23
+ configs,
24
+ };
@@ -0,0 +1,3 @@
1
+ import { Rule } from "eslint";
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const PHYSICAL_TO_LOGICAL = {
4
+ marginLeft: "marginInlineStart",
5
+ marginRight: "marginInlineEnd",
6
+ paddingLeft: "paddingInlineStart",
7
+ paddingRight: "paddingInlineEnd",
8
+ left: "insetInlineStart",
9
+ right: "insetInlineEnd",
10
+ borderTopLeftRadius: "borderStartStartRadius",
11
+ borderBottomLeftRadius: "borderStartEndRadius",
12
+ borderTopRightRadius: "borderEndStartRadius",
13
+ borderBottomRightRadius: "borderEndEndRadius",
14
+ borderLeft: "borderInlineStart",
15
+ borderRight: "borderInlineEnd",
16
+ borderLeftWidth: "borderInlineStartWidth",
17
+ borderRightWidth: "borderInlineEndWidth",
18
+ borderLeftStyle: "borderInlineStartStyle",
19
+ borderRightStyle: "borderInlineEndStyle",
20
+ borderLeftColor: "borderInlineStartColor",
21
+ borderRightColor: "borderInlineEndColor",
22
+ };
23
+ const TEXT_ALIGN_MAPPING = {
24
+ left: "start",
25
+ right: "end",
26
+ };
27
+ const rule = {
28
+ meta: {
29
+ type: "suggestion",
30
+ docs: {
31
+ description: "Enforce CSS Logical Properties instead of physical properties for better RTL support",
32
+ recommended: true,
33
+ },
34
+ fixable: "code",
35
+ schema: [],
36
+ },
37
+ create(context) {
38
+ return {
39
+ Property(node) {
40
+ // Check if this is a property with an Identifier or Literal key
41
+ const key = node.key;
42
+ let propName = "";
43
+ if (key.type === "Identifier") {
44
+ propName = key.name;
45
+ }
46
+ else if (key.type === "Literal" && typeof key.value === "string") {
47
+ propName = key.value;
48
+ }
49
+ // Check for physical properties that should be logical
50
+ if (propName in PHYSICAL_TO_LOGICAL) {
51
+ const logicalProperty = PHYSICAL_TO_LOGICAL[propName];
52
+ context.report({
53
+ node,
54
+ message: `Use logical property '${logicalProperty}' instead of '${propName}' for better RTL support`,
55
+ fix(fixer) {
56
+ return fixer.replaceText(key, logicalProperty);
57
+ },
58
+ });
59
+ }
60
+ // Check for textAlign property
61
+ if (propName === "textAlign") {
62
+ const value = node.value;
63
+ if (value.type === "Literal" &&
64
+ typeof value.value === "string" &&
65
+ value.value in TEXT_ALIGN_MAPPING) {
66
+ const logicalValue = TEXT_ALIGN_MAPPING[value.value];
67
+ context.report({
68
+ node: value,
69
+ message: `Use textAlign: '${logicalValue}' instead of '${value.value}' for better RTL support`,
70
+ fix(fixer) {
71
+ return fixer.replaceText(value, `'${logicalValue}'`);
72
+ },
73
+ });
74
+ }
75
+ }
76
+ },
77
+ };
78
+ },
79
+ };
80
+ exports.default = rule;
@@ -0,0 +1,3 @@
1
+ import { Rule } from "eslint";
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // Mapping of physical Tailwind classes to their logical counterparts
4
+ const TAILWIND_PHYSICAL_TO_LOGICAL = {
5
+ "ml-": "ms-",
6
+ "mr-": "me-",
7
+ "pl-": "ps-",
8
+ "pr-": "pe-",
9
+ "text-left": "text-start",
10
+ "text-right": "text-end",
11
+ "rounded-tl-": "rounded-ss-",
12
+ "rounded-tr-": "rounded-se-",
13
+ "rounded-bl-": "rounded-es-",
14
+ "rounded-br-": "rounded-ee-",
15
+ "left-": "start-",
16
+ "right-": "end-",
17
+ };
18
+ const EXACT_REPLACEMENTS = {
19
+ "text-left": "text-start",
20
+ "text-right": "text-end",
21
+ };
22
+ /**
23
+ * Replace physical Tailwind classes with their logical equivalents
24
+ */
25
+ function replaceClassesInString(str) {
26
+ let result = str;
27
+ // First, handle exact replacements (e.g., text-left -> text-start)
28
+ for (const [physical, logical] of Object.entries(EXACT_REPLACEMENTS)) {
29
+ result = result.replace(new RegExp(`\\b${physical}\\b`, "g"), logical);
30
+ }
31
+ // Then handle prefix replacements (e.g., ml- -> ms-)
32
+ // We need to be careful to match the full class name
33
+ for (const [physical, logical] of Object.entries(TAILWIND_PHYSICAL_TO_LOGICAL)) {
34
+ // Skip exact replacements as they're already handled
35
+ if (physical in EXACT_REPLACEMENTS)
36
+ continue;
37
+ // Create a regex that matches the physical prefix followed by any characters until whitespace or end
38
+ const regex = new RegExp(`\\b${physical.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}([a-zA-Z0-9-]*)\\b`, "g");
39
+ result = result.replace(regex, `${logical}$1`);
40
+ }
41
+ return result;
42
+ }
43
+ /**
44
+ * Check if a string contains any physical Tailwind classes that need to be replaced
45
+ */
46
+ function hasPhysicalClasses(str) {
47
+ // Check for exact matches first
48
+ for (const physical of Object.keys(EXACT_REPLACEMENTS)) {
49
+ if (new RegExp(`\\b${physical}\\b`).test(str)) {
50
+ return true;
51
+ }
52
+ }
53
+ // Check for prefix matches
54
+ for (const physical of Object.keys(TAILWIND_PHYSICAL_TO_LOGICAL)) {
55
+ if (physical in EXACT_REPLACEMENTS)
56
+ continue;
57
+ if (new RegExp(`\\b${physical.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`).test(str)) {
58
+ return true;
59
+ }
60
+ }
61
+ return false;
62
+ }
63
+ const rule = {
64
+ meta: {
65
+ type: "suggestion",
66
+ docs: {
67
+ description: "Enforce logical Tailwind CSS classes instead of physical ones for better RTL support",
68
+ recommended: true,
69
+ },
70
+ fixable: "code",
71
+ schema: [],
72
+ },
73
+ create(context) {
74
+ return {
75
+ Literal(node) {
76
+ // Check if this is a className or class attribute value
77
+ if (typeof node.value !== "string") {
78
+ return;
79
+ }
80
+ const value = node.value;
81
+ // Only process if this looks like a className/class value
82
+ if (!hasPhysicalClasses(value)) {
83
+ return;
84
+ }
85
+ // Check if the parent is a JSXAttribute with name "className" or "class"
86
+ const parent = node.parent;
87
+ if (parent && parent.type === "JSXExpressionContainer") {
88
+ // Parent is within a JSX expression container
89
+ const grandParent = parent.parent;
90
+ if (grandParent &&
91
+ grandParent.type === "JSXAttribute" &&
92
+ (grandParent.name.name === "className" ||
93
+ grandParent.name.name === "class")) {
94
+ const logicalValue = replaceClassesInString(value);
95
+ if (logicalValue !== value) {
96
+ context.report({
97
+ node,
98
+ message: "Use logical Tailwind CSS classes instead of physical ones for better RTL support",
99
+ fix(fixer) {
100
+ return fixer.replaceText(node, `"${logicalValue}"`);
101
+ },
102
+ });
103
+ }
104
+ }
105
+ }
106
+ else if (parent && parent.type === "JSXAttribute") {
107
+ // Direct attribute value
108
+ if (parent.name.name === "className" ||
109
+ parent.name.name === "class") {
110
+ const logicalValue = replaceClassesInString(value);
111
+ if (logicalValue !== value) {
112
+ context.report({
113
+ node,
114
+ message: "Use logical Tailwind CSS classes instead of physical ones for better RTL support",
115
+ fix(fixer) {
116
+ return fixer.replaceText(node, `"${logicalValue}"`);
117
+ },
118
+ });
119
+ }
120
+ }
121
+ }
122
+ },
123
+ TemplateElement(node) {
124
+ // Handle template literals in className attributes
125
+ const value = node.value.raw;
126
+ if (!hasPhysicalClasses(value)) {
127
+ return;
128
+ }
129
+ // Check if this is part of a template literal in className
130
+ const parent = node.parent;
131
+ if (parent && parent.type === "TemplateLiteral") {
132
+ const grandParent = parent.parent;
133
+ if (grandParent &&
134
+ grandParent.type === "JSXExpressionContainer" &&
135
+ grandParent.parent &&
136
+ grandParent.parent.type === "JSXAttribute") {
137
+ const attr = grandParent.parent;
138
+ if (attr.name.name === "className" || attr.name.name === "class") {
139
+ const logicalValue = replaceClassesInString(value);
140
+ if (logicalValue !== value) {
141
+ context.report({
142
+ node,
143
+ message: "Use logical Tailwind CSS classes instead of physical ones for better RTL support",
144
+ fix(fixer) {
145
+ return fixer.replaceText(node, logicalValue);
146
+ },
147
+ });
148
+ }
149
+ }
150
+ }
151
+ }
152
+ },
153
+ };
154
+ },
155
+ };
156
+ exports.default = rule;
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "rtl-shield",
3
+ "version": "0.1.0",
4
+ "description": "ESLint plugin to enforce CSS Logical Properties for robust RTL support",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md",
10
+ "LICENSE"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "test": "vitest",
15
+ "test:watch": "vitest --watch",
16
+ "prepublishOnly": "npm run build && npm run test -- --run"
17
+ },
18
+ "keywords": [
19
+ "eslint",
20
+ "eslint-plugin",
21
+ "rtl",
22
+ "css-logical-properties",
23
+ "i18n"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/berkinduz/rtl-shield.git"
30
+ },
31
+ "bugs": {
32
+ "url": "https://github.com/berkinduz/rtl-shield/issues"
33
+ },
34
+ "homepage": "https://github.com/berkinduz/rtl-shield#readme",
35
+ "peerDependencies": {
36
+ "eslint": "^8.0.0 || ^9.0.0"
37
+ },
38
+ "dependencies": {
39
+ "@typescript-eslint/utils": "^6.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@babel/eslint-parser": "^7.28.5",
43
+ "@babel/preset-react": "^7.28.5",
44
+ "@types/eslint": "^9.6.1",
45
+ "@types/node": "^20.0.0",
46
+ "eslint": "^8.0.0",
47
+ "espree": "^11.0.0",
48
+ "typescript": "^5.0.0",
49
+ "vitest": "^1.0.0"
50
+ }
51
+ }