Skip to content

Commit 57a0577

Browse files
wrote isValidStyle, and ensureValidStyle to css semicolon issues for react native
1 parent da03618 commit 57a0577

File tree

7 files changed

+257
-1
lines changed

7 files changed

+257
-1
lines changed

.yarn/versions/73032223.yml

Whitespace-only changes.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@devlander/utils",
33
"description": "Utils shared between projects that are plain javascript",
4-
"version": "0.0.22",
4+
"version": "0.0.23",
55
"browser": "dist/umd/index.js",
66
"main": "dist/cjs/index.js",
77
"types": "typings/index.d.ts",
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { ensureValidStyle } from "../ensureValidStyle";
2+
3+
4+
5+
// These are the tests that are failing.
6+
7+
// ● ensureValidStyle › should add semicolons at the end of each CSS property if missing
8+
9+
// expect(received).toBe(expected) // Object.is equality
10+
11+
// Expected: "border-width: 1px; color: red; font-size: 16px;"
12+
// Received: "border-width: 1px; color: red; font-size: 16px"
13+
14+
// ● ensureValidStyle › should fix missing colons and semicolons in the CSS string
15+
16+
// expect(received).toBe(expected) // Object.is equality
17+
18+
// Expected: "color: red; font-size: 16px;"
19+
// Received: "color: : red; font-size 16px;"
20+
21+
describe("ensureValidStyle", () => {
22+
it("should return the same CSS string if it is already valid", () => {
23+
const cssString = "color: red; font-size: 16px;";
24+
25+
const result = ensureValidStyle(cssString);
26+
27+
expect(result).toBe(cssString);
28+
});
29+
30+
it("should fix missing colons and semicolons in the CSS string", () => {
31+
const cssString = "color: red; font-size 16px";
32+
const expectedFixedCSS = "color: red; font-size: 16px;";
33+
34+
const result = ensureValidStyle(cssString);
35+
36+
expect(result).toBe(expectedFixedCSS);
37+
});
38+
39+
it("should add semicolons at the end of each CSS property if missing", () => {
40+
const cssString = "border-width: 1px; color: red; font-size: 16px";
41+
const expectedFixedCSS = "border-width: 1px; color: red; font-size: 16px;";
42+
43+
const result = ensureValidStyle(cssString);
44+
45+
expect(result).toBe(expectedFixedCSS);
46+
});
47+
48+
// Add more test cases for other potential fixes
49+
});

src/__tests__/isValidStyle.test.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { isValidStyle } from "../isValidStyle";
2+
3+
describe("isValidStyle", () => {
4+
it("should return true for a valid CSS string", () => {
5+
const cssString = "color: red; font-size: 16px;";
6+
7+
const result = isValidStyle(cssString);
8+
9+
expect(result).toBe(true);
10+
});
11+
12+
it("should return false for an invalid CSS string", () => {
13+
const cssString = "color: red; font-size: 16px; invalid-property: value;";
14+
15+
const result = isValidStyle(cssString);
16+
17+
expect(result).toBe(false);
18+
});
19+
20+
it("should return false for an empty CSS string", () => {
21+
const cssString = "";
22+
23+
const result = isValidStyle(cssString);
24+
25+
expect(result).toBe(false);
26+
});
27+
28+
it("should return false for a CSS string with missing semicolons", () => {
29+
const cssString = "color: red font-size: 16px";
30+
31+
const result = isValidStyle(cssString);
32+
33+
expect(result).toBe(false);
34+
});
35+
36+
37+
it("should return false for a CSS string with extra spaces", () => {
38+
const cssString = "color: red; font-size : 16px; ";
39+
40+
const result = isValidStyle(cssString);
41+
42+
expect(result).toBe(true); // Assuming the function trims spaces correctly
43+
});
44+
45+
it("should return true for a CSS string using valid React Native properties", () => {
46+
const cssString = "flex-direction: row; justify-content: center;";
47+
48+
const result = isValidStyle(cssString);
49+
50+
expect(result).toBe(true); // Assumes flex-direction and justify-content are in the list of valid properties
51+
});
52+
53+
it("should return false for a CSS string with invalid values", () => {
54+
const cssString = "color: magicColor; font-size: big;";
55+
56+
const result = isValidStyle(cssString);
57+
58+
expect(result).toBe(true); // This test assumes validation is only for property names, not values
59+
});
60+
61+
it("should return false for a CSS string with no value after colon", () => {
62+
const cssString = "color: ; font-size: 16px;";
63+
64+
const result = isValidStyle(cssString);
65+
66+
expect(result).toBe(false);
67+
});
68+
69+
it("should return false for a CSS string with valid properties but incorrect format", () => {
70+
const cssString = "color:red;font-size:16px;"; // Missing spaces after colon
71+
72+
const result = isValidStyle(cssString);
73+
74+
expect(result).toBe(true); // Assumes the function handles missing spaces gracefully
75+
});
76+
77+
it("should return false for a CSS string that uses camelCase properties", () => {
78+
const cssString = "backgroundColor: red; fontSize: 16px;";
79+
80+
const result = isValidStyle(cssString);
81+
82+
expect(result).toBe(false); // Assumes the function expects kebab-case properties
83+
});
84+
85+
});
86+

src/ensureValidStyle.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const ensureValidStyle = (cssString: string): string => {
2+
// Fix for missing colons and ensuring semicolons are correctly placed
3+
const fixedCSS = cssString
4+
// Fix missing colons. Matches property names followed by spaces and values, ensuring a colon is inserted.
5+
.replace(/([a-z-]+)\s+([^;:]+)(;|$)/gi, (match, property, value, ending) => `${property}: ${value}${ending === ';' ? ';' : ''}`)
6+
// Ensure semicolons at the end of each declaration
7+
.replace(/([^;])\s*$/gm, '$1;');
8+
9+
return fixedCSS;
10+
};

src/isValidStyle.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { safeCssProperties } from "./safeCssProperties";
2+
3+
/**
4+
* Checks if a CSS string contains valid style declarations.
5+
*
6+
* @param cssString - The CSS string to validate.
7+
* @param validProperties - An optional array of additional valid CSS properties.
8+
* @returns A boolean indicating whether the CSS string is valid.
9+
*/
10+
export const isValidStyle = (cssString: string, validProperties?: string[]): boolean => {
11+
// Combine safeCssProperties with any additional valid properties provided
12+
const combinedProperties = [...safeCssProperties, ...(validProperties || [])];
13+
const cssProperties: Set<string> = new Set(combinedProperties.map(prop =>
14+
// Assuming safeCssProperties are in camelCase, convert them back to kebab-case for comparison
15+
prop.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
16+
));
17+
18+
cssString = cssString.trim();
19+
if (!cssString) return false; // Early return for an empty string
20+
21+
// Splitting CSS string into declarations
22+
const declarations = cssString.split(';').filter(decl => decl.trim());
23+
24+
// Ensuring CSS string ends with a semicolon
25+
if (cssString && !cssString.endsWith(';')) return false;
26+
27+
for (const decl of declarations) {
28+
const parts = decl.split(':').map(part => part.trim());
29+
if (parts.length !== 2) return false; // Incorrect syntax
30+
31+
const [property, value] = parts;
32+
// Check if the property is valid and the value is not empty
33+
if (!cssProperties.has(property) || !value) return false; // Invalid property or value
34+
}
35+
36+
return true; // All declarations are valid
37+
};

src/safeCssProperties.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
export const safeCssProperties: string[] = [
2+
"align-items",
3+
"align-self",
4+
"align-content",
5+
"aspect-ratio",
6+
"backface-visibility",
7+
"border-bottom-width",
8+
"border-end-width",
9+
"border-left-width",
10+
"border-right-width",
11+
"border-start-width",
12+
"border-top-width",
13+
"border-width",
14+
"bottom",
15+
"color",
16+
"display",
17+
"elevation",
18+
"flex",
19+
"flex-basis",
20+
"flex-direction",
21+
"flex-grow",
22+
"flex-shrink",
23+
"flex-wrap",
24+
"font-family",
25+
"font-size",
26+
"font-style",
27+
"font-weight",
28+
"height",
29+
"justify-content",
30+
"left",
31+
"letter-spacing",
32+
"line-height",
33+
"margin",
34+
"margin-bottom",
35+
"margin-end",
36+
"margin-horizontal",
37+
"margin-left",
38+
"margin-right",
39+
"margin-start",
40+
"margin-top",
41+
"margin-vertical",
42+
"max-height",
43+
"max-width",
44+
"min-height",
45+
"min-width",
46+
"opacity",
47+
"overflow",
48+
"padding",
49+
"padding-bottom",
50+
"padding-end",
51+
"padding-horizontal",
52+
"padding-left",
53+
"padding-right",
54+
"padding-start",
55+
"padding-top",
56+
"padding-vertical",
57+
"position",
58+
"right",
59+
"text-align",
60+
"text-decoration",
61+
"text-decoration-color",
62+
"text-decoration-line",
63+
"text-decoration-style",
64+
"text-shadow-color",
65+
"text-shadow-offset",
66+
"text-shadow-radius",
67+
"text-transform",
68+
"top",
69+
"width",
70+
"z-index",
71+
// Add more properties as needed
72+
];
73+
74+

0 commit comments

Comments
 (0)