@ogxjs/core 0.1.2 → 0.2.0-alpha.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/cache/hash.d.ts +66 -0
- package/dist/cache/hash.d.ts.map +1 -0
- package/dist/cache/hash.js +161 -0
- package/dist/cache/index.d.ts +10 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +12 -0
- package/dist/cache/lru.d.ts +122 -0
- package/dist/cache/lru.d.ts.map +1 -0
- package/dist/cache/lru.js +269 -0
- package/dist/cache/snapshot.d.ts +116 -0
- package/dist/cache/snapshot.d.ts.map +1 -0
- package/dist/cache/snapshot.js +204 -0
- package/dist/cache.d.ts +2 -2
- package/dist/cache.js +2 -2
- package/dist/css.d.ts +19 -6
- package/dist/css.d.ts.map +1 -1
- package/dist/index.d.ts +17 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -9
- package/dist/ogx.js +2 -2
- package/dist/perf/index.d.ts +8 -0
- package/dist/perf/index.d.ts.map +1 -0
- package/dist/perf/index.js +7 -0
- package/dist/perf/timing.d.ts +160 -0
- package/dist/perf/timing.d.ts.map +1 -0
- package/dist/perf/timing.js +305 -0
- package/dist/presets/blog.js +1 -1
- package/dist/presets/docs.d.ts +2 -0
- package/dist/presets/docs.d.ts.map +1 -1
- package/dist/presets/docs.js +26 -23
- package/dist/presets/minimal.d.ts +2 -0
- package/dist/presets/minimal.d.ts.map +1 -1
- package/dist/presets/minimal.js +8 -16
- package/dist/presets/social.d.ts +2 -0
- package/dist/presets/social.d.ts.map +1 -1
- package/dist/presets/social.js +28 -18
- package/dist/render-png.d.ts.map +1 -1
- package/dist/render-png.js +9 -1
- package/dist/render-svg.d.ts.map +1 -1
- package/dist/render-svg.js +11 -1
- package/dist/tailwind/class-cache.d.ts +141 -0
- package/dist/tailwind/class-cache.d.ts.map +1 -0
- package/dist/tailwind/class-cache.js +212 -0
- package/dist/tailwind/index.d.ts +14 -1
- package/dist/tailwind/index.d.ts.map +1 -1
- package/dist/tailwind/index.js +15 -1
- package/dist/tailwind/lookup-tables.d.ts +30 -0
- package/dist/tailwind/lookup-tables.d.ts.map +1 -0
- package/dist/tailwind/lookup-tables.js +427 -0
- package/dist/tailwind/parser-v2.d.ts +54 -0
- package/dist/tailwind/parser-v2.d.ts.map +1 -0
- package/dist/tailwind/parser-v2.js +250 -0
- package/dist/tailwind/parser.d.ts +1 -0
- package/dist/tailwind/parser.d.ts.map +1 -1
- package/dist/tailwind/parser.js +1 -0
- package/dist/tailwind/prefix-handlers.d.ts +68 -0
- package/dist/tailwind/prefix-handlers.d.ts.map +1 -0
- package/dist/tailwind/prefix-handlers.js +931 -0
- package/package.json +17 -2
package/dist/presets/social.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h1, img, row, span, stack } from "../builder";
|
|
2
2
|
/**
|
|
3
3
|
* Social preset - card-style for social media
|
|
4
4
|
*/
|
|
5
5
|
export const socialPreset = (props) => {
|
|
6
|
-
const { title, handle, avatar, brand, logo, gradient = "to-br", fromColor = "oklch(65% 0.25 260)", // Vibrant Indigo-ish
|
|
6
|
+
const { title, handle, avatar, brand, logo, colorScheme = "dark", gradient = "to-br", fromColor = "oklch(65% 0.25 260)", // Vibrant Indigo-ish
|
|
7
7
|
toColor = "oklch(60% 0.3 300)", // Vibrant Purple-ish
|
|
8
8
|
slots = {}, } = props;
|
|
9
|
+
const isDark = colorScheme === "dark";
|
|
9
10
|
const gradientStyle = `linear-gradient(${gradient === "to-r"
|
|
10
11
|
? "90deg"
|
|
11
12
|
: gradient === "to-br"
|
|
@@ -14,53 +15,62 @@ export const socialPreset = (props) => {
|
|
|
14
15
|
? "180deg"
|
|
15
16
|
: "225deg"}, ${fromColor}, ${toColor})`;
|
|
16
17
|
return stack(["w-full", "h-full", "p-20", "relative", "overflow-hidden"], [
|
|
17
|
-
//
|
|
18
|
-
absolute("", null, { style: { backgroundImage: gradientStyle } }),
|
|
19
|
-
// Subtle Background Texture (Grain/Noise-like mesh)
|
|
20
|
-
absolute(["inset-0 opacity-20", "bg-grid-white/5-32"]),
|
|
21
|
-
absolute(["bg-grain/15"]), // Quality Boost: Dithering
|
|
22
|
-
// Content Layout
|
|
18
|
+
// Content Layout (background applied on container to avoid extra layers)
|
|
23
19
|
stack("flex-1 justify-between relative", [
|
|
24
20
|
// Header
|
|
25
21
|
slots.header ??
|
|
26
22
|
row("items-center justify-between", [
|
|
27
23
|
row("items-center gap-4", [
|
|
28
|
-
logo
|
|
24
|
+
logo
|
|
25
|
+
? img(logo, [
|
|
26
|
+
"w-12 h-12 rounded-xl shadow-lg",
|
|
27
|
+
isDark ? "bg-zinc-950" : "bg-white border border-zinc-200",
|
|
28
|
+
])
|
|
29
|
+
: null,
|
|
29
30
|
brand
|
|
30
|
-
? span([
|
|
31
|
+
? span([
|
|
32
|
+
"text-2xl font-black tracking-tighter",
|
|
33
|
+
isDark ? "text-white" : "text-zinc-950",
|
|
34
|
+
], brand.toUpperCase())
|
|
31
35
|
: null,
|
|
32
36
|
]),
|
|
33
37
|
// Subtle platform indicator
|
|
34
|
-
span([
|
|
38
|
+
span([
|
|
39
|
+
isDark ? "text-white/30" : "text-black/30",
|
|
40
|
+
"text-xs font-bold tracking-widest",
|
|
41
|
+
], "SOCIAL CARD"),
|
|
35
42
|
]),
|
|
36
43
|
// Main content
|
|
37
44
|
stack("gap-6 overflow-hidden", [
|
|
38
45
|
h1([
|
|
39
46
|
"text-7xl",
|
|
40
47
|
"font-black",
|
|
41
|
-
"text-white",
|
|
48
|
+
isDark ? "text-white" : "text-zinc-950",
|
|
42
49
|
"leading-[1.05]",
|
|
43
|
-
"tracking-tight",
|
|
50
|
+
"tracking-tight",
|
|
44
51
|
], title),
|
|
45
52
|
]),
|
|
46
53
|
// Footer with user info (Clean Glass Badge)
|
|
47
54
|
slots.footer ??
|
|
48
55
|
(handle || avatar
|
|
49
56
|
? row([
|
|
50
|
-
"items-center gap-4 p-3 pr-6 rounded-full self-start shadow-
|
|
51
|
-
|
|
57
|
+
"items-center gap-4 p-3 pr-6 rounded-full self-start shadow-lg",
|
|
58
|
+
isDark
|
|
59
|
+
? "bg-black/20 border border-white/20"
|
|
60
|
+
: "bg-white/40 border border-black/10",
|
|
52
61
|
], [
|
|
53
62
|
avatar
|
|
54
63
|
? img(avatar, "w-10 h-10 rounded-full border border-white/20 shadow-sm")
|
|
55
64
|
: null,
|
|
56
65
|
handle
|
|
57
66
|
? span([
|
|
58
|
-
"text-xl font-bold
|
|
59
|
-
"
|
|
67
|
+
"text-xl font-bold tracking-tight",
|
|
68
|
+
isDark ? "text-white/90" : "text-zinc-900/90",
|
|
69
|
+
"truncate",
|
|
60
70
|
], handle)
|
|
61
71
|
: null,
|
|
62
72
|
])
|
|
63
73
|
: null),
|
|
64
74
|
]),
|
|
65
|
-
]);
|
|
75
|
+
], { style: { backgroundImage: gradientStyle } });
|
|
66
76
|
};
|
package/dist/render-png.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-png.d.ts","sourceRoot":"","sources":["../src/render-png.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEzD;;;GAGG;AACH,wBAAsB,MAAM,CAC3B,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,aAAkB,GACzB,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"render-png.d.ts","sourceRoot":"","sources":["../src/render-png.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEzD;;;GAGG;AACH,wBAAsB,MAAM,CAC3B,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,aAAkB,GACzB,OAAO,CAAC,UAAU,CAAC,CA8BrB"}
|
package/dist/render-png.js
CHANGED
|
@@ -4,7 +4,10 @@ import { renderToSVG } from "./render-svg";
|
|
|
4
4
|
* Node.js only: uses @resvg/resvg-js for SVG → PNG conversion
|
|
5
5
|
*/
|
|
6
6
|
export async function render(element, options = {}) {
|
|
7
|
+
const profile = process.env.OGX_PROFILE === "1";
|
|
8
|
+
const tStart = profile ? performance.now() : 0;
|
|
7
9
|
const svg = await renderToSVG(element, options);
|
|
10
|
+
const tAfterSvg = profile ? performance.now() : 0;
|
|
8
11
|
const width = options.width ?? 1200;
|
|
9
12
|
const resvgPkg = "@resvg/resvg-js";
|
|
10
13
|
const { Resvg } = await import(resvgPkg);
|
|
@@ -15,5 +18,10 @@ export async function render(element, options = {}) {
|
|
|
15
18
|
},
|
|
16
19
|
});
|
|
17
20
|
const pngData = resvg.render();
|
|
18
|
-
|
|
21
|
+
const result = pngData.asPng();
|
|
22
|
+
if (profile) {
|
|
23
|
+
const tEnd = performance.now();
|
|
24
|
+
console.log(`[OGX PROFILE] render png: svg=${(tAfterSvg - tStart).toFixed(2)}ms resvg=${(tEnd - tAfterSvg).toFixed(2)}ms total=${(tEnd - tStart).toFixed(2)}ms`);
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
19
27
|
}
|
package/dist/render-svg.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-svg.d.ts","sourceRoot":"","sources":["../src/render-svg.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEX,UAAU,EACV,aAAa,EAEb,MAAM,SAAS,CAAC;AAKjB;;;GAGG;AACH,wBAAsB,WAAW,CAChC,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,aAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"render-svg.d.ts","sourceRoot":"","sources":["../src/render-svg.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEX,UAAU,EACV,aAAa,EAEb,MAAM,SAAS,CAAC;AAKjB;;;GAGG;AACH,wBAAsB,WAAW,CAChC,OAAO,EAAE,UAAU,EACnB,OAAO,GAAE,aAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,CAyDjB"}
|
package/dist/render-svg.js
CHANGED
|
@@ -9,6 +9,8 @@ const DEFAULT_HEIGHT = 630;
|
|
|
9
9
|
* Browser-safe: uses only Satori (no Node.js dependencies)
|
|
10
10
|
*/
|
|
11
11
|
export async function renderToSVG(element, options = {}) {
|
|
12
|
+
const profile = process.env.OGX_PROFILE === "1";
|
|
13
|
+
const tStart = profile ? performance.now() : 0;
|
|
12
14
|
const platformDims = options.platform
|
|
13
15
|
? getPlatformDimensions(options.platform)
|
|
14
16
|
: null;
|
|
@@ -35,13 +37,21 @@ export async function renderToSVG(element, options = {}) {
|
|
|
35
37
|
theme: options.theme,
|
|
36
38
|
colorScheme: options.colorScheme,
|
|
37
39
|
};
|
|
40
|
+
const tTransformStart = profile ? performance.now() : 0;
|
|
38
41
|
const transformedElement = transformElement(element, debug, fullOptions);
|
|
39
|
-
|
|
42
|
+
const tTransformEnd = profile ? performance.now() : 0;
|
|
43
|
+
const svg = await satori(transformedElement, {
|
|
40
44
|
width,
|
|
41
45
|
height,
|
|
42
46
|
fonts: resolvedFonts.map(fontToSatoriFont),
|
|
43
47
|
debug,
|
|
44
48
|
});
|
|
49
|
+
if (profile) {
|
|
50
|
+
const tEnd = performance.now();
|
|
51
|
+
// Log coarse-grained timings for debugging hot paths
|
|
52
|
+
console.log(`[OGX PROFILE] renderToSVG transform=${(tTransformEnd - tTransformStart).toFixed(2)}ms satori=${(tEnd - tTransformEnd).toFixed(2)}ms total=${(tEnd - tStart).toFixed(2)}ms`);
|
|
53
|
+
}
|
|
54
|
+
return svg;
|
|
45
55
|
}
|
|
46
56
|
/**
|
|
47
57
|
* Transform OGX element tree to Satori-compatible format
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ogxjs/core - Tailwind Class Cache
|
|
3
|
+
* Per-class caching for maximum performance
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* Caches individual parsed classes instead of full class strings.
|
|
7
|
+
* This allows reuse across different elements with overlapping classes.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* Element A: "flex bg-blue-500 p-4"
|
|
11
|
+
* Element B: "flex bg-red-500 p-4"
|
|
12
|
+
* → "flex" and "p-4" are parsed once, reused for both
|
|
13
|
+
*
|
|
14
|
+
* @performance
|
|
15
|
+
* - Eliminates redundant parsing for common classes
|
|
16
|
+
* - Reduces memory by sharing parsed results
|
|
17
|
+
* - O(1) lookup per class
|
|
18
|
+
*
|
|
19
|
+
* @version 0.2.0 "Turbo"
|
|
20
|
+
*/
|
|
21
|
+
import type { CSSProperties } from "../css";
|
|
22
|
+
/**
|
|
23
|
+
* Cache for individual parsed Tailwind classes
|
|
24
|
+
* Key: class name (e.g., "bg-blue-500")
|
|
25
|
+
* Value: parsed CSS properties
|
|
26
|
+
*
|
|
27
|
+
* @performance v0.2.0 Turbo optimizations:
|
|
28
|
+
* - Direct reference return (no spread copy) - trust consumers
|
|
29
|
+
* - No Object.freeze - avoid expensive operation
|
|
30
|
+
* - Lazy eviction check
|
|
31
|
+
*/
|
|
32
|
+
declare class TailwindClassCache {
|
|
33
|
+
private cache;
|
|
34
|
+
private hits;
|
|
35
|
+
private misses;
|
|
36
|
+
/**
|
|
37
|
+
* Get cached CSS properties for a class
|
|
38
|
+
* @returns Cached properties or undefined if not cached
|
|
39
|
+
*
|
|
40
|
+
* @performance Returns direct reference - DO NOT MUTATE
|
|
41
|
+
*/
|
|
42
|
+
get(cls: string): CSSProperties | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Cache CSS properties for a class
|
|
45
|
+
* @param cls - Tailwind class name
|
|
46
|
+
* @param props - Parsed CSS properties (will be stored directly)
|
|
47
|
+
*/
|
|
48
|
+
set(cls: string, props: CSSProperties): void;
|
|
49
|
+
/**
|
|
50
|
+
* Check if a class has cached properties
|
|
51
|
+
*/
|
|
52
|
+
has(cls: string): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Clear the entire cache
|
|
55
|
+
*/
|
|
56
|
+
clear(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Get cache statistics
|
|
59
|
+
*/
|
|
60
|
+
getStats(): CacheStats;
|
|
61
|
+
/**
|
|
62
|
+
* Check if a class should not be cached
|
|
63
|
+
*/
|
|
64
|
+
private isUncacheable;
|
|
65
|
+
/**
|
|
66
|
+
* Evict oldest entries (FIFO strategy)
|
|
67
|
+
* Removes 10% of cache to avoid frequent evictions
|
|
68
|
+
*/
|
|
69
|
+
private evictOldest;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Cache for full class strings (entire tw prop)
|
|
73
|
+
* Useful when the same exact class string is used multiple times
|
|
74
|
+
*
|
|
75
|
+
* Key: "flex bg-blue-500 p-4"
|
|
76
|
+
* Value: merged CSS properties
|
|
77
|
+
*
|
|
78
|
+
* @performance v0.2.0 Turbo optimizations:
|
|
79
|
+
* - Direct reference return (no spread copy)
|
|
80
|
+
* - No Object.freeze
|
|
81
|
+
* - Efficient LRU-like eviction
|
|
82
|
+
*/
|
|
83
|
+
declare class TailwindStringCache {
|
|
84
|
+
private cache;
|
|
85
|
+
private maxSize;
|
|
86
|
+
/**
|
|
87
|
+
* Get cached properties for a full class string
|
|
88
|
+
* @performance Returns direct reference - DO NOT MUTATE
|
|
89
|
+
*/
|
|
90
|
+
get(key: string): CSSProperties | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Cache properties for a full class string
|
|
93
|
+
*/
|
|
94
|
+
set(key: string, props: CSSProperties): void;
|
|
95
|
+
/**
|
|
96
|
+
* Check if a string has cached properties
|
|
97
|
+
*/
|
|
98
|
+
has(key: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Clear the cache
|
|
101
|
+
*/
|
|
102
|
+
clear(): void;
|
|
103
|
+
/**
|
|
104
|
+
* Get cache size
|
|
105
|
+
*/
|
|
106
|
+
get size(): number;
|
|
107
|
+
}
|
|
108
|
+
export interface CacheStats {
|
|
109
|
+
/** Current number of cached classes */
|
|
110
|
+
size: number;
|
|
111
|
+
/** Maximum cache size */
|
|
112
|
+
maxSize: number;
|
|
113
|
+
/** Number of cache hits */
|
|
114
|
+
hits: number;
|
|
115
|
+
/** Number of cache misses */
|
|
116
|
+
misses: number;
|
|
117
|
+
/** Hit rate (0-1) */
|
|
118
|
+
hitRate: number;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Singleton instance for class-level caching
|
|
122
|
+
*/
|
|
123
|
+
export declare const classCache: TailwindClassCache;
|
|
124
|
+
/**
|
|
125
|
+
* Singleton instance for full string caching
|
|
126
|
+
*/
|
|
127
|
+
export declare const stringCache: TailwindStringCache;
|
|
128
|
+
/**
|
|
129
|
+
* Clear all Tailwind caches
|
|
130
|
+
* Useful for testing or when theme changes
|
|
131
|
+
*/
|
|
132
|
+
export declare function clearAllCaches(): void;
|
|
133
|
+
/**
|
|
134
|
+
* Get combined cache statistics
|
|
135
|
+
*/
|
|
136
|
+
export declare function getCacheStats(): {
|
|
137
|
+
classCache: CacheStats;
|
|
138
|
+
stringCacheSize: number;
|
|
139
|
+
};
|
|
140
|
+
export {};
|
|
141
|
+
//# sourceMappingURL=class-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"class-cache.d.ts","sourceRoot":"","sources":["../../src/tailwind/class-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAmB5C;;;;;;;;;GASG;AACH,cAAM,kBAAkB;IACvB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,MAAM,CAAK;IAEnB;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAU3C;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;IAa5C;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,QAAQ,IAAI,UAAU;IAWtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAIrB;;;OAGG;IACH,OAAO,CAAC,WAAW;CAUnB;AAID;;;;;;;;;;;GAWG;AACH,cAAM,mBAAmB;IACxB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,OAAO,CAAQ;IAEvB;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI3C;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI;IAe5C;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;CACD;AAID,MAAM,WAAW,UAAU;IAC1B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;CAChB;AAID;;GAEG;AACH,eAAO,MAAM,UAAU,oBAA2B,CAAC;AAEnD;;GAEG;AACH,eAAO,MAAM,WAAW,qBAA4B,CAAC;AAErD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI;IAChC,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACxB,CAKA"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ogxjs/core - Tailwind Class Cache
|
|
3
|
+
* Per-class caching for maximum performance
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* Caches individual parsed classes instead of full class strings.
|
|
7
|
+
* This allows reuse across different elements with overlapping classes.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* Element A: "flex bg-blue-500 p-4"
|
|
11
|
+
* Element B: "flex bg-red-500 p-4"
|
|
12
|
+
* → "flex" and "p-4" are parsed once, reused for both
|
|
13
|
+
*
|
|
14
|
+
* @performance
|
|
15
|
+
* - Eliminates redundant parsing for common classes
|
|
16
|
+
* - Reduces memory by sharing parsed results
|
|
17
|
+
* - O(1) lookup per class
|
|
18
|
+
*
|
|
19
|
+
* @version 0.2.0 "Turbo"
|
|
20
|
+
*/
|
|
21
|
+
// CONFIGURATION
|
|
22
|
+
/**
|
|
23
|
+
* Maximum cache size to prevent memory leaks
|
|
24
|
+
* ~5000 classes × ~200 bytes avg = ~1MB max
|
|
25
|
+
*/
|
|
26
|
+
const MAX_CACHE_SIZE = 5000;
|
|
27
|
+
/**
|
|
28
|
+
* Classes to never cache (dynamic/theme-dependent)
|
|
29
|
+
*/
|
|
30
|
+
const UNCACHEABLE_PATTERNS = [
|
|
31
|
+
/^dark:/, // Dark mode variants (theme-dependent)
|
|
32
|
+
];
|
|
33
|
+
// CLASS CACHE
|
|
34
|
+
/**
|
|
35
|
+
* Cache for individual parsed Tailwind classes
|
|
36
|
+
* Key: class name (e.g., "bg-blue-500")
|
|
37
|
+
* Value: parsed CSS properties
|
|
38
|
+
*
|
|
39
|
+
* @performance v0.2.0 Turbo optimizations:
|
|
40
|
+
* - Direct reference return (no spread copy) - trust consumers
|
|
41
|
+
* - No Object.freeze - avoid expensive operation
|
|
42
|
+
* - Lazy eviction check
|
|
43
|
+
*/
|
|
44
|
+
class TailwindClassCache {
|
|
45
|
+
cache = new Map();
|
|
46
|
+
hits = 0;
|
|
47
|
+
misses = 0;
|
|
48
|
+
/**
|
|
49
|
+
* Get cached CSS properties for a class
|
|
50
|
+
* @returns Cached properties or undefined if not cached
|
|
51
|
+
*
|
|
52
|
+
* @performance Returns direct reference - DO NOT MUTATE
|
|
53
|
+
*/
|
|
54
|
+
get(cls) {
|
|
55
|
+
const cached = this.cache.get(cls);
|
|
56
|
+
if (cached !== undefined) {
|
|
57
|
+
this.hits++;
|
|
58
|
+
return cached; // Direct reference - no copy overhead
|
|
59
|
+
}
|
|
60
|
+
this.misses++;
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Cache CSS properties for a class
|
|
65
|
+
* @param cls - Tailwind class name
|
|
66
|
+
* @param props - Parsed CSS properties (will be stored directly)
|
|
67
|
+
*/
|
|
68
|
+
set(cls, props) {
|
|
69
|
+
// Don't cache theme-dependent classes
|
|
70
|
+
if (this.isUncacheable(cls))
|
|
71
|
+
return;
|
|
72
|
+
// Evict oldest entries if cache is full (lazy check)
|
|
73
|
+
if (this.cache.size >= MAX_CACHE_SIZE) {
|
|
74
|
+
this.evictOldest();
|
|
75
|
+
}
|
|
76
|
+
// Store directly - no copy, no freeze
|
|
77
|
+
this.cache.set(cls, props);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if a class has cached properties
|
|
81
|
+
*/
|
|
82
|
+
has(cls) {
|
|
83
|
+
return this.cache.has(cls);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Clear the entire cache
|
|
87
|
+
*/
|
|
88
|
+
clear() {
|
|
89
|
+
this.cache.clear();
|
|
90
|
+
this.hits = 0;
|
|
91
|
+
this.misses = 0;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get cache statistics
|
|
95
|
+
*/
|
|
96
|
+
getStats() {
|
|
97
|
+
const total = this.hits + this.misses;
|
|
98
|
+
return {
|
|
99
|
+
size: this.cache.size,
|
|
100
|
+
maxSize: MAX_CACHE_SIZE,
|
|
101
|
+
hits: this.hits,
|
|
102
|
+
misses: this.misses,
|
|
103
|
+
hitRate: total > 0 ? this.hits / total : 0,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Check if a class should not be cached
|
|
108
|
+
*/
|
|
109
|
+
isUncacheable(cls) {
|
|
110
|
+
return UNCACHEABLE_PATTERNS.some((pattern) => pattern.test(cls));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Evict oldest entries (FIFO strategy)
|
|
114
|
+
* Removes 10% of cache to avoid frequent evictions
|
|
115
|
+
*/
|
|
116
|
+
evictOldest() {
|
|
117
|
+
const toRemove = Math.ceil(MAX_CACHE_SIZE * 0.1);
|
|
118
|
+
const iterator = this.cache.keys();
|
|
119
|
+
for (let i = 0; i < toRemove; i++) {
|
|
120
|
+
const { value, done } = iterator.next();
|
|
121
|
+
if (done)
|
|
122
|
+
break;
|
|
123
|
+
this.cache.delete(value);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// FULL STRING CACHE
|
|
128
|
+
/**
|
|
129
|
+
* Cache for full class strings (entire tw prop)
|
|
130
|
+
* Useful when the same exact class string is used multiple times
|
|
131
|
+
*
|
|
132
|
+
* Key: "flex bg-blue-500 p-4"
|
|
133
|
+
* Value: merged CSS properties
|
|
134
|
+
*
|
|
135
|
+
* @performance v0.2.0 Turbo optimizations:
|
|
136
|
+
* - Direct reference return (no spread copy)
|
|
137
|
+
* - No Object.freeze
|
|
138
|
+
* - Efficient LRU-like eviction
|
|
139
|
+
*/
|
|
140
|
+
class TailwindStringCache {
|
|
141
|
+
cache = new Map();
|
|
142
|
+
maxSize = 1000;
|
|
143
|
+
/**
|
|
144
|
+
* Get cached properties for a full class string
|
|
145
|
+
* @performance Returns direct reference - DO NOT MUTATE
|
|
146
|
+
*/
|
|
147
|
+
get(key) {
|
|
148
|
+
return this.cache.get(key);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Cache properties for a full class string
|
|
152
|
+
*/
|
|
153
|
+
set(key, props) {
|
|
154
|
+
if (this.cache.size >= this.maxSize) {
|
|
155
|
+
// Simple eviction: delete oldest entries (first 20%)
|
|
156
|
+
const toRemove = Math.ceil(this.maxSize * 0.2);
|
|
157
|
+
const iterator = this.cache.keys();
|
|
158
|
+
for (let i = 0; i < toRemove; i++) {
|
|
159
|
+
const { value, done } = iterator.next();
|
|
160
|
+
if (done)
|
|
161
|
+
break;
|
|
162
|
+
this.cache.delete(value);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Store directly - no copy, no freeze
|
|
166
|
+
this.cache.set(key, props);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Check if a string has cached properties
|
|
170
|
+
*/
|
|
171
|
+
has(key) {
|
|
172
|
+
return this.cache.has(key);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Clear the cache
|
|
176
|
+
*/
|
|
177
|
+
clear() {
|
|
178
|
+
this.cache.clear();
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get cache size
|
|
182
|
+
*/
|
|
183
|
+
get size() {
|
|
184
|
+
return this.cache.size;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// EXPORTS
|
|
188
|
+
/**
|
|
189
|
+
* Singleton instance for class-level caching
|
|
190
|
+
*/
|
|
191
|
+
export const classCache = new TailwindClassCache();
|
|
192
|
+
/**
|
|
193
|
+
* Singleton instance for full string caching
|
|
194
|
+
*/
|
|
195
|
+
export const stringCache = new TailwindStringCache();
|
|
196
|
+
/**
|
|
197
|
+
* Clear all Tailwind caches
|
|
198
|
+
* Useful for testing or when theme changes
|
|
199
|
+
*/
|
|
200
|
+
export function clearAllCaches() {
|
|
201
|
+
classCache.clear();
|
|
202
|
+
stringCache.clear();
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get combined cache statistics
|
|
206
|
+
*/
|
|
207
|
+
export function getCacheStats() {
|
|
208
|
+
return {
|
|
209
|
+
classCache: classCache.getStats(),
|
|
210
|
+
stringCacheSize: stringCache.size,
|
|
211
|
+
};
|
|
212
|
+
}
|
package/dist/tailwind/index.d.ts
CHANGED
|
@@ -1,2 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @ogxjs/core - Tailwind Module
|
|
3
|
+
* High-performance Tailwind CSS parser
|
|
4
|
+
*
|
|
5
|
+
* @version 0.2.0 "Turbo"
|
|
6
|
+
*/
|
|
7
|
+
export type { CacheStats } from "./class-cache";
|
|
8
|
+
export { classCache, stringCache } from "./class-cache";
|
|
9
|
+
export { colors } from "./colors";
|
|
10
|
+
export { getStaticClass, isStaticClass, STATIC_CLASSES } from "./lookup-tables";
|
|
11
|
+
export { clearAllCaches, getCacheStats, parseTailwind, parseTailwindBatch, } from "./parser-v2";
|
|
12
|
+
export type { GradientState, ParseContext } from "./prefix-handlers";
|
|
13
|
+
export { ORDERED_PREFIXES, PREFIX_HANDLERS, parseSpacingValue, resolveColorValue, } from "./prefix-handlers";
|
|
14
|
+
export { borderRadius, fontSize, fontWeight, opacity, spacing } from "./scales";
|
|
2
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tailwind/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tailwind/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEhF,OAAO,EACN,cAAc,EACd,aAAa,EACb,aAAa,EACb,kBAAkB,GAClB,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EACN,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/tailwind/index.js
CHANGED
|
@@ -1 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @ogxjs/core - Tailwind Module
|
|
3
|
+
* High-performance Tailwind CSS parser
|
|
4
|
+
*
|
|
5
|
+
* @version 0.2.0 "Turbo"
|
|
6
|
+
*/
|
|
7
|
+
export { classCache, stringCache } from "./class-cache";
|
|
8
|
+
export { colors } from "./colors";
|
|
9
|
+
// Advanced exports for customization
|
|
10
|
+
export { getStaticClass, isStaticClass, STATIC_CLASSES } from "./lookup-tables";
|
|
11
|
+
// Main parser (v2 with O(1) lookups)
|
|
12
|
+
export { clearAllCaches, getCacheStats, parseTailwind, parseTailwindBatch, } from "./parser-v2";
|
|
13
|
+
export { ORDERED_PREFIXES, PREFIX_HANDLERS, parseSpacingValue, resolveColorValue, } from "./prefix-handlers";
|
|
14
|
+
// Scales and values
|
|
15
|
+
export { borderRadius, fontSize, fontWeight, opacity, spacing } from "./scales";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ogxjs/core - Tailwind Lookup Tables
|
|
3
|
+
* O(1) lookup for static classes (no dynamic values)
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* This module provides instant lookup for ~200+ static Tailwind classes.
|
|
7
|
+
* Instead of iterating through if/else chains, we use Map for O(1) access.
|
|
8
|
+
*
|
|
9
|
+
* @performance
|
|
10
|
+
* - Before: O(n) where n = number of if/else conditions (~100)
|
|
11
|
+
* - After: O(1) constant time lookup
|
|
12
|
+
*
|
|
13
|
+
* @version 0.2.0 "Turbo"
|
|
14
|
+
*/
|
|
15
|
+
import type { CSSProperties } from "../css";
|
|
16
|
+
/**
|
|
17
|
+
* Static classes that map directly to CSS properties
|
|
18
|
+
* No parsing needed - just lookup and return
|
|
19
|
+
*/
|
|
20
|
+
export declare const STATIC_CLASSES: Map<string, CSSProperties>;
|
|
21
|
+
/**
|
|
22
|
+
* Check if a class is static (can be looked up directly)
|
|
23
|
+
*/
|
|
24
|
+
export declare function isStaticClass(cls: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Get CSS properties for a static class
|
|
27
|
+
* Returns undefined if not a static class
|
|
28
|
+
*/
|
|
29
|
+
export declare function getStaticClass(cls: string): CSSProperties | undefined;
|
|
30
|
+
//# sourceMappingURL=lookup-tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup-tables.d.ts","sourceRoot":"","sources":["../../src/tailwind/lookup-tables.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C;;;GAGG;AACH,eAAO,MAAM,cAAc,4BAsdzB,CAAC;AAEH;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAErE"}
|