chaincss 2.0.7 → 2.1.0
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/CHANGELOG.md +30 -0
- package/CODE_OF_CONDUCT.md +21 -0
- package/CONTRIBUTING.md +28 -0
- package/README.md +455 -226
- package/demo/demo/node_modules/caniuse-db/fulldata-json/data-2.0.json +1 -0
- package/demo/index.html +16 -0
- package/demo/package.json +20 -0
- package/demo/src/App.tsx +117 -0
- package/demo/src/chaincss-barrel.ts +9 -0
- package/demo/src/main.tsx +8 -0
- package/demo/src/styles.chain.ts +300 -0
- package/demo/vite.config.ts +46 -0
- package/dist/cli/commands/build.d.ts +0 -1
- package/dist/cli/commands/cache.d.ts +1 -0
- package/dist/cli/commands/init.d.ts +6 -3
- package/dist/cli/commands/timeline.d.ts +0 -1
- package/dist/cli/commands/watch.d.ts +0 -1
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +3213 -5296
- package/dist/cli/types.d.ts +51 -20
- package/dist/cli/utils/config-loader.d.ts +0 -1
- package/dist/cli/utils/file-utils.d.ts +27 -3
- package/dist/cli/utils/logger.d.ts +0 -1
- package/dist/compiler/Chain.d.ts +215 -0
- package/dist/compiler/animations.d.ts +76 -0
- package/dist/compiler/atomic-optimizer.d.ts +47 -12
- package/dist/compiler/breakpoints.d.ts +46 -0
- package/dist/compiler/btt.d.ts +36 -60
- package/dist/compiler/cache-manager.d.ts +58 -4
- package/dist/compiler/commonProps.d.ts +0 -1
- package/dist/compiler/content-addressable-cache.d.ts +78 -0
- package/dist/compiler/helpers.d.ts +54 -0
- package/dist/compiler/index.d.ts +16 -9
- package/dist/compiler/index.js +4450 -4316
- package/dist/compiler/prefixer.d.ts +17 -1
- package/dist/compiler/shorthands.d.ts +28 -0
- package/dist/compiler/suggestions.d.ts +43 -0
- package/dist/compiler/theme-contract.d.ts +16 -27
- package/dist/compiler/token-resolver.d.ts +69 -0
- package/dist/compiler/tokens.d.ts +33 -8
- package/dist/core/auto-detector.d.ts +34 -0
- package/dist/core/common-utils.d.ts +97 -0
- package/dist/core/compiler.d.ts +63 -23
- package/dist/core/constants.d.ts +137 -36
- package/dist/core/smart-chain.d.ts +3 -0
- package/dist/core/types.d.ts +122 -15
- package/dist/core/utils.d.ts +134 -17
- package/dist/index.d.ts +52 -8
- package/dist/index.js +7090 -5578
- package/dist/plugins/vite.d.ts +7 -5
- package/dist/plugins/vite.js +2964 -25641
- package/dist/plugins/webpack.d.ts +24 -1
- package/dist/plugins/webpack.js +209 -72
- package/dist/runtime/Chain.d.ts +32 -0
- package/dist/runtime/auto-hooks.d.ts +11 -0
- package/dist/runtime/hmr.d.ts +22 -2
- package/dist/runtime/index.d.ts +3 -2
- package/dist/runtime/index.js +3648 -301
- package/dist/runtime/injector.d.ts +39 -72
- package/dist/runtime/react.d.ts +17 -12
- package/dist/runtime/svelte.d.ts +15 -0
- package/dist/runtime/types.d.ts +126 -4
- package/dist/runtime/utils.d.ts +0 -1
- package/dist/runtime/vue.d.ts +34 -14
- package/package.json +59 -66
- package/src/cli/commands/build.ts +133 -0
- package/src/cli/commands/cache.ts +371 -0
- package/src/cli/commands/init.ts +230 -0
- package/src/cli/commands/timeline.ts +435 -0
- package/src/cli/commands/watch.ts +211 -0
- package/src/cli/index.ts +226 -0
- package/src/cli/types.ts +100 -0
- package/src/cli/utils/config-loader.ts +174 -0
- package/src/cli/utils/file-utils.ts +139 -0
- package/src/cli/utils/logger.ts +74 -0
- package/src/compiler/Chain.ts +831 -0
- package/src/compiler/animations.ts +517 -0
- package/src/compiler/atomic-optimizer.ts +786 -0
- package/src/compiler/breakpoints.ts +347 -0
- package/src/compiler/btt.ts +1147 -0
- package/src/compiler/cache-manager.ts +446 -0
- package/src/compiler/commonProps.ts +18 -0
- package/src/compiler/content-addressable-cache.ts +478 -0
- package/src/compiler/helpers.ts +407 -0
- package/src/compiler/index.ts +72 -0
- package/src/compiler/prefixer.ts +724 -0
- package/src/compiler/shorthands.ts +558 -0
- package/src/compiler/suggestions.ts +436 -0
- package/src/compiler/theme-contract.ts +197 -0
- package/src/compiler/token-resolver.ts +241 -0
- package/src/compiler/tokens.ts +612 -0
- package/src/core/auto-detector.ts +187 -0
- package/src/core/common-utils.ts +423 -0
- package/src/core/compiler.ts +835 -0
- package/src/core/constants.ts +424 -0
- package/src/core/index.ts +107 -0
- package/src/core/smart-chain.ts +163 -0
- package/src/core/types.ts +257 -0
- package/src/core/utils.ts +598 -0
- package/src/index.ts +208 -0
- package/src/plugins/vite.d.ts +316 -0
- package/src/plugins/vite.ts +424 -0
- package/src/plugins/webpack.d.ts +289 -0
- package/src/plugins/webpack.ts +416 -0
- package/src/runtime/Chain.ts +242 -0
- package/src/runtime/auto-hooks.tsx +127 -0
- package/src/runtime/auto-vue.ts +72 -0
- package/src/runtime/hmr.ts +212 -0
- package/src/runtime/index.ts +82 -0
- package/src/runtime/injector.ts +273 -0
- package/src/runtime/react.tsx +269 -0
- package/src/runtime/svelte.ts +15 -0
- package/src/runtime/types.ts +256 -0
- package/src/runtime/utils.ts +128 -0
- package/src/runtime/vite-env.d.ts +120 -0
- package/src/runtime/vue.ts +231 -0
- package/tsconfig.build.json +41 -0
- package/tsconfig.json +25 -0
- package/tsconfig.runtimes.json +18 -0
- package/dist/cli/cli.cjs +0 -7
- package/dist/cli/commands/build.d.ts.map +0 -1
- package/dist/cli/commands/compile.d.ts +0 -3
- package/dist/cli/commands/compile.d.ts.map +0 -1
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/commands/timeline.d.ts.map +0 -1
- package/dist/cli/commands/watch.d.ts.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/types.d.ts.map +0 -1
- package/dist/cli/utils/config-loader.d.ts.map +0 -1
- package/dist/cli/utils/file-utils.d.ts.map +0 -1
- package/dist/cli/utils/logger.d.ts.map +0 -1
- package/dist/compiler/atomic-optimizer.d.ts.map +0 -1
- package/dist/compiler/btt.d.ts.map +0 -1
- package/dist/compiler/cache-manager.d.ts.map +0 -1
- package/dist/compiler/commonProps.d.ts.map +0 -1
- package/dist/compiler/index.d.ts.map +0 -1
- package/dist/compiler/prefixer.d.ts.map +0 -1
- package/dist/compiler/theme-contract.d.ts.map +0 -1
- package/dist/compiler/tokens.d.ts.map +0 -1
- package/dist/compiler/types.d.ts +0 -57
- package/dist/compiler/types.d.ts.map +0 -1
- package/dist/core/compiler.d.ts.map +0 -1
- package/dist/core/constants.d.ts.map +0 -1
- package/dist/core/index.d.ts +0 -4
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/utils.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/plugins/vite.d.ts.map +0 -1
- package/dist/plugins/webpack.d.ts.map +0 -1
- package/dist/runtime/hmr.d.ts.map +0 -1
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/injector.d.ts.map +0 -1
- package/dist/runtime/react.d.ts.map +0 -1
- package/dist/runtime/react.js +0 -324
- package/dist/runtime/types.d.ts.map +0 -1
- package/dist/runtime/utils.d.ts.map +0 -1
- package/dist/runtime/vue.d.ts.map +0 -1
- package/dist/runtime/vue.js +0 -286
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
// chaincss/src/compiler/cache-manager.ts
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import crypto from 'crypto';
|
|
5
|
+
|
|
6
|
+
export interface CacheData {
|
|
7
|
+
version: string;
|
|
8
|
+
created: string;
|
|
9
|
+
updated: string;
|
|
10
|
+
atomic: Record<string, any>;
|
|
11
|
+
usage: Record<string, any>;
|
|
12
|
+
componentMap: Record<string, any>;
|
|
13
|
+
stats: {
|
|
14
|
+
totalStyles: number;
|
|
15
|
+
atomicStyles: number;
|
|
16
|
+
cacheHits: number;
|
|
17
|
+
cacheMisses: number;
|
|
18
|
+
};
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CacheOptions {
|
|
23
|
+
maxAge?: number; // Maximum age in milliseconds
|
|
24
|
+
maxSize?: number; // Maximum cache size in bytes
|
|
25
|
+
compress?: boolean; // Compress cache data
|
|
26
|
+
autoSave?: boolean; // Auto-save on changes
|
|
27
|
+
saveInterval?: number; // Auto-save interval in ms
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class CacheManager {
|
|
31
|
+
cachePath: string;
|
|
32
|
+
cacheDir: string;
|
|
33
|
+
cache: CacheData | Record<string, any>;
|
|
34
|
+
private dirty: boolean = false;
|
|
35
|
+
private saveTimer: NodeJS.Timeout | null = null;
|
|
36
|
+
private stats = {
|
|
37
|
+
hits: 0,
|
|
38
|
+
misses: 0,
|
|
39
|
+
writes: 0,
|
|
40
|
+
reads: 0
|
|
41
|
+
};
|
|
42
|
+
private options: Required<CacheOptions>;
|
|
43
|
+
|
|
44
|
+
constructor(cachePath: string = './.chaincss-cache', options: CacheOptions = {}) {
|
|
45
|
+
this.options = {
|
|
46
|
+
maxAge: options.maxAge || 7 * 24 * 60 * 60 * 1000, // 7 days default
|
|
47
|
+
maxSize: options.maxSize || 100 * 1024 * 1024, // 100MB default
|
|
48
|
+
compress: options.compress || false,
|
|
49
|
+
autoSave: options.autoSave !== false,
|
|
50
|
+
saveInterval: options.saveInterval || 5000 // 5 seconds
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
this.cachePath = path.resolve(process.cwd(), cachePath);
|
|
54
|
+
this.cacheDir = path.dirname(this.cachePath);
|
|
55
|
+
this.cache = {};
|
|
56
|
+
this.load();
|
|
57
|
+
|
|
58
|
+
// Setup auto-save if enabled
|
|
59
|
+
if (this.options.autoSave) {
|
|
60
|
+
this.startAutoSave();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private startAutoSave(): void {
|
|
65
|
+
if (this.saveTimer) clearInterval(this.saveTimer);
|
|
66
|
+
this.saveTimer = setInterval(() => {
|
|
67
|
+
if (this.dirty) {
|
|
68
|
+
this.save();
|
|
69
|
+
}
|
|
70
|
+
}, this.options.saveInterval);
|
|
71
|
+
|
|
72
|
+
// Ensure timer doesn't keep process alive
|
|
73
|
+
if (this.saveTimer.unref) {
|
|
74
|
+
this.saveTimer.unref();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private stopAutoSave(): void {
|
|
79
|
+
if (this.saveTimer) {
|
|
80
|
+
clearInterval(this.saveTimer);
|
|
81
|
+
this.saveTimer = null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
load(): void {
|
|
86
|
+
try {
|
|
87
|
+
if (fs.existsSync(this.cachePath)) {
|
|
88
|
+
let data = fs.readFileSync(this.cachePath, 'utf8');
|
|
89
|
+
|
|
90
|
+
// Decompress if needed
|
|
91
|
+
if (this.options.compress && this.isCompressed(data)) {
|
|
92
|
+
data = this.decompress(data);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this.cache = JSON.parse(data);
|
|
96
|
+
|
|
97
|
+
// Check if cache is expired
|
|
98
|
+
if (this.isExpired()) {
|
|
99
|
+
console.log('Cache expired, clearing...');
|
|
100
|
+
this.clear();
|
|
101
|
+
this.cache = this.getDefaultCache();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check cache size
|
|
105
|
+
this.checkAndPrune();
|
|
106
|
+
} else {
|
|
107
|
+
// Ensure cache directory exists
|
|
108
|
+
if (!fs.existsSync(this.cacheDir)) {
|
|
109
|
+
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
110
|
+
}
|
|
111
|
+
this.cache = this.getDefaultCache();
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.warn('Could not load cache, starting fresh:', (error as Error).message);
|
|
115
|
+
this.cache = this.getDefaultCache();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private getDefaultCache(): CacheData {
|
|
120
|
+
return {
|
|
121
|
+
version: '2.0.0',
|
|
122
|
+
created: new Date().toISOString(),
|
|
123
|
+
updated: new Date().toISOString(),
|
|
124
|
+
atomic: {},
|
|
125
|
+
usage: {},
|
|
126
|
+
componentMap: {},
|
|
127
|
+
stats: {
|
|
128
|
+
totalStyles: 0,
|
|
129
|
+
atomicStyles: 0,
|
|
130
|
+
cacheHits: 0,
|
|
131
|
+
cacheMisses: 0
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private isExpired(): boolean {
|
|
137
|
+
const created = this.cache.created ? new Date(this.cache.created).getTime() : 0;
|
|
138
|
+
const now = Date.now();
|
|
139
|
+
return (now - created) > this.options.maxAge;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private checkAndPrune(): void {
|
|
143
|
+
try {
|
|
144
|
+
const stats = fs.statSync(this.cachePath);
|
|
145
|
+
if (stats.size > this.options.maxSize) {
|
|
146
|
+
console.log(`Cache size (${stats.size} bytes) exceeds limit (${this.options.maxSize} bytes), pruning...`);
|
|
147
|
+
this.prune();
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
// File might not exist yet
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private isCompressed(data: string): boolean {
|
|
155
|
+
// Check if data looks like compressed (base64 encoded)
|
|
156
|
+
return data.startsWith('COMPRESSED:');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private compress(data: string): string {
|
|
160
|
+
// Simple compression - could be enhanced with zlib
|
|
161
|
+
const compressed = Buffer.from(data).toString('base64');
|
|
162
|
+
return `COMPRESSED:${compressed}`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private decompress(data: string): string {
|
|
166
|
+
if (data.startsWith('COMPRESSED:')) {
|
|
167
|
+
const compressed = data.substring(11);
|
|
168
|
+
return Buffer.from(compressed, 'base64').toString();
|
|
169
|
+
}
|
|
170
|
+
return data;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
get(key: string): any {
|
|
174
|
+
this.stats.reads++;
|
|
175
|
+
|
|
176
|
+
if (this.cache[key] !== undefined) {
|
|
177
|
+
// Check if this specific entry has expired
|
|
178
|
+
if (this.cache[key].expires && this.cache[key].expires < Date.now()) {
|
|
179
|
+
delete this.cache[key];
|
|
180
|
+
this.stats.misses++;
|
|
181
|
+
this.dirty = true;
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.stats.hits++;
|
|
186
|
+
if (this.cache.stats) {
|
|
187
|
+
this.cache.stats.cacheHits++;
|
|
188
|
+
}
|
|
189
|
+
return this.cache[key];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.stats.misses++;
|
|
193
|
+
if (this.cache.stats) {
|
|
194
|
+
this.cache.stats.cacheMisses++;
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
set(key: string, value: any, ttl?: number): void {
|
|
200
|
+
const entry = {
|
|
201
|
+
...value,
|
|
202
|
+
cachedAt: Date.now(),
|
|
203
|
+
expires: ttl ? Date.now() + ttl : undefined
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
this.cache[key] = entry;
|
|
207
|
+
this.dirty = true;
|
|
208
|
+
this.stats.writes++;
|
|
209
|
+
|
|
210
|
+
if (this.cache.stats && key !== 'stats') {
|
|
211
|
+
// Update stats if this is atomic or component data
|
|
212
|
+
if (key === 'atomic') {
|
|
213
|
+
this.cache.stats.atomicStyles = Object.keys(value).length;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
has(key: string): boolean {
|
|
219
|
+
const value = this.get(key);
|
|
220
|
+
return value !== undefined;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
delete(key: string): boolean {
|
|
224
|
+
if (this.cache[key] !== undefined) {
|
|
225
|
+
delete this.cache[key];
|
|
226
|
+
this.dirty = true;
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
clear(): void {
|
|
233
|
+
this.cache = this.getDefaultCache();
|
|
234
|
+
this.dirty = true;
|
|
235
|
+
this.stats = { hits: 0, misses: 0, writes: 0, reads: 0 };
|
|
236
|
+
|
|
237
|
+
if (fs.existsSync(this.cachePath)) {
|
|
238
|
+
try {
|
|
239
|
+
fs.unlinkSync(this.cachePath);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
console.warn('Could not delete cache file:', (error as Error).message);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
console.log('Cache cleared');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
prune(): void {
|
|
249
|
+
const now = Date.now();
|
|
250
|
+
let prunedCount = 0;
|
|
251
|
+
|
|
252
|
+
for (const [key, value] of Object.entries(this.cache)) {
|
|
253
|
+
// Skip metadata keys
|
|
254
|
+
if (['version', 'created', 'updated', 'stats'].includes(key)) continue;
|
|
255
|
+
|
|
256
|
+
// Remove expired entries
|
|
257
|
+
if (value.expires && value.expires < now) {
|
|
258
|
+
delete this.cache[key];
|
|
259
|
+
prunedCount++;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Update timestamp
|
|
264
|
+
this.cache.updated = new Date().toISOString();
|
|
265
|
+
this.dirty = true;
|
|
266
|
+
|
|
267
|
+
if (prunedCount > 0 && this.options.autoSave) {
|
|
268
|
+
console.log(`Pruned ${prunedCount} expired cache entries`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
save(): void {
|
|
273
|
+
if (!this.dirty) return;
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
// Update metadata
|
|
277
|
+
this.cache.updated = new Date().toISOString();
|
|
278
|
+
if (this.cache.stats) {
|
|
279
|
+
this.cache.stats = { ...this.cache.stats, ...this.stats };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
let data = JSON.stringify(this.cache, null, 2);
|
|
283
|
+
|
|
284
|
+
// Compress if enabled
|
|
285
|
+
if (this.options.compress && data.length > 1024) {
|
|
286
|
+
data = this.compress(data);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Ensure directory exists
|
|
290
|
+
if (!fs.existsSync(this.cacheDir)) {
|
|
291
|
+
fs.mkdirSync(this.cacheDir, { recursive: true });
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Write to temp file first, then rename for atomicity
|
|
295
|
+
const tempPath = `${this.cachePath}.tmp`;
|
|
296
|
+
fs.writeFileSync(tempPath, data, 'utf8');
|
|
297
|
+
fs.renameSync(tempPath, this.cachePath);
|
|
298
|
+
|
|
299
|
+
this.dirty = false;
|
|
300
|
+
} catch (error) {
|
|
301
|
+
console.warn('Could not save cache:', (error as Error).message);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
getStats(): {
|
|
306
|
+
hits: number;
|
|
307
|
+
misses: number;
|
|
308
|
+
reads: number;
|
|
309
|
+
writes: number;
|
|
310
|
+
hitRate: number;
|
|
311
|
+
size: number;
|
|
312
|
+
entryCount: number;
|
|
313
|
+
} {
|
|
314
|
+
const total = this.stats.hits + this.stats.misses;
|
|
315
|
+
const hitRate = total > 0 ? (this.stats.hits / total) * 100 : 0;
|
|
316
|
+
|
|
317
|
+
let size = 0;
|
|
318
|
+
try {
|
|
319
|
+
if (fs.existsSync(this.cachePath)) {
|
|
320
|
+
const stats = fs.statSync(this.cachePath);
|
|
321
|
+
size = stats.size;
|
|
322
|
+
}
|
|
323
|
+
} catch (error) {
|
|
324
|
+
// Ignore
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const entryCount = Object.keys(this.cache).filter(k =>
|
|
328
|
+
!['version', 'created', 'updated', 'stats'].includes(k)
|
|
329
|
+
).length;
|
|
330
|
+
|
|
331
|
+
return {
|
|
332
|
+
hits: this.stats.hits,
|
|
333
|
+
misses: this.stats.misses,
|
|
334
|
+
reads: this.stats.reads,
|
|
335
|
+
writes: this.stats.writes,
|
|
336
|
+
hitRate,
|
|
337
|
+
size,
|
|
338
|
+
entryCount
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
getCacheSize(): number {
|
|
343
|
+
try {
|
|
344
|
+
if (fs.existsSync(this.cachePath)) {
|
|
345
|
+
const stats = fs.statSync(this.cachePath);
|
|
346
|
+
return stats.size;
|
|
347
|
+
}
|
|
348
|
+
} catch (error) {
|
|
349
|
+
// Ignore
|
|
350
|
+
}
|
|
351
|
+
return 0;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
getCacheAge(): number {
|
|
355
|
+
try {
|
|
356
|
+
if (fs.existsSync(this.cachePath)) {
|
|
357
|
+
const stats = fs.statSync(this.cachePath);
|
|
358
|
+
return Date.now() - stats.mtimeMs;
|
|
359
|
+
}
|
|
360
|
+
} catch (error) {
|
|
361
|
+
// Ignore
|
|
362
|
+
}
|
|
363
|
+
return 0;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
getKeys(): string[] {
|
|
367
|
+
return Object.keys(this.cache).filter(k =>
|
|
368
|
+
!['version', 'created', 'updated', 'stats'].includes(k)
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
getSize(): number {
|
|
373
|
+
return this.getCacheSize();
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
isDirty(): boolean {
|
|
377
|
+
return this.dirty;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async flush(): Promise<void> {
|
|
381
|
+
if (this.dirty) {
|
|
382
|
+
this.save();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
destroy(): void {
|
|
387
|
+
this.stopAutoSave();
|
|
388
|
+
this.clear();
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Get cache entry with metadata
|
|
392
|
+
getEntry(key: string): { value: any; cachedAt: number; expires?: number } | undefined {
|
|
393
|
+
const entry = this.cache[key];
|
|
394
|
+
if (entry && (!entry.expires || entry.expires > Date.now())) {
|
|
395
|
+
return {
|
|
396
|
+
value: entry.value !== undefined ? entry.value : entry,
|
|
397
|
+
cachedAt: entry.cachedAt,
|
|
398
|
+
expires: entry.expires
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
return undefined;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Set cache entry with custom TTL in seconds
|
|
405
|
+
setWithTTL(key: string, value: any, ttlSeconds: number): void {
|
|
406
|
+
this.set(key, value, ttlSeconds * 1000);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Bulk set multiple entries
|
|
410
|
+
setBulk(entries: Record<string, any>): void {
|
|
411
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
412
|
+
this.set(key, value);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Bulk get multiple entries
|
|
417
|
+
getBulk(keys: string[]): Record<string, any> {
|
|
418
|
+
const result: Record<string, any> = {};
|
|
419
|
+
for (const key of keys) {
|
|
420
|
+
const value = this.get(key);
|
|
421
|
+
if (value !== undefined) {
|
|
422
|
+
result[key] = value;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return result;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Get or compute cache value
|
|
429
|
+
async getOrCompute<T>(
|
|
430
|
+
key: string,
|
|
431
|
+
compute: () => Promise<T>,
|
|
432
|
+
ttl?: number
|
|
433
|
+
): Promise<T> {
|
|
434
|
+
const cached = this.get(key);
|
|
435
|
+
if (cached !== undefined) {
|
|
436
|
+
return cached;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const computed = await compute();
|
|
440
|
+
this.set(key, computed, ttl);
|
|
441
|
+
return computed;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// ESM Export
|
|
446
|
+
export { CacheManager as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// src/compiler/commonProps.ts
|
|
2
|
+
export const COMMON_CSS_PROPERTIES: string[] = [
|
|
3
|
+
'align-content', 'align-items', 'align-self', 'animation', 'background',
|
|
4
|
+
'background-clip', 'background-color', 'background-image', 'background-position',
|
|
5
|
+
'background-repeat', 'background-size', 'border', 'border-bottom', 'border-color',
|
|
6
|
+
'border-left', 'border-radius', 'border-right', 'border-style', 'border-top',
|
|
7
|
+
'border-width', 'bottom', 'box-shadow', 'box-sizing', 'color', 'content',
|
|
8
|
+
'cursor', 'display', 'flex', 'flex-direction', 'flex-grow', 'flex-shrink',
|
|
9
|
+
'flex-wrap', 'float', 'font', 'font-family', 'font-size', 'font-weight',
|
|
10
|
+
'gap', 'grid', 'grid-template-columns', 'grid-template-rows', 'height',
|
|
11
|
+
'justify-content', 'left', 'letter-spacing', 'line-height', 'margin',
|
|
12
|
+
'margin-bottom', 'margin-left', 'margin-right', 'margin-top', 'max-height',
|
|
13
|
+
'max-width', 'min-height', 'min-width', 'opacity', 'outline', 'overflow',
|
|
14
|
+
'padding', 'padding-bottom', 'padding-left', 'padding-right', 'padding-top',
|
|
15
|
+
'position', 'right', 'text-align', 'text-decoration', 'text-transform',
|
|
16
|
+
'top', 'transform', 'transition', 'transition-delay', 'transition-duration',
|
|
17
|
+
'transition-property', 'transition-timing-function', 'width', 'z-index'
|
|
18
|
+
];
|