@mgcrea/react-native-tailwind 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/babel/index.cjs +1 -1
- package/dist/babel/utils/attributeMatchers.test.ts +294 -0
- package/dist/babel/utils/componentSupport.test.ts +426 -0
- package/dist/parser/colors.test.js +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.cjs.map +2 -2
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +2 -2
- package/dist/utils/flattenColors.d.ts +1 -0
- package/dist/utils/flattenColors.js +1 -1
- package/dist/utils/flattenColors.test.js +1 -1
- package/package.json +1 -1
- package/src/babel/utils/attributeMatchers.test.ts +294 -0
- package/src/babel/utils/componentSupport.test.ts +426 -0
- package/src/parser/colors.test.ts +32 -0
- package/src/parser/index.ts +1 -1
- package/src/utils/flattenColors.test.ts +100 -0
- package/src/utils/flattenColors.ts +3 -1
|
@@ -7,6 +7,7 @@ type NestedColors = {
|
|
|
7
7
|
/**
|
|
8
8
|
* Flatten nested color objects into flat key-value map
|
|
9
9
|
* Example: { brand: { light: '#fff', dark: '#000' } } => { 'brand-light': '#fff', 'brand-dark': '#000' }
|
|
10
|
+
* Special handling for DEFAULT: { primary: { DEFAULT: '#000', 500: '#333' } } => { 'primary': '#000', 'primary-500': '#333' }
|
|
10
11
|
*
|
|
11
12
|
* @param colors - Nested color object where values can be strings or objects
|
|
12
13
|
* @param prefix - Optional prefix for nested keys (used for recursion)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.flattenColors=flattenColors;var _slicedToArray2=_interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));function flattenColors(colors){var prefix=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"";var result={};for(var _ref of Object.entries(colors)){var _ref2=(0,_slicedToArray2.default)(_ref,2);var _key=_ref2[0];var value=_ref2[1];var newKey=prefix?`${prefix}-${_key}`:_key;if(typeof value==="string"){result[newKey]=value;}else if(typeof value==="object"&&value!==null){Object.assign(result,flattenColors(value,newKey));}}return result;}
|
|
1
|
+
var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.flattenColors=flattenColors;var _slicedToArray2=_interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));function flattenColors(colors){var prefix=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"";var result={};for(var _ref of Object.entries(colors)){var _ref2=(0,_slicedToArray2.default)(_ref,2);var _key=_ref2[0];var value=_ref2[1];var newKey=_key==="DEFAULT"&&prefix?prefix:prefix?`${prefix}-${_key}`:_key;if(typeof value==="string"){result[newKey]=value;}else if(typeof value==="object"&&value!==null){Object.assign(result,flattenColors(value,newKey));}}return result;}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var _vitest=require("vitest");var _flattenColors=require("./flattenColors");(0,_vitest.describe)("flattenColors",function(){(0,_vitest.it)("should handle flat color objects",function(){var colors={red:"#ff0000",blue:"#0000ff",green:"#00ff00"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({red:"#ff0000",blue:"#0000ff",green:"#00ff00"});});(0,_vitest.it)("should flatten single-level nested objects",function(){var colors={brand:{primary:"#ff6b6b",secondary:"#4ecdc4"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"brand-primary":"#ff6b6b","brand-secondary":"#4ecdc4"});});(0,_vitest.it)("should flatten multi-level nested objects",function(){var colors={brand:{light:{primary:"#ffcccc",secondary:"#ccffff"},dark:{primary:"#990000",secondary:"#006666"}}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"brand-light-primary":"#ffcccc","brand-light-secondary":"#ccffff","brand-dark-primary":"#990000","brand-dark-secondary":"#006666"});});(0,_vitest.it)("should handle mixed flat and nested objects",function(){var colors={white:"#ffffff",black:"#000000",brand:{primary:"#ff6b6b",secondary:"#4ecdc4"},accent:"#ffe66d"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({white:"#ffffff",black:"#000000","brand-primary":"#ff6b6b","brand-secondary":"#4ecdc4",accent:"#ffe66d"});});(0,_vitest.it)("should handle Tailwind-style color scale objects",function(){var colors={gray:{"50":"#f9fafb","100":"#f3f4f6","200":"#e5e7eb","500":"#6b7280","900":"#111827"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"gray-50":"#f9fafb","gray-100":"#f3f4f6","gray-200":"#e5e7eb","gray-500":"#6b7280","gray-900":"#111827"});});(0,_vitest.it)("should handle empty object",function(){(0,_vitest.expect)((0,_flattenColors.flattenColors)({})).toEqual({});});(0,_vitest.it)("should handle single color",function(){var colors={primary:"#ff0000"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({primary:"#ff0000"});});(0,_vitest.it)("should handle deeply nested objects (3+ levels)",function(){var colors={theme:{light:{brand:{primary:"#ff6b6b",secondary:"#4ecdc4"}},dark:{brand:{primary:"#990000",secondary:"#006666"}}}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"theme-light-brand-primary":"#ff6b6b","theme-light-brand-secondary":"#4ecdc4","theme-dark-brand-primary":"#990000","theme-dark-brand-secondary":"#006666"});});(0,_vitest.it)("should handle numeric keys",function(){var colors={blue:{"100":"#dbeafe","500":"#3b82f6","900":"#1e3a8a"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"blue-100":"#dbeafe","blue-500":"#3b82f6","blue-900":"#1e3a8a"});});(0,_vitest.it)("should handle keys with hyphens",function(){var colors={"brand-primary":"#ff0000","brand-secondary":{light:"#00ff00",dark:"#006600"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"brand-primary":"#ff0000","brand-secondary-light":"#00ff00","brand-secondary-dark":"#006600"});});(0,_vitest.it)("should handle uppercase and lowercase hex values",function(){var colors={red:"#FF0000",blue:"#0000ff",green:"#00Ff00"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({red:"#FF0000",blue:"#0000ff",green:"#00Ff00"});});(0,_vitest.it)("should handle 3-digit hex values",function(){var colors={red:"#f00",blue:"#00f",green:"#0f0"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({red:"#f00",blue:"#00f",green:"#0f0"});});(0,_vitest.it)("should handle 8-digit hex values (with alpha)",function(){var colors={"red-50":"#ff000080","blue-50":"#0000ff80"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"red-50":"#ff000080","blue-50":"#0000ff80"});});(0,_vitest.it)("should handle complex real-world Tailwind config",function(){var colors={transparent:"transparent",current:"currentColor",white:"#ffffff",black:"#000000",gray:{"50":"#f9fafb","100":"#f3f4f6","500":"#6b7280","900":"#111827"},brand:{primary:"#ff6b6b",secondary:"#4ecdc4",accent:{light:"#ffe66d",dark:"#ffb900"}}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({transparent:"transparent",current:"currentColor",white:"#ffffff",black:"#000000","gray-50":"#f9fafb","gray-100":"#f3f4f6","gray-500":"#6b7280","gray-900":"#111827","brand-primary":"#ff6b6b","brand-secondary":"#4ecdc4","brand-accent-light":"#ffe66d","brand-accent-dark":"#ffb900"});});(0,_vitest.it)("should not mutate input object",function(){var colors={brand:{primary:"#ff6b6b",secondary:"#4ecdc4"}};var original=JSON.parse(JSON.stringify(colors));(0,_flattenColors.flattenColors)(colors);(0,_vitest.expect)(colors).toEqual(original);});(0,_vitest.it)("should handle undefined values gracefully",function(){var colors={red:"#ff0000",blue:undefined,green:"#00ff00"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({red:"#ff0000",green:"#00ff00"});});(0,_vitest.it)("should handle special color keywords",function(){var colors={transparent:"transparent",current:"currentColor",inherit:"inherit"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({transparent:"transparent",current:"currentColor",inherit:"inherit"});});(0,_vitest.it)("should handle RGB/RGBA color values",function(){var colors={primary:"rgb(255, 0, 0)",secondary:"rgba(0, 255, 0, 0.5)"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({primary:"rgb(255, 0, 0)",secondary:"rgba(0, 255, 0, 0.5)"});});(0,_vitest.it)("should handle very deeply nested structures (stress test)",function(){var colors={level1:{level2:{level3:{level4:{level5:"#ff0000"}}}}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"level1-level2-level3-level4-level5":"#ff0000"});});(0,_vitest.it)("should handle camelCase keys",function(){var colors={brandPrimary:"#ff0000",accentColor:{lightShade:"#ffcccc",darkShade:"#cc0000"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({brandPrimary:"#ff0000","accentColor-lightShade":"#ffcccc","accentColor-darkShade":"#cc0000"});});(0,_vitest.it)("should produce consistent output",function(){var colors={brand:{primary:"#ff6b6b",secondary:"#4ecdc4"}};var result1=(0,_flattenColors.flattenColors)(colors);var result2=(0,_flattenColors.flattenColors)(colors);var result3=(0,_flattenColors.flattenColors)(colors);(0,_vitest.expect)(result1).toEqual(result2);(0,_vitest.expect)(result2).toEqual(result3);});(0,_vitest.it)("should maintain key order (insertion order)",function(){var colors={z:"#000001",a:"#000002",m:"#000003"};var flattened=(0,_flattenColors.flattenColors)(colors);var keys=Object.keys(flattened);(0,_vitest.expect)(keys).toEqual(["z","a","m"]);});});
|
|
1
|
+
var _vitest=require("vitest");var _flattenColors=require("./flattenColors");(0,_vitest.describe)("flattenColors",function(){(0,_vitest.it)("should handle flat color objects",function(){var colors={red:"#ff0000",blue:"#0000ff",green:"#00ff00"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({red:"#ff0000",blue:"#0000ff",green:"#00ff00"});});(0,_vitest.it)("should flatten single-level nested objects",function(){var colors={brand:{primary:"#ff6b6b",secondary:"#4ecdc4"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"brand-primary":"#ff6b6b","brand-secondary":"#4ecdc4"});});(0,_vitest.it)("should flatten multi-level nested objects",function(){var colors={brand:{light:{primary:"#ffcccc",secondary:"#ccffff"},dark:{primary:"#990000",secondary:"#006666"}}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"brand-light-primary":"#ffcccc","brand-light-secondary":"#ccffff","brand-dark-primary":"#990000","brand-dark-secondary":"#006666"});});(0,_vitest.it)("should handle mixed flat and nested objects",function(){var colors={white:"#ffffff",black:"#000000",brand:{primary:"#ff6b6b",secondary:"#4ecdc4"},accent:"#ffe66d"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({white:"#ffffff",black:"#000000","brand-primary":"#ff6b6b","brand-secondary":"#4ecdc4",accent:"#ffe66d"});});(0,_vitest.it)("should handle Tailwind-style color scale objects",function(){var colors={gray:{"50":"#f9fafb","100":"#f3f4f6","200":"#e5e7eb","500":"#6b7280","900":"#111827"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"gray-50":"#f9fafb","gray-100":"#f3f4f6","gray-200":"#e5e7eb","gray-500":"#6b7280","gray-900":"#111827"});});(0,_vitest.it)("should handle empty object",function(){(0,_vitest.expect)((0,_flattenColors.flattenColors)({})).toEqual({});});(0,_vitest.it)("should handle single color",function(){var colors={primary:"#ff0000"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({primary:"#ff0000"});});(0,_vitest.it)("should handle deeply nested objects (3+ levels)",function(){var colors={theme:{light:{brand:{primary:"#ff6b6b",secondary:"#4ecdc4"}},dark:{brand:{primary:"#990000",secondary:"#006666"}}}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"theme-light-brand-primary":"#ff6b6b","theme-light-brand-secondary":"#4ecdc4","theme-dark-brand-primary":"#990000","theme-dark-brand-secondary":"#006666"});});(0,_vitest.it)("should handle numeric keys",function(){var colors={blue:{"100":"#dbeafe","500":"#3b82f6","900":"#1e3a8a"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"blue-100":"#dbeafe","blue-500":"#3b82f6","blue-900":"#1e3a8a"});});(0,_vitest.it)("should handle keys with hyphens",function(){var colors={"brand-primary":"#ff0000","brand-secondary":{light:"#00ff00",dark:"#006600"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"brand-primary":"#ff0000","brand-secondary-light":"#00ff00","brand-secondary-dark":"#006600"});});(0,_vitest.it)("should handle uppercase and lowercase hex values",function(){var colors={red:"#FF0000",blue:"#0000ff",green:"#00Ff00"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({red:"#FF0000",blue:"#0000ff",green:"#00Ff00"});});(0,_vitest.it)("should handle 3-digit hex values",function(){var colors={red:"#f00",blue:"#00f",green:"#0f0"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({red:"#f00",blue:"#00f",green:"#0f0"});});(0,_vitest.it)("should handle 8-digit hex values (with alpha)",function(){var colors={"red-50":"#ff000080","blue-50":"#0000ff80"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"red-50":"#ff000080","blue-50":"#0000ff80"});});(0,_vitest.it)("should handle complex real-world Tailwind config",function(){var colors={transparent:"transparent",current:"currentColor",white:"#ffffff",black:"#000000",gray:{"50":"#f9fafb","100":"#f3f4f6","500":"#6b7280","900":"#111827"},brand:{primary:"#ff6b6b",secondary:"#4ecdc4",accent:{light:"#ffe66d",dark:"#ffb900"}}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({transparent:"transparent",current:"currentColor",white:"#ffffff",black:"#000000","gray-50":"#f9fafb","gray-100":"#f3f4f6","gray-500":"#6b7280","gray-900":"#111827","brand-primary":"#ff6b6b","brand-secondary":"#4ecdc4","brand-accent-light":"#ffe66d","brand-accent-dark":"#ffb900"});});(0,_vitest.it)("should not mutate input object",function(){var colors={brand:{primary:"#ff6b6b",secondary:"#4ecdc4"}};var original=JSON.parse(JSON.stringify(colors));(0,_flattenColors.flattenColors)(colors);(0,_vitest.expect)(colors).toEqual(original);});(0,_vitest.it)("should handle undefined values gracefully",function(){var colors={red:"#ff0000",blue:undefined,green:"#00ff00"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({red:"#ff0000",green:"#00ff00"});});(0,_vitest.it)("should handle special color keywords",function(){var colors={transparent:"transparent",current:"currentColor",inherit:"inherit"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({transparent:"transparent",current:"currentColor",inherit:"inherit"});});(0,_vitest.it)("should handle RGB/RGBA color values",function(){var colors={primary:"rgb(255, 0, 0)",secondary:"rgba(0, 255, 0, 0.5)"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({primary:"rgb(255, 0, 0)",secondary:"rgba(0, 255, 0, 0.5)"});});(0,_vitest.it)("should handle very deeply nested structures (stress test)",function(){var colors={level1:{level2:{level3:{level4:{level5:"#ff0000"}}}}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"level1-level2-level3-level4-level5":"#ff0000"});});(0,_vitest.it)("should handle camelCase keys",function(){var colors={brandPrimary:"#ff0000",accentColor:{lightShade:"#ffcccc",darkShade:"#cc0000"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({brandPrimary:"#ff0000","accentColor-lightShade":"#ffcccc","accentColor-darkShade":"#cc0000"});});(0,_vitest.it)("should produce consistent output",function(){var colors={brand:{primary:"#ff6b6b",secondary:"#4ecdc4"}};var result1=(0,_flattenColors.flattenColors)(colors);var result2=(0,_flattenColors.flattenColors)(colors);var result3=(0,_flattenColors.flattenColors)(colors);(0,_vitest.expect)(result1).toEqual(result2);(0,_vitest.expect)(result2).toEqual(result3);});(0,_vitest.it)("should maintain key order (insertion order)",function(){var colors={z:"#000001",a:"#000002",m:"#000003"};var flattened=(0,_flattenColors.flattenColors)(colors);var keys=Object.keys(flattened);(0,_vitest.expect)(keys).toEqual(["z","a","m"]);});(0,_vitest.it)("should handle DEFAULT key in color scale objects",function(){var colors={primary:{"50":"#eefdfd","100":"#d4f9f9","200":"#aef2f3","500":"#1bacb5","900":"#1e4f5b",DEFAULT:"#1bacb5"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({primary:"#1bacb5","primary-50":"#eefdfd","primary-100":"#d4f9f9","primary-200":"#aef2f3","primary-500":"#1bacb5","primary-900":"#1e4f5b"});});(0,_vitest.it)("should handle DEFAULT key with multiple color scales",function(){var colors={primary:{DEFAULT:"#1bacb5","500":"#1bacb5"},secondary:{DEFAULT:"#ff6b6b","500":"#ff6b6b"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({primary:"#1bacb5","primary-500":"#1bacb5",secondary:"#ff6b6b","secondary-500":"#ff6b6b"});});(0,_vitest.it)("should handle DEFAULT key in nested structures",function(){var colors={brand:{primary:{DEFAULT:"#1bacb5",light:"#d4f9f9",dark:"#0e343e"}}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"brand-primary":"#1bacb5","brand-primary-light":"#d4f9f9","brand-primary-dark":"#0e343e"});});(0,_vitest.it)("should handle DEFAULT at top level (edge case)",function(){var colors={DEFAULT:"#000000",primary:"#ff0000"};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({DEFAULT:"#000000",primary:"#ff0000"});});(0,_vitest.it)("should handle mixed DEFAULT and regular keys",function(){var colors={gray:{"50":"#f9fafb","100":"#f3f4f6",DEFAULT:"#6b7280","500":"#6b7280","900":"#111827"},white:"#ffffff",brand:{DEFAULT:"#ff6b6b",accent:"#4ecdc4"}};(0,_vitest.expect)((0,_flattenColors.flattenColors)(colors)).toEqual({"gray-50":"#f9fafb","gray-100":"#f3f4f6",gray:"#6b7280","gray-500":"#6b7280","gray-900":"#111827",white:"#ffffff",brand:"#ff6b6b","brand-accent":"#4ecdc4"});});});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mgcrea/react-native-tailwind",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Compile-time Tailwind CSS for React Native with zero runtime overhead",
|
|
5
5
|
"author": "Olivier Louvignes <olivier@mgcrea.io> (https://github.com/mgcrea)",
|
|
6
6
|
"homepage": "https://github.com/mgcrea/react-native-tailwind#readme",
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_CLASS_ATTRIBUTES,
|
|
4
|
+
buildAttributeMatchers,
|
|
5
|
+
getTargetStyleProp,
|
|
6
|
+
isAttributeSupported,
|
|
7
|
+
} from "./attributeMatchers";
|
|
8
|
+
|
|
9
|
+
describe("DEFAULT_CLASS_ATTRIBUTES", () => {
|
|
10
|
+
it("should contain standard className attributes", () => {
|
|
11
|
+
expect(DEFAULT_CLASS_ATTRIBUTES).toEqual([
|
|
12
|
+
"className",
|
|
13
|
+
"contentContainerClassName",
|
|
14
|
+
"columnWrapperClassName",
|
|
15
|
+
"ListHeaderComponentClassName",
|
|
16
|
+
"ListFooterComponentClassName",
|
|
17
|
+
]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should be a readonly array", () => {
|
|
21
|
+
// TypeScript compile-time check - if this compiles, the const assertion works
|
|
22
|
+
const _typeCheck: readonly string[] = DEFAULT_CLASS_ATTRIBUTES;
|
|
23
|
+
expect(_typeCheck).toBeDefined();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("buildAttributeMatchers", () => {
|
|
28
|
+
it("should separate exact matches from patterns", () => {
|
|
29
|
+
const attributes = ["className", "containerClassName", "*Style", "custom*"];
|
|
30
|
+
const result = buildAttributeMatchers(attributes);
|
|
31
|
+
|
|
32
|
+
// Exact matches should be in a Set
|
|
33
|
+
expect(result.exactMatches).toBeInstanceOf(Set);
|
|
34
|
+
expect(result.exactMatches.has("className")).toBe(true);
|
|
35
|
+
expect(result.exactMatches.has("containerClassName")).toBe(true);
|
|
36
|
+
expect(result.exactMatches.size).toBe(2);
|
|
37
|
+
|
|
38
|
+
// Patterns should be RegExp objects
|
|
39
|
+
expect(result.patterns).toHaveLength(2);
|
|
40
|
+
expect(result.patterns[0]).toBeInstanceOf(RegExp);
|
|
41
|
+
expect(result.patterns[1]).toBeInstanceOf(RegExp);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should handle only exact matches", () => {
|
|
45
|
+
const attributes = ["className", "customClass", "anotherClass"];
|
|
46
|
+
const result = buildAttributeMatchers(attributes);
|
|
47
|
+
|
|
48
|
+
expect(result.exactMatches.size).toBe(3);
|
|
49
|
+
expect(result.patterns).toHaveLength(0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should handle only patterns", () => {
|
|
53
|
+
const attributes = ["*ClassName", "container*", "*Style*"];
|
|
54
|
+
const result = buildAttributeMatchers(attributes);
|
|
55
|
+
|
|
56
|
+
expect(result.exactMatches.size).toBe(0);
|
|
57
|
+
expect(result.patterns).toHaveLength(3);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should handle empty array", () => {
|
|
61
|
+
const result = buildAttributeMatchers([]);
|
|
62
|
+
|
|
63
|
+
expect(result.exactMatches.size).toBe(0);
|
|
64
|
+
expect(result.patterns).toHaveLength(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should convert glob patterns to regex correctly", () => {
|
|
68
|
+
const attributes = ["*ClassName", "container*", "*custom*"];
|
|
69
|
+
const result = buildAttributeMatchers(attributes);
|
|
70
|
+
|
|
71
|
+
// Test that patterns match expected strings
|
|
72
|
+
expect(result.patterns[0]?.test("myClassName")).toBe(true);
|
|
73
|
+
expect(result.patterns[0]?.test("fooClassName")).toBe(true);
|
|
74
|
+
expect(result.patterns[0]?.test("className")).toBe(false); // Doesn't start with anything
|
|
75
|
+
|
|
76
|
+
expect(result.patterns[1]?.test("containerStyle")).toBe(true);
|
|
77
|
+
expect(result.patterns[1]?.test("containerFoo")).toBe(true);
|
|
78
|
+
expect(result.patterns[1]?.test("myContainer")).toBe(false);
|
|
79
|
+
|
|
80
|
+
expect(result.patterns[2]?.test("mycustomattr")).toBe(true);
|
|
81
|
+
expect(result.patterns[2]?.test("customattr")).toBe(true);
|
|
82
|
+
expect(result.patterns[2]?.test("attrcustom")).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should handle multiple wildcards in same pattern", () => {
|
|
86
|
+
const attributes = ["*custom*Class*"];
|
|
87
|
+
const result = buildAttributeMatchers(attributes);
|
|
88
|
+
|
|
89
|
+
expect(result.patterns[0]?.test("mycustomFooClassName")).toBe(true);
|
|
90
|
+
expect(result.patterns[0]?.test("customClassName")).toBe(true);
|
|
91
|
+
expect(result.patterns[0]?.test("foocustombarClassbaz")).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("isAttributeSupported", () => {
|
|
96
|
+
it("should match exact attributes", () => {
|
|
97
|
+
const { exactMatches, patterns } = buildAttributeMatchers(["className", "customClass"]);
|
|
98
|
+
|
|
99
|
+
expect(isAttributeSupported("className", exactMatches, patterns)).toBe(true);
|
|
100
|
+
expect(isAttributeSupported("customClass", exactMatches, patterns)).toBe(true);
|
|
101
|
+
expect(isAttributeSupported("otherClass", exactMatches, patterns)).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should match pattern-based attributes", () => {
|
|
105
|
+
const { exactMatches, patterns } = buildAttributeMatchers(["*ClassName", "container*"]);
|
|
106
|
+
|
|
107
|
+
expect(isAttributeSupported("myClassName", exactMatches, patterns)).toBe(true);
|
|
108
|
+
expect(isAttributeSupported("fooClassName", exactMatches, patterns)).toBe(true);
|
|
109
|
+
expect(isAttributeSupported("containerStyle", exactMatches, patterns)).toBe(true);
|
|
110
|
+
expect(isAttributeSupported("containerFoo", exactMatches, patterns)).toBe(true);
|
|
111
|
+
expect(isAttributeSupported("randomAttr", exactMatches, patterns)).toBe(false);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("should match both exact and pattern attributes", () => {
|
|
115
|
+
const { exactMatches, patterns } = buildAttributeMatchers(["className", "*Style"]);
|
|
116
|
+
|
|
117
|
+
// Exact match
|
|
118
|
+
expect(isAttributeSupported("className", exactMatches, patterns)).toBe(true);
|
|
119
|
+
|
|
120
|
+
// Pattern match
|
|
121
|
+
expect(isAttributeSupported("containerStyle", exactMatches, patterns)).toBe(true);
|
|
122
|
+
expect(isAttributeSupported("customStyle", exactMatches, patterns)).toBe(true);
|
|
123
|
+
|
|
124
|
+
// No match
|
|
125
|
+
expect(isAttributeSupported("otherAttr", exactMatches, patterns)).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should prioritize exact matches (performance)", () => {
|
|
129
|
+
// Even if a pattern would match, exact match should work
|
|
130
|
+
const { exactMatches, patterns } = buildAttributeMatchers(["className", "*Name"]);
|
|
131
|
+
|
|
132
|
+
expect(isAttributeSupported("className", exactMatches, patterns)).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should handle empty matchers", () => {
|
|
136
|
+
const { exactMatches, patterns } = buildAttributeMatchers([]);
|
|
137
|
+
|
|
138
|
+
expect(isAttributeSupported("className", exactMatches, patterns)).toBe(false);
|
|
139
|
+
expect(isAttributeSupported("anyAttr", exactMatches, patterns)).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should be case-sensitive", () => {
|
|
143
|
+
const { exactMatches, patterns } = buildAttributeMatchers(["className"]);
|
|
144
|
+
|
|
145
|
+
expect(isAttributeSupported("className", exactMatches, patterns)).toBe(true);
|
|
146
|
+
expect(isAttributeSupported("ClassName", exactMatches, patterns)).toBe(false);
|
|
147
|
+
expect(isAttributeSupported("classname", exactMatches, patterns)).toBe(false);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("should match default React Native FlatList attributes", () => {
|
|
151
|
+
const { exactMatches, patterns } = buildAttributeMatchers([...DEFAULT_CLASS_ATTRIBUTES]);
|
|
152
|
+
|
|
153
|
+
expect(isAttributeSupported("className", exactMatches, patterns)).toBe(true);
|
|
154
|
+
expect(isAttributeSupported("contentContainerClassName", exactMatches, patterns)).toBe(true);
|
|
155
|
+
expect(isAttributeSupported("columnWrapperClassName", exactMatches, patterns)).toBe(true);
|
|
156
|
+
expect(isAttributeSupported("ListHeaderComponentClassName", exactMatches, patterns)).toBe(true);
|
|
157
|
+
expect(isAttributeSupported("ListFooterComponentClassName", exactMatches, patterns)).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should work with complex glob patterns", () => {
|
|
161
|
+
const { exactMatches, patterns } = buildAttributeMatchers(["*Container*Class*"]);
|
|
162
|
+
|
|
163
|
+
expect(isAttributeSupported("myContainerFooClassName", exactMatches, patterns)).toBe(true);
|
|
164
|
+
expect(isAttributeSupported("ContainerClassName", exactMatches, patterns)).toBe(true);
|
|
165
|
+
expect(isAttributeSupported("fooContainerBarClassBaz", exactMatches, patterns)).toBe(true);
|
|
166
|
+
expect(isAttributeSupported("ContainerStyle", exactMatches, patterns)).toBe(false);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe("getTargetStyleProp", () => {
|
|
171
|
+
it("should convert className to style", () => {
|
|
172
|
+
expect(getTargetStyleProp("className")).toBe("style");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("should convert *ClassName to *Style", () => {
|
|
176
|
+
expect(getTargetStyleProp("contentContainerClassName")).toBe("contentContainerStyle");
|
|
177
|
+
expect(getTargetStyleProp("columnWrapperClassName")).toBe("columnWrapperStyle");
|
|
178
|
+
expect(getTargetStyleProp("ListHeaderComponentClassName")).toBe("ListHeaderComponentStyle");
|
|
179
|
+
expect(getTargetStyleProp("ListFooterComponentClassName")).toBe("ListFooterComponentStyle");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should handle custom className attributes", () => {
|
|
183
|
+
expect(getTargetStyleProp("customClassName")).toBe("customStyle");
|
|
184
|
+
expect(getTargetStyleProp("myCustomClassName")).toBe("myCustomStyle");
|
|
185
|
+
expect(getTargetStyleProp("fooBarClassName")).toBe("fooBarStyle");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("should return style for attributes not ending in ClassName", () => {
|
|
189
|
+
expect(getTargetStyleProp("customClass")).toBe("style");
|
|
190
|
+
expect(getTargetStyleProp("class")).toBe("style");
|
|
191
|
+
expect(getTargetStyleProp("myAttr")).toBe("style");
|
|
192
|
+
expect(getTargetStyleProp("")).toBe("style");
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("should handle edge cases", () => {
|
|
196
|
+
// Attribute IS exactly "ClassName"
|
|
197
|
+
expect(getTargetStyleProp("ClassName")).toBe("Style");
|
|
198
|
+
|
|
199
|
+
// Multiple "ClassName" occurrences (only last one replaced)
|
|
200
|
+
expect(getTargetStyleProp("classNameClassName")).toBe("classNameStyle");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should be case-sensitive", () => {
|
|
204
|
+
expect(getTargetStyleProp("classname")).toBe("style");
|
|
205
|
+
expect(getTargetStyleProp("CLASSNAME")).toBe("style");
|
|
206
|
+
expect(getTargetStyleProp("classNamee")).toBe("style");
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("should handle all default attributes correctly", () => {
|
|
210
|
+
const expectedMappings = [
|
|
211
|
+
["className", "style"],
|
|
212
|
+
["contentContainerClassName", "contentContainerStyle"],
|
|
213
|
+
["columnWrapperClassName", "columnWrapperStyle"],
|
|
214
|
+
["ListHeaderComponentClassName", "ListHeaderComponentStyle"],
|
|
215
|
+
["ListFooterComponentClassName", "ListFooterComponentStyle"],
|
|
216
|
+
] as const;
|
|
217
|
+
|
|
218
|
+
for (const [input, expected] of expectedMappings) {
|
|
219
|
+
expect(getTargetStyleProp(input)).toBe(expected);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe("Integration - Real-world scenarios", () => {
|
|
225
|
+
it("should handle FlatList with multiple className attributes", () => {
|
|
226
|
+
const { exactMatches, patterns } = buildAttributeMatchers([...DEFAULT_CLASS_ATTRIBUTES]);
|
|
227
|
+
|
|
228
|
+
// All FlatList className props should be supported
|
|
229
|
+
const flatListAttrs = [
|
|
230
|
+
["className", "style"],
|
|
231
|
+
["contentContainerClassName", "contentContainerStyle"],
|
|
232
|
+
["columnWrapperClassName", "columnWrapperStyle"],
|
|
233
|
+
["ListHeaderComponentClassName", "ListHeaderComponentStyle"],
|
|
234
|
+
["ListFooterComponentClassName", "ListFooterComponentStyle"],
|
|
235
|
+
] as const;
|
|
236
|
+
|
|
237
|
+
for (const [attr, expectedStyle] of flatListAttrs) {
|
|
238
|
+
expect(isAttributeSupported(attr, exactMatches, patterns)).toBe(true);
|
|
239
|
+
expect(getTargetStyleProp(attr)).toBe(expectedStyle);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("should support custom wildcard pattern for all *ClassName attributes", () => {
|
|
244
|
+
const { exactMatches, patterns } = buildAttributeMatchers(["*ClassName"]);
|
|
245
|
+
|
|
246
|
+
// Should match any attribute ending in ClassName (with at least one char before)
|
|
247
|
+
// Note: The regex ^.*ClassName$ requires at least one character due to .*
|
|
248
|
+
expect(isAttributeSupported("myCustomClassName", exactMatches, patterns)).toBe(true);
|
|
249
|
+
expect(isAttributeSupported("fooBarBazClassName", exactMatches, patterns)).toBe(true);
|
|
250
|
+
expect(isAttributeSupported("xClassName", exactMatches, patterns)).toBe(true);
|
|
251
|
+
|
|
252
|
+
// Edge case: bare "className" needs at least one char before it for .* to match
|
|
253
|
+
// If you want to include "className", add it explicitly or use a different pattern
|
|
254
|
+
expect(isAttributeSupported("className", exactMatches, patterns)).toBe(false);
|
|
255
|
+
|
|
256
|
+
// Should convert to corresponding style prop
|
|
257
|
+
expect(getTargetStyleProp("myCustomClassName")).toBe("myCustomStyle");
|
|
258
|
+
|
|
259
|
+
// Should not match non-className attributes
|
|
260
|
+
expect(isAttributeSupported("myCustomClass", exactMatches, patterns)).toBe(false);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("should support combining exact matches with patterns", () => {
|
|
264
|
+
const { exactMatches, patterns } = buildAttributeMatchers([
|
|
265
|
+
"className",
|
|
266
|
+
"customClass",
|
|
267
|
+
"*ClassName",
|
|
268
|
+
"container*",
|
|
269
|
+
]);
|
|
270
|
+
|
|
271
|
+
// Exact matches
|
|
272
|
+
expect(isAttributeSupported("className", exactMatches, patterns)).toBe(true);
|
|
273
|
+
expect(isAttributeSupported("customClass", exactMatches, patterns)).toBe(true);
|
|
274
|
+
|
|
275
|
+
// Pattern matches
|
|
276
|
+
expect(isAttributeSupported("myClassName", exactMatches, patterns)).toBe(true);
|
|
277
|
+
expect(isAttributeSupported("containerStyle", exactMatches, patterns)).toBe(true);
|
|
278
|
+
|
|
279
|
+
// No matches
|
|
280
|
+
expect(isAttributeSupported("randomAttr", exactMatches, patterns)).toBe(false);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it("should handle empty configuration gracefully", () => {
|
|
284
|
+
const { exactMatches, patterns } = buildAttributeMatchers([]);
|
|
285
|
+
|
|
286
|
+
// Nothing should be supported
|
|
287
|
+
expect(isAttributeSupported("className", exactMatches, patterns)).toBe(false);
|
|
288
|
+
expect(isAttributeSupported("anything", exactMatches, patterns)).toBe(false);
|
|
289
|
+
|
|
290
|
+
// getTargetStyleProp should still work
|
|
291
|
+
expect(getTargetStyleProp("className")).toBe("style");
|
|
292
|
+
expect(getTargetStyleProp("customClassName")).toBe("customStyle");
|
|
293
|
+
});
|
|
294
|
+
});
|