diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9343f7a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +Nothing yet. + +## [0.2.0] - 2023-09-08 + +### Fixed + +- `no-physical-properties` rule now correctly handles classes with !important like `!pl-1` flag and modifiers like `hover:` (#1) + +## [0.1.0] - 2023-08-24 + +### Added + +- `no-physical-properties` rule \ No newline at end of file diff --git a/README.md b/README.md index caaa7fd..7465663 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ Welcome your contribution! ## TODO: - [x] Tailwindcss physical properties to logical properties +- [ ] Add support for advanced className like `cn('pl-2', {...})`[.](https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/6b6c0dd28e123cc118bff83654f951f736fa58e8/lib/rules/no-arbitrary-value.js#L169) - [ ] Strict `` to have dir attribute depending on a codition or whatever detecting the language - [ ] Strict `` to have `dir="ltr"` to override the parent's direction - [ ] in the future maybe throw a warning that `letter-spacing` doesn't work well with RTL languages to disable it in rtl `rtl:***` (NOT SURE) diff --git a/docs/rules/no-physical-properties.md b/docs/rules/no-physical-properties.md index 23a57b1..e45a612 100644 --- a/docs/rules/no-physical-properties.md +++ b/docs/rules/no-physical-properties.md @@ -10,13 +10,13 @@ This rule enforces the use of css logical properties instead of physical propert ## Examples of incorrect code for this rule: ```jsx -
+
``` ## Examples of correct code for this rule: ```jsx -
+
``` ## To automatically fix all of the problems reported by this rule diff --git a/src/rules/no-physical-properties.ts b/src/rules/no-physical-properties.ts index c024038..786e90d 100644 --- a/src/rules/no-physical-properties.ts +++ b/src/rules/no-physical-properties.ts @@ -2,6 +2,11 @@ import { Rule } from 'eslint'; import { logicalProperties } from '../configs/tw-logical-properties'; import { JSXAttribute } from 'estree-jsx'; +/** + * **TODO** Refactor this ugly code + * **TODO** Add support for `className={cn('ms-1', 'me-2')}` + */ + const exampleRule: Rule.RuleModule = { meta: { type: 'suggestion', @@ -42,7 +47,17 @@ const ruleListener = (ctx: Rule.RuleContext) => { const PH_CNs = logicalProperties.map((c) => c.physical); const conflictClassNames = cnArr.filter((cn) => - PH_CNs.some((c) => cn.startsWith(c)) + PH_CNs.some((c) => { + let isValid = false; + [ + new RegExp(`^${c}.*`), + new RegExp(`!${c}.*`), + new RegExp(`.+:${c}.*`), + ].forEach((regex) => { + if (regex.test(cn)) isValid = true; + }); + return isValid; + }) ); if (!conflictClassNames.length) return; @@ -54,10 +69,19 @@ const ruleListener = (ctx: Rule.RuleContext) => { invalid: conflictClassNames.join(' '), valid: conflictClassNames .map((cn) => { - const { logical, physical } = logicalProperties.find((c) => - cn.startsWith(c.physical) - )!; - return cn.replace(physical, logical); + const prop = logicalProperties.find((c) => { + let isValid = false; + [ + new RegExp(`^${c.physical}.*`), + new RegExp(`!${c.physical}.*`), + new RegExp(`.+:${c.physical}.*`), + ].forEach((regex) => { + if (regex.test(cn)) isValid = true; + }); + return isValid; + }); + if (!prop) return cn; + return cn.replace(prop.physical, prop.logical); }) .join(' '), }, @@ -66,10 +90,19 @@ const ruleListener = (ctx: Rule.RuleContext) => { const fixedClassName = cnArr .map((cn) => { if (conflictClassNames.includes(cn)) { - const { logical, physical } = logicalProperties.find((c) => - cn.startsWith(c.physical) - )!; - return cn.replace(physical, logical); + const prop = logicalProperties.find((c) => { + let isValid = false; + [ + new RegExp(`^${c.physical}.*`), + new RegExp(`!${c.physical}.*`), + new RegExp(`.+:${c.physical}.*`), + ].forEach((regex) => { + if (regex.test(cn)) isValid = true; + }); + return isValid; + }); + if (!prop) return cn; + return cn.replace(prop.physical, prop.logical); } return cn; }) diff --git a/tests/rules/no-physical-properties.ts b/tests/rules/no-physical-properties.ts index 8d73ca2..131fc66 100644 --- a/tests/rules/no-physical-properties.ts +++ b/tests/rules/no-physical-properties.ts @@ -16,9 +16,17 @@ tester.run('no-physical-properties', logicalProperties, { code: `
text
`, }, { - name: 'should work fine with `class` attribute', + name: 'should work well with `class` attribute', code: `
text
`, - } + }, + { + name: 'should work well with the important flag', + code: `
text
`, + }, + { + name: 'should work well with the prefixes flag', + code: `
text
`, + }, ], invalid: [ { @@ -69,5 +77,35 @@ tester.run('no-physical-properties', logicalProperties, { output: `
text
`, errors: [{ messageId: 'noPhysicalProperties' }], }, + { + name: 'should report if physical properties are used with the important flag and fix them', + code: `
text
`, + output: `
text
`, + errors: [{ messageId: 'noPhysicalProperties' }], + }, + { + name: 'should report if physical properties are used with modifiers and fix them', + code: `
text
`, + output: `
text
`, + errors: [{ messageId: 'noPhysicalProperties' }], + }, + { + name: 'should report if physical properties are used with modifiers and fix them', + code: `
text
`, + output: `
text
`, + errors: [{ messageId: 'noPhysicalProperties' }], + }, + { + name: 'should report if physical properties are used with modifiers and fix them', + code: `
text
`, + output: `
text
`, + errors: [{ messageId: 'noPhysicalProperties' }], + }, + { + name: 'should report if physical properties are used with important flag and modifiers and fix them', + code: `
text
`, + output: `
text
`, + errors: [{ messageId: 'noPhysicalProperties' }], + }, ], });