chaincss 1.13.2 → 2.0.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.
Files changed (101) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/LICENSE +2 -3
  3. package/README.md +239 -114
  4. package/dist/cli/commands/build.d.ts +3 -0
  5. package/dist/cli/commands/build.d.ts.map +1 -0
  6. package/dist/cli/commands/compile.d.ts +3 -0
  7. package/dist/cli/commands/compile.d.ts.map +1 -0
  8. package/dist/cli/commands/init.d.ts +5 -0
  9. package/dist/cli/commands/init.d.ts.map +1 -0
  10. package/dist/cli/commands/timeline.d.ts +2 -0
  11. package/dist/cli/commands/timeline.d.ts.map +1 -0
  12. package/dist/cli/commands/watch.d.ts +6 -0
  13. package/dist/cli/commands/watch.d.ts.map +1 -0
  14. package/dist/cli/index.d.ts +2 -0
  15. package/dist/cli/index.d.ts.map +1 -0
  16. package/dist/cli/index.js +5960 -0
  17. package/dist/cli/types.d.ts +51 -0
  18. package/dist/cli/types.d.ts.map +1 -0
  19. package/dist/cli/utils/config-loader.d.ts +8 -0
  20. package/dist/cli/utils/config-loader.d.ts.map +1 -0
  21. package/dist/cli/utils/file-utils.d.ts +9 -0
  22. package/dist/cli/utils/file-utils.d.ts.map +1 -0
  23. package/dist/cli/utils/logger.d.ts +17 -0
  24. package/dist/cli/utils/logger.d.ts.map +1 -0
  25. package/dist/compiler/atomic-optimizer.d.ts +76 -0
  26. package/dist/compiler/atomic-optimizer.d.ts.map +1 -0
  27. package/dist/compiler/btt.d.ts +138 -0
  28. package/dist/compiler/btt.d.ts.map +1 -0
  29. package/dist/compiler/cache-manager.d.ts +20 -0
  30. package/dist/compiler/cache-manager.d.ts.map +1 -0
  31. package/dist/compiler/commonProps.d.ts +2 -0
  32. package/dist/compiler/commonProps.d.ts.map +1 -0
  33. package/dist/compiler/index.d.ts +12 -0
  34. package/dist/compiler/index.d.ts.map +1 -0
  35. package/dist/compiler/index.js +5177 -0
  36. package/dist/compiler/prefixer.d.ts +42 -0
  37. package/dist/compiler/prefixer.d.ts.map +1 -0
  38. package/dist/compiler/theme-contract.d.ts +61 -0
  39. package/dist/compiler/theme-contract.d.ts.map +1 -0
  40. package/dist/compiler/tokens.d.ts +52 -0
  41. package/dist/compiler/tokens.d.ts.map +1 -0
  42. package/dist/compiler/types.d.ts +57 -0
  43. package/dist/compiler/types.d.ts.map +1 -0
  44. package/dist/core/compiler.d.ts +32 -0
  45. package/dist/core/compiler.d.ts.map +1 -0
  46. package/dist/core/constants.d.ts +129 -0
  47. package/dist/core/constants.d.ts.map +1 -0
  48. package/dist/core/index.d.ts +4 -0
  49. package/dist/core/index.d.ts.map +1 -0
  50. package/dist/core/types.d.ts +88 -0
  51. package/dist/core/types.d.ts.map +1 -0
  52. package/dist/core/utils.d.ts +37 -0
  53. package/dist/core/utils.d.ts.map +1 -0
  54. package/dist/index.d.ts +13 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +5667 -0
  57. package/dist/plugins/vite.d.ts +11 -0
  58. package/dist/plugins/vite.d.ts.map +1 -0
  59. package/dist/plugins/vite.js +25839 -0
  60. package/dist/plugins/webpack.d.ts +45 -0
  61. package/dist/plugins/webpack.d.ts.map +1 -0
  62. package/dist/plugins/webpack.js +107 -0
  63. package/dist/runtime/hmr.d.ts +3 -0
  64. package/dist/runtime/hmr.d.ts.map +1 -0
  65. package/dist/runtime/index.d.ts +15 -0
  66. package/dist/runtime/index.d.ts.map +1 -0
  67. package/dist/runtime/index.js +552 -0
  68. package/dist/runtime/injector.d.ts +85 -0
  69. package/dist/runtime/injector.d.ts.map +1 -0
  70. package/dist/runtime/react.d.ts +54 -0
  71. package/dist/runtime/react.d.ts.map +1 -0
  72. package/dist/runtime/react.js +270 -0
  73. package/dist/runtime/types.d.ts +45 -0
  74. package/dist/runtime/types.d.ts.map +1 -0
  75. package/dist/runtime/utils.d.ts +62 -0
  76. package/dist/runtime/utils.d.ts.map +1 -0
  77. package/dist/runtime/vue.d.ts +52 -0
  78. package/dist/runtime/vue.d.ts.map +1 -0
  79. package/dist/runtime/vue.js +232 -0
  80. package/package.json +90 -109
  81. package/browser/commonProps.js +0 -14
  82. package/browser/index.js +0 -3
  83. package/browser/react-hooks.js +0 -162
  84. package/browser/rtt.js +0 -370
  85. package/node/atomic-optimizer.js +0 -391
  86. package/node/btt.js +0 -962
  87. package/node/cache-manager.js +0 -56
  88. package/node/chaincss.js +0 -489
  89. package/node/css-properties.json +0 -633
  90. package/node/index.js +0 -2
  91. package/node/loaders/chaincss-loader.js +0 -62
  92. package/node/plugins/next-plugin.js +0 -120
  93. package/node/plugins/vite-plugin.js +0 -383
  94. package/node/plugins/webpack-plugin.js +0 -41
  95. package/node/prefixer.js +0 -237
  96. package/node/strVal.js +0 -106
  97. package/node/theme-validator.js +0 -32
  98. package/shared/theme-contract.js +0 -98
  99. package/shared/tokens.cjs +0 -256
  100. package/shared/tokens.mjs +0 -320
  101. package/types.d.ts +0 -277
@@ -1,391 +0,0 @@
1
- const crypto = require('crypto');
2
- const path = require('path');
3
- const fs = require('fs');
4
-
5
- function hashKey(key) {
6
- return crypto.createHash('sha1').update(key).digest('hex').slice(0, 6);
7
- }
8
-
9
- function kebab(s) {
10
- return s.replace(/([A-Z])/g, '-$1').toLowerCase();
11
- }
12
-
13
- class AtomicOptimizer {
14
- constructor(options = {}) {
15
- this.options = {
16
- enabled: true,
17
- threshold: 3, // Default threshold
18
- naming: 'hash', // 'hash' | 'readable'
19
- cache: true,
20
- cachePath: './.chaincss-cache',
21
- minify: true,
22
- alwaysAtomic: [], // Force these props to be atomic
23
- neverAtomic: [ // Never make these atomic
24
- 'content', 'animation', 'transition', 'keyframes',
25
- 'counterIncrement', 'counterReset'
26
- ],
27
- ...options
28
- };
29
-
30
- this.usageCount = new Map(); // prop:value -> count
31
- this.atomicClasses = new Map(); // prop:value -> { className, prop, value, usageCount }
32
- this.stats = {
33
- totalStyles: 0,
34
- atomicStyles: 0,
35
- standardStyles: 0,
36
- uniqueProperties: 0,
37
- savings: 0
38
- };
39
-
40
- if (this.options.cache) {
41
- this.loadCache();
42
- }
43
- }
44
-
45
- // ============================================================================
46
- // Cache Management
47
- // ============================================================================
48
-
49
- loadCache() {
50
- try {
51
- if (!fs.existsSync(this.options.cachePath)) return;
52
-
53
- const data = JSON.parse(fs.readFileSync(this.options.cachePath, 'utf8'));
54
-
55
- // Version check
56
- if (data.version !== '1.0.0') {
57
- console.log('Cache version mismatch, creating new cache');
58
- return;
59
- }
60
-
61
- // Check if config changed
62
- if (data.config?.threshold !== this.options.threshold) {
63
- console.log(`Cache threshold (${data.config?.threshold}) differs from current (${this.options.threshold})`);
64
- return;
65
- }
66
-
67
- this.atomicClasses = new Map(data.atomicClasses || []);
68
- this.stats = data.stats || this.stats;
69
-
70
- const cacheTime = new Date(data.timestamp).toLocaleString();
71
- console.log(`✅ Loaded ${this.atomicClasses.size} atomic classes from cache (${cacheTime})`);
72
-
73
- } catch (err) {
74
- console.log('Could not load cache:', err.message);
75
- }
76
- }
77
-
78
- saveCache() {
79
- if (!this.options.cache) return;
80
-
81
- try {
82
- const cacheDir = path.dirname(this.options.cachePath);
83
- if (!fs.existsSync(cacheDir)) {
84
- fs.mkdirSync(cacheDir, { recursive: true });
85
- }
86
-
87
- // Clean up old cache files (keep last 5)
88
- if (fs.existsSync(cacheDir)) {
89
- const files = fs.readdirSync(cacheDir)
90
- .filter(f => f.startsWith('.chaincss-cache'))
91
- .map(f => ({
92
- name: f,
93
- time: fs.statSync(path.join(cacheDir, f)).mtime.getTime()
94
- }))
95
- .sort((a, b) => b.time - a.time);
96
-
97
- // Keep only the 5 most recent cache files
98
- files.slice(5).forEach(f => {
99
- try { fs.unlinkSync(path.join(cacheDir, f.name)); } catch {}
100
- });
101
- }
102
-
103
- const cache = {
104
- version: '1.0.0',
105
- timestamp: Date.now(),
106
- atomicClasses: Array.from(this.atomicClasses.entries()),
107
- stats: this.stats,
108
- config: {
109
- threshold: this.options.threshold,
110
- naming: this.options.naming
111
- }
112
- };
113
-
114
- fs.writeFileSync(this.options.cachePath, JSON.stringify(cache, null, 2), 'utf8');
115
- } catch (err) {
116
- console.log('Could not save cache:', err.message);
117
- }
118
- }
119
-
120
- // ============================================================================
121
- // Style Tracking
122
- // ============================================================================
123
-
124
- trackStyles(styles) {
125
- const styleArray = Array.isArray(styles) ? styles : Object.values(styles);
126
-
127
- for (const style of styleArray) {
128
- if (!style || !style.selectors) continue;
129
-
130
- for (const [prop, value] of Object.entries(style)) {
131
- if (prop === 'selectors' || prop === 'atRules' || prop === 'hover') continue;
132
-
133
- const key = `${prop}:${value}`;
134
- this.usageCount.set(key, (this.usageCount.get(key) || 0) + 1);
135
- this.stats.totalStyles++;
136
- }
137
- }
138
-
139
- this.stats.uniqueProperties = this.usageCount.size;
140
- }
141
-
142
- shouldBeAtomic(prop, value) {
143
- // Never atomic
144
- if (this.options.neverAtomic.includes(prop)) return false;
145
-
146
- // Always atomic
147
- if (this.options.alwaysAtomic.includes(prop)) return true;
148
-
149
- // Critical props that need higher threshold
150
- const criticalProps = ['position', 'display', 'flex', 'grid', 'zIndex', 'top', 'left', 'right', 'bottom'];
151
- const isCritical = criticalProps.includes(prop);
152
-
153
- const key = `${prop}:${value}`;
154
- const usage = this.usageCount.get(key) || 0;
155
-
156
- // Critical props need double threshold to be atomic
157
- if (isCritical && usage < this.options.threshold * 2) {
158
- return false;
159
- }
160
-
161
- return usage >= this.options.threshold;
162
- }
163
-
164
- generateClassName(prop, value) {
165
- const key = `${prop}:${value}`;
166
-
167
- if (this.options.naming === 'hash') {
168
- return `c_${hashKey(key)}`;
169
- }
170
-
171
- // Readable naming
172
- const kebabProp = kebab(prop);
173
- const safeValue = String(value).replace(/[^a-z0-9_-]/gi, '-').slice(0, 30);
174
- return `${kebabProp}-${safeValue}`;
175
- }
176
-
177
- getOrCreateAtomic(prop, value) {
178
- const key = `${prop}:${value}`;
179
-
180
- if (!this.atomicClasses.has(key)) {
181
- const className = this.generateClassName(prop, value);
182
- this.atomicClasses.set(key, {
183
- className,
184
- prop,
185
- value,
186
- usageCount: this.usageCount.get(key) || 0
187
- });
188
- this.stats.atomicStyles++;
189
- }
190
-
191
- return this.atomicClasses.get(key).className;
192
- }
193
-
194
- // ============================================================================
195
- // CSS Generation
196
- // ============================================================================
197
-
198
- generateAtomicCSS() {
199
- let css = '';
200
- const sortedClasses = Array.from(this.atomicClasses.values())
201
- .sort((a, b) => b.usageCount - a.usageCount);
202
-
203
- for (const atomic of sortedClasses) {
204
- const kebabProp = kebab(atomic.prop);
205
- css += `.${atomic.className}{${kebabProp}:${atomic.value}${this.options.minify ? '' : ';'}}\n`;
206
- }
207
-
208
- return css;
209
- }
210
-
211
- generateComponentCSS(componentName, style, selectors) {
212
- const atomicClasses = [];
213
- const standardStyles = {};
214
- const hoverStyles = {};
215
-
216
- // Separate styles
217
- for (const [prop, value] of Object.entries(style)) {
218
- if (prop === 'selectors' || prop === 'atRules') continue;
219
-
220
- if (prop === 'hover' && typeof value === 'object') {
221
- // Handle hover styles
222
- for (const [hoverProp, hoverValue] of Object.entries(value)) {
223
- if (this.shouldBeAtomic(hoverProp, hoverValue)) {
224
- atomicClasses.push(this.getOrCreateAtomic(hoverProp, hoverValue));
225
- } else {
226
- hoverStyles[hoverProp] = hoverValue;
227
- }
228
- }
229
- } else if (this.shouldBeAtomic(prop, value)) {
230
- atomicClasses.push(this.getOrCreateAtomic(prop, value));
231
- } else {
232
- standardStyles[prop] = value;
233
- }
234
- }
235
-
236
- // Generate CSS
237
- let componentCSS = '';
238
- const selectorStr = selectors.join(', ');
239
-
240
- if (atomicClasses.length > 0 || Object.keys(standardStyles).length > 0) {
241
- componentCSS += `${selectorStr} {\n`;
242
-
243
- // Atomic classes (inlined for specificity)
244
- for (const className of atomicClasses) {
245
- const atomic = this.findAtomicByClassName(className);
246
- if (atomic) {
247
- const kebabProp = kebab(atomic.prop);
248
- componentCSS += ` ${kebabProp}: ${atomic.value};\n`;
249
- }
250
- }
251
-
252
- // Standard styles
253
- for (const [prop, value] of Object.entries(standardStyles)) {
254
- const kebabProp = kebab(prop);
255
- componentCSS += ` ${kebabProp}: ${value};\n`;
256
- }
257
-
258
- componentCSS += `}\n`;
259
- }
260
-
261
- // Hover styles
262
- if (Object.keys(hoverStyles).length > 0) {
263
- componentCSS += `${selectorStr}:hover {\n`;
264
- for (const [prop, value] of Object.entries(hoverStyles)) {
265
- const kebabProp = kebab(prop);
266
- componentCSS += ` ${kebabProp}: ${value};\n`;
267
- }
268
- componentCSS += `}\n`;
269
- }
270
-
271
- return componentCSS;
272
- }
273
-
274
- findAtomicByClassName(className) {
275
- for (const atomic of this.atomicClasses.values()) {
276
- if (atomic.className === className) return atomic;
277
- }
278
- return null;
279
- }
280
-
281
- validateStyleOrder(originalStyles, atomicStyles) {
282
- const originalProps = new Set();
283
- const atomicProps = new Set();
284
-
285
- const styleArray = Array.isArray(originalStyles) ? originalStyles : Object.values(originalStyles);
286
- for (const style of styleArray) {
287
- if (!style) continue;
288
- for (const prop of Object.keys(style)) {
289
- if (prop !== 'selectors' && prop !== 'atRules' && prop !== 'hover') {
290
- originalProps.add(prop);
291
- }
292
- }
293
- }
294
-
295
- for (const atomic of this.atomicClasses.values()) {
296
- atomicProps.add(atomic.prop);
297
- }
298
-
299
- const missingProps = [...originalProps].filter(p => !atomicProps.has(p));
300
- if (missingProps.length > 0) {
301
- console.warn('⚠️ Missing atomic classes for:', missingProps.slice(0, 10));
302
- }
303
- }
304
-
305
- getStats() {
306
- const savings = this.stats.totalStyles > 0
307
- ? ((this.stats.totalStyles - this.stats.atomicStyles) / this.stats.totalStyles * 100).toFixed(1)
308
- : 0;
309
-
310
- return {
311
- totalStyles: this.stats.totalStyles,
312
- atomicStyles: this.stats.atomicStyles,
313
- standardStyles: this.stats.standardStyles,
314
- uniqueProperties: this.stats.uniqueProperties,
315
- savings: `${savings}%`
316
- };
317
- }
318
-
319
- // ============================================================================
320
- // Main Optimize Method
321
- // ============================================================================
322
-
323
- optimize(stylesInput) {
324
- if (!this.options.enabled) {
325
- return {
326
- css: '',
327
- map: {},
328
- stats: this.getStats(),
329
- atomicCSS: ''
330
- };
331
- }
332
-
333
- // Normalize input to array
334
- const styleArray = Array.isArray(stylesInput)
335
- ? stylesInput
336
- : typeof stylesInput === 'object'
337
- ? Object.values(stylesInput)
338
- : [];
339
-
340
- // Track usage counts
341
- this.trackStyles(styleArray);
342
-
343
- // Generate CSS
344
- let atomicCSS = this.generateAtomicCSS();
345
- let componentCSS = '';
346
- const classMap = {};
347
-
348
- for (const style of styleArray) {
349
- if (!style || !style.selectors) continue;
350
-
351
- const selectors = style.selectors;
352
- const selectorKey = selectors.join(', ');
353
-
354
- // Generate component CSS
355
- componentCSS += this.generateComponentCSS(style.name || 'component', style, selectors);
356
-
357
- // Build class map for users
358
- const atomicClassesForSelector = [];
359
- for (const [prop, value] of Object.entries(style)) {
360
- if (prop === 'selectors' || prop === 'atRules' || prop === 'hover') continue;
361
- if (this.shouldBeAtomic(prop, value)) {
362
- atomicClassesForSelector.push(this.getOrCreateAtomic(prop, value));
363
- }
364
- }
365
- classMap[selectorKey] = atomicClassesForSelector.join(' ');
366
- }
367
-
368
- // Validation
369
- this.validateStyleOrder(styleArray);
370
-
371
- // Save cache
372
- if (this.options.cache) {
373
- this.saveCache();
374
- }
375
-
376
- // Calculate savings
377
- const savings = this.stats.totalStyles > 0
378
- ? ((this.stats.totalStyles - this.atomicClasses.size) / this.stats.totalStyles * 100).toFixed(1)
379
- : 0;
380
-
381
- return {
382
- css: (atomicCSS + componentCSS).trim(),
383
- map: classMap,
384
- stats: this.getStats(),
385
- atomicCSS: atomicCSS.trim(),
386
- componentCSS: componentCSS.trim()
387
- };
388
- }
389
- }
390
-
391
- module.exports = { AtomicOptimizer };