Skip to content

Commit

Permalink
Memoize hash function
Browse files Browse the repository at this point in the history
  • Loading branch information
zoontek committed Jan 13, 2025
1 parent 7edfaab commit 917f645
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 42 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@swan-io/css",
"version": "0.1.1",
"version": "0.1.2",
"license": "MIT",
"description": "A lightweight and performant atomic CSS-in-JS library",
"author": "Mathieu Acthernoene <[email protected]>",
Expand Down
4 changes: 4 additions & 0 deletions src/hash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import hashRaw from "@emotion/hash";
import { memoizeOne } from "./utils";

export const hash = memoizeOne(hashRaw);
13 changes: 5 additions & 8 deletions src/hyphenateName.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
// https://github.com/facebook/react/blob/v19.0.0/packages/react-dom-bindings/src/shared/hyphenateStyleName.js

const uppercasePattern = /([A-Z])/g;
const hyphenateNameCache: Record<string, string> = {};
import { memoizeOne } from "./utils";

export const hyphenateName = (name: string): string => {
hyphenateNameCache[name] ??= name
.replace(uppercasePattern, "-$1")
.toLowerCase();
const uppercasePattern = /([A-Z])/g;

return hyphenateNameCache[name];
};
export const hyphenateName = memoizeOne((value: string): string =>
value.replace(uppercasePattern, "-$1").toLowerCase(),
);
49 changes: 21 additions & 28 deletions src/normalizeValue.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import normalizeColor from "@react-native/normalize-colors";
import { Property } from "./types";

const normalizeValueCache: Record<string, string> = {};
import { memoizeTwo } from "./utils";

/**
* CSS properties which accept numbers but are not in units of "px"
Expand Down Expand Up @@ -64,37 +63,31 @@ const isWebColor = (color: string): boolean =>
color === "inherit" ||
color.indexOf("var(") === 0;

export const normalizeValue = (
value: string | number | undefined,
property: string,
): string | undefined => {
if (typeof value === "number") {
return unitlessProperties.has(property) ? String(value) : `${value}px`;
}

if (colorProperties.has(property)) {
if (value == null || isWebColor(value)) {
return value;
export const normalizeValue = memoizeTwo(
(key: string, value: string | number): string => {
if (typeof value === "number") {
return unitlessProperties.has(key) ? String(value) : `${value}px`;
}

if (normalizeValueCache[value] != null) {
return normalizeValueCache[value];
}
if (colorProperties.has(key)) {
if (isWebColor(value)) {
return value;
}

const normalizedColor = normalizeColor(value);
const normalizedColor = normalizeColor(value);

if (normalizedColor != null) {
const int = ((normalizedColor << 24) | (normalizedColor >>> 8)) >>> 0;
if (normalizedColor != null) {
const int = ((normalizedColor << 24) | (normalizedColor >>> 8)) >>> 0;

const r = (int >> 16) & 255;
const g = (int >> 8) & 255;
const b = int & 255;
const a = ((int >> 24) & 255) / 255;
const r = (int >> 16) & 255;
const g = (int >> 8) & 255;
const b = int & 255;
const a = ((int >> 24) & 255) / 255;

normalizeValueCache[value] = `rgba(${r}, ${g}, ${b}, ${a.toFixed(2)})`;
return normalizeValueCache[value];
return `rgba(${r}, ${g}, ${b}, ${a.toFixed(2)})`;
}
}
}

return value;
};
return value;
},
);
10 changes: 5 additions & 5 deletions src/sheet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import hash from "@emotion/hash";
import { hash } from "./hash";
import { hyphenateName } from "./hyphenateName";
import { normalizeValue } from "./normalizeValue";
import { ClassNames, Keyframes, Nestable, Style } from "./types";
Expand Down Expand Up @@ -53,15 +53,15 @@ const insertRule = (sheet: CSSMediaRule, rule: string): void => {
}
};

const stringifyRule = (name: string, value: string | number): string => {
if (name === "appearance") {
const stringifyRule = (key: string, value: string | number): string => {
if (key === "appearance") {
return `-webkit-appearance: ${value}; appearance: ${value};`;
}
if (name === "lineClamp") {
if (key === "lineClamp") {
return `-webkit-line-clamp: ${value}; line-clamp: ${value};`;
}

return `${hyphenateName(name)}: ${normalizeValue(value, name)};`;
return `${hyphenateName(key)}: ${normalizeValue(key, value)};`;
};

const extractClassNames = (items: ClassNames, acc: string[]): string[] => {
Expand Down
28 changes: 28 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,31 @@ export const forEach = <T extends Record<PropertyKey, unknown>>(
}
}
};

export const memoizeOne = <T>(fn: (value: string) => T) => {
const cache: Record<string, T> = Object.create(null);

return (value: string): T => {
if (cache[value] === undefined) {
cache[value] = fn(value);
}

return cache[value];
};
};

export const memoizeTwo = <T>(
fn: (key: string, value: string | number) => T,
) => {
const cache: Record<string, T> = Object.create(null);

return (key: string, value: string | number): T => {
const cacheKey = key + ":" + value;

if (cache[cacheKey] === undefined) {
cache[cacheKey] = fn(key, value);
}

return cache[cacheKey];
};
};

0 comments on commit 917f645

Please sign in to comment.