@luna_ui/luna 0.11.0 → 0.17.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/dist/api-DAWeanTX.js +1 -0
- package/dist/api-qXll116-.d.ts +80 -0
- package/dist/cli.mjs +27 -22
- package/dist/css/index.js +1 -0
- package/dist/event-utils.d.ts +1 -1
- package/dist/event-utils.js +1 -1
- package/dist/{index-BZoM-af5.d.ts → index-VY8G32hr.d.ts} +16 -76
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/jsx-dev-runtime.js +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/dist/raw.d.ts +2 -0
- package/dist/raw.js +1 -0
- package/dist/resource.d.ts +41 -0
- package/dist/resource.js +1 -0
- package/dist/router-lite.d.ts +44 -0
- package/dist/router-lite.js +1 -0
- package/dist/signals-shared.d.ts +12 -0
- package/dist/signals-shared.js +1 -0
- package/dist/signals.d.ts +2 -3
- package/dist/signals.js +1 -1
- package/dist/vite-plugin.d.ts +7708 -2
- package/dist/vite-plugin.js +7 -6
- package/package.json +30 -11
- package/dist/event-utils-9cHYnvun.js +0 -1
- package/dist/src-BFWjzzPo.js +0 -1
- package/src/css/extract.ts +0 -798
- package/src/css/index.ts +0 -10
- package/src/css/inject.ts +0 -205
- package/src/css/inline.ts +0 -182
- package/src/css/minify.ts +0 -70
- package/src/css/optimizer.ts +0 -6
- package/src/css/runtime.ts +0 -344
- package/src/css-optimizer/README.md +0 -353
- package/src/css-optimizer/cooccurrence.ts +0 -100
- package/src/css-optimizer/core.ts +0 -263
- package/src/css-optimizer/extractors.ts +0 -243
- package/src/css-optimizer/hash.ts +0 -54
- package/src/css-optimizer/index.ts +0 -129
- package/src/css-optimizer/merge.ts +0 -109
- package/src/css-optimizer/moonbit-analyzer.ts +0 -210
- package/src/css-optimizer/parser.ts +0 -120
- package/src/css-optimizer/pattern.ts +0 -171
- package/src/css-optimizer/transformers.ts +0 -301
- package/src/css-optimizer/types.ts +0 -128
- package/src/event-utils.ts +0 -227
- package/src/hydration/createHydrator.ts +0 -62
- package/src/hydration/delegate.ts +0 -62
- package/src/hydration/drag.ts +0 -214
- package/src/hydration/index.ts +0 -12
- package/src/hydration/keyboard.ts +0 -64
- package/src/hydration/toggle.ts +0 -101
- package/src/index.ts +0 -908
- package/src/jsx-dev-runtime.ts +0 -2
- package/src/jsx-runtime.ts +0 -398
- package/src/signals.ts +0 -113
- package/src/vite-plugin.ts +0 -718
- package/tests/__screenshots__/apg.test.ts/APG-Components---Accessibility-Tests-Button-Pattern-disabled-button-has-aria-disabled-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API--SolidJS-style--createResource-error-is-undefined-when-pending-1.png +0 -0
- package/tests/__screenshots__/resource.test.ts/Resource-API--SolidJS-style--createResource-transitions-to-success-on-resolve-1.png +0 -0
- package/tests/apg.test.ts +0 -466
- package/tests/context.test.ts +0 -118
- package/tests/css-optimizer-extractors.test.ts +0 -264
- package/tests/css-optimizer-integration.test.ts +0 -566
- package/tests/css-optimizer-transformers.test.ts +0 -301
- package/tests/css-optimizer.test.ts +0 -646
- package/tests/css-runtime.bench.ts +0 -442
- package/tests/css-runtime.test.ts +0 -342
- package/tests/debounced.test.ts +0 -165
- package/tests/dom.test.ts +0 -873
- package/tests/integration.test.ts +0 -405
- package/tests/issue-11-show-null-to-truthy.test.ts +0 -176
- package/tests/issue-5-for-infinite-loop.test.ts +0 -516
- package/tests/jsx-runtime.test.tsx +0 -393
- package/tests/lifecycle.test.ts +0 -833
- package/tests/move-before.bench.ts +0 -304
- package/tests/preact-signals-comparison.test.ts +0 -1608
- package/tests/resource.test.ts +0 -170
- package/tests/router.test.ts +0 -117
- package/tests/show-initial-mount-leak.test.tsx +0 -182
- package/tests/solidjs-api.test.ts +0 -660
- package/tests/static-perf.bench.ts +0 -64
- package/tests/store.test.ts +0 -263
- package/tests/tsx-syntax.test.tsx +0 -404
- /package/dist/{event-utils-BkTM7rk5.d.ts → event-utils-BvAf0NwN.d.ts} +0 -0
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Frequent pattern mining for CSS classes
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { ClassUsage, MergePattern } from "./types.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Find frequent patterns (sets of classes that often appear together)
|
|
9
|
-
* Uses a greedy enumeration approach for small pattern sizes
|
|
10
|
-
*/
|
|
11
|
-
export function findFrequentPatterns(
|
|
12
|
-
usages: ClassUsage[],
|
|
13
|
-
minFrequency: number,
|
|
14
|
-
maxSize: number
|
|
15
|
-
): MergePattern[] {
|
|
16
|
-
// Count all class set patterns
|
|
17
|
-
const patternCounts = new Map<string, number>();
|
|
18
|
-
|
|
19
|
-
for (const usage of usages) {
|
|
20
|
-
const classes = [...usage.classes].sort();
|
|
21
|
-
const n = classes.length;
|
|
22
|
-
|
|
23
|
-
// Count pairs (size 2)
|
|
24
|
-
for (let i = 0; i < n; i++) {
|
|
25
|
-
for (let j = i + 1; j < n; j++) {
|
|
26
|
-
const key = `${classes[i]}|${classes[j]}`;
|
|
27
|
-
patternCounts.set(key, (patternCounts.get(key) || 0) + 1);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Count triples (size 3)
|
|
32
|
-
if (maxSize >= 3) {
|
|
33
|
-
for (let i = 0; i < n; i++) {
|
|
34
|
-
for (let j = i + 1; j < n; j++) {
|
|
35
|
-
for (let k = j + 1; k < n; k++) {
|
|
36
|
-
const key = `${classes[i]}|${classes[j]}|${classes[k]}`;
|
|
37
|
-
patternCounts.set(key, (patternCounts.get(key) || 0) + 1);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Count quadruples (size 4)
|
|
44
|
-
if (maxSize >= 4) {
|
|
45
|
-
for (let i = 0; i < n; i++) {
|
|
46
|
-
for (let j = i + 1; j < n; j++) {
|
|
47
|
-
for (let k = j + 1; k < n; k++) {
|
|
48
|
-
for (let l = k + 1; l < n; l++) {
|
|
49
|
-
const key = `${classes[i]}|${classes[j]}|${classes[k]}|${classes[l]}`;
|
|
50
|
-
patternCounts.set(key, (patternCounts.get(key) || 0) + 1);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Count quintuples (size 5)
|
|
58
|
-
if (maxSize >= 5) {
|
|
59
|
-
for (let i = 0; i < n; i++) {
|
|
60
|
-
for (let j = i + 1; j < n; j++) {
|
|
61
|
-
for (let k = j + 1; k < n; k++) {
|
|
62
|
-
for (let l = k + 1; l < n; l++) {
|
|
63
|
-
for (let m = l + 1; m < n; m++) {
|
|
64
|
-
const key = `${classes[i]}|${classes[j]}|${classes[k]}|${classes[l]}|${classes[m]}`;
|
|
65
|
-
patternCounts.set(key, (patternCounts.get(key) || 0) + 1);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Filter by min frequency and create patterns
|
|
75
|
-
const patterns: MergePattern[] = [];
|
|
76
|
-
|
|
77
|
-
for (const [key, frequency] of patternCounts) {
|
|
78
|
-
if (frequency >= minFrequency) {
|
|
79
|
-
const originalClasses = key.split("|");
|
|
80
|
-
const classCount = originalClasses.length;
|
|
81
|
-
|
|
82
|
-
// Estimate savings:
|
|
83
|
-
// HTML: each class is ~6 chars + space, merged saves (n-1) * 7 * frequency
|
|
84
|
-
// CSS: each rule is ~25 bytes, merged saves (n-1) * 25
|
|
85
|
-
const htmlSavings = (classCount - 1) * 7 * frequency;
|
|
86
|
-
const cssSavings = (classCount - 1) * 25;
|
|
87
|
-
const bytesSaved = htmlSavings + cssSavings;
|
|
88
|
-
|
|
89
|
-
patterns.push({
|
|
90
|
-
originalClasses,
|
|
91
|
-
mergedClass: "", // Will be set during merge
|
|
92
|
-
declarations: [], // Will be set during merge
|
|
93
|
-
frequency,
|
|
94
|
-
bytesSaved,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Sort by bytes saved descending
|
|
100
|
-
patterns.sort((a, b) => b.bytesSaved - a.bytesSaved);
|
|
101
|
-
|
|
102
|
-
// Remove subsumed patterns
|
|
103
|
-
return removeSubsumedPatterns(patterns);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Remove patterns that are subsets of larger patterns with similar frequency
|
|
108
|
-
* This prevents double-counting savings
|
|
109
|
-
*/
|
|
110
|
-
export function removeSubsumedPatterns(patterns: MergePattern[]): MergePattern[] {
|
|
111
|
-
const result: MergePattern[] = [];
|
|
112
|
-
|
|
113
|
-
for (let i = 0; i < patterns.length; i++) {
|
|
114
|
-
const pattern = patterns[i];
|
|
115
|
-
let isDominated = false;
|
|
116
|
-
|
|
117
|
-
for (let j = 0; j < patterns.length; j++) {
|
|
118
|
-
if (i === j) continue;
|
|
119
|
-
|
|
120
|
-
const other = patterns[j];
|
|
121
|
-
// Check if other is a superset with similar or higher frequency (80% threshold)
|
|
122
|
-
if (
|
|
123
|
-
other.originalClasses.length > pattern.originalClasses.length &&
|
|
124
|
-
other.frequency >= pattern.frequency * 0.8
|
|
125
|
-
) {
|
|
126
|
-
const patternSet = new Set(pattern.originalClasses);
|
|
127
|
-
const otherSet = new Set(other.originalClasses);
|
|
128
|
-
|
|
129
|
-
// Check if pattern is subset of other
|
|
130
|
-
let isSubset = true;
|
|
131
|
-
for (const cls of patternSet) {
|
|
132
|
-
if (!otherSet.has(cls)) {
|
|
133
|
-
isSubset = false;
|
|
134
|
-
break;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (isSubset) {
|
|
139
|
-
isDominated = true;
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (!isDominated) {
|
|
146
|
-
result.push(pattern);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return result;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Group usages by their exact class set
|
|
155
|
-
* Returns a map from sorted class key to array of usages
|
|
156
|
-
*/
|
|
157
|
-
export function groupByClassSet(
|
|
158
|
-
usages: ClassUsage[]
|
|
159
|
-
): Map<string, ClassUsage[]> {
|
|
160
|
-
const groups = new Map<string, ClassUsage[]>();
|
|
161
|
-
|
|
162
|
-
for (const usage of usages) {
|
|
163
|
-
const key = [...usage.classes].sort().join("|");
|
|
164
|
-
if (!groups.has(key)) {
|
|
165
|
-
groups.set(key, []);
|
|
166
|
-
}
|
|
167
|
-
groups.get(key)!.push(usage);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return groups;
|
|
171
|
-
}
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CSS Co-occurrence Optimizer - Transformers
|
|
3
|
-
*
|
|
4
|
-
* Pluggable output transformation strategies for different formats.
|
|
5
|
-
* Each transformer applies merge maps to source content.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Transformer interface - implement this for custom output formats
|
|
10
|
-
*/
|
|
11
|
-
export interface ClassTransformer {
|
|
12
|
-
/** Transformer name for debugging */
|
|
13
|
-
name: string;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Transform content by applying merge map
|
|
17
|
-
* @param content - Source content to transform
|
|
18
|
-
* @param mergeMap - Mapping from "class1 class2" to "merged_class"
|
|
19
|
-
* @param options - Transformer-specific options
|
|
20
|
-
*/
|
|
21
|
-
transform(
|
|
22
|
-
content: string,
|
|
23
|
-
mergeMap: Map<string, string>,
|
|
24
|
-
options?: TransformerOptions
|
|
25
|
-
): string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Common transformer options
|
|
30
|
-
*/
|
|
31
|
-
export interface TransformerOptions {
|
|
32
|
-
/** Class prefix for identifying mergeable classes (default: "_") */
|
|
33
|
-
classPrefix?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* HTML Transformer
|
|
38
|
-
*
|
|
39
|
-
* Transforms HTML by replacing class="" attribute values with merged classes.
|
|
40
|
-
*/
|
|
41
|
-
export class HtmlTransformer implements ClassTransformer {
|
|
42
|
-
name = "html";
|
|
43
|
-
|
|
44
|
-
private pattern = /class\s*=\s*"([^"]+)"/g;
|
|
45
|
-
|
|
46
|
-
transform(
|
|
47
|
-
content: string,
|
|
48
|
-
mergeMap: Map<string, string>,
|
|
49
|
-
options: TransformerOptions = {}
|
|
50
|
-
): string {
|
|
51
|
-
if (mergeMap.size === 0) {
|
|
52
|
-
return content;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const { classPrefix = "_" } = options;
|
|
56
|
-
|
|
57
|
-
// Sort merge keys by length descending (longer patterns first)
|
|
58
|
-
const sortedKeys = [...mergeMap.keys()].sort((a, b) => b.length - a.length);
|
|
59
|
-
|
|
60
|
-
return content.replace(this.pattern, (match, classValue) => {
|
|
61
|
-
const classes = classValue.trim().split(/\s+/);
|
|
62
|
-
const prefixedClasses = classes.filter((c: string) => c.startsWith(classPrefix));
|
|
63
|
-
const otherClasses = classes.filter((c: string) => !c.startsWith(classPrefix));
|
|
64
|
-
|
|
65
|
-
// Sort for consistent matching
|
|
66
|
-
prefixedClasses.sort();
|
|
67
|
-
|
|
68
|
-
let result = [...prefixedClasses];
|
|
69
|
-
const merged: string[] = [];
|
|
70
|
-
|
|
71
|
-
// Apply each merge pattern
|
|
72
|
-
for (const key of sortedKeys) {
|
|
73
|
-
const patternClasses = key.split(" ");
|
|
74
|
-
const mergedClass = mergeMap.get(key)!;
|
|
75
|
-
|
|
76
|
-
// Check if all pattern classes are present
|
|
77
|
-
let allPresent = true;
|
|
78
|
-
for (const cls of patternClasses) {
|
|
79
|
-
if (!result.includes(cls)) {
|
|
80
|
-
allPresent = false;
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (allPresent) {
|
|
86
|
-
result = result.filter((c) => !patternClasses.includes(c));
|
|
87
|
-
merged.push(mergedClass);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const finalClasses = [...merged, ...result, ...otherClasses].join(" ");
|
|
92
|
-
return `class="${finalClasses}"`;
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* JSX Transformer
|
|
99
|
-
*
|
|
100
|
-
* Transforms JSX/TSX by replacing className attribute values.
|
|
101
|
-
*/
|
|
102
|
-
export class JsxTransformer implements ClassTransformer {
|
|
103
|
-
name = "jsx";
|
|
104
|
-
|
|
105
|
-
private stringPattern = /className\s*=\s*"([^"]+)"/g;
|
|
106
|
-
|
|
107
|
-
transform(
|
|
108
|
-
content: string,
|
|
109
|
-
mergeMap: Map<string, string>,
|
|
110
|
-
options: TransformerOptions = {}
|
|
111
|
-
): string {
|
|
112
|
-
if (mergeMap.size === 0) {
|
|
113
|
-
return content;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const { classPrefix = "_" } = options;
|
|
117
|
-
const sortedKeys = [...mergeMap.keys()].sort((a, b) => b.length - a.length);
|
|
118
|
-
|
|
119
|
-
return content.replace(this.stringPattern, (match, classValue) => {
|
|
120
|
-
const classes = classValue.trim().split(/\s+/);
|
|
121
|
-
const prefixedClasses = classes.filter((c: string) => c.startsWith(classPrefix));
|
|
122
|
-
const otherClasses = classes.filter((c: string) => !c.startsWith(classPrefix));
|
|
123
|
-
|
|
124
|
-
prefixedClasses.sort();
|
|
125
|
-
|
|
126
|
-
let result = [...prefixedClasses];
|
|
127
|
-
const merged: string[] = [];
|
|
128
|
-
|
|
129
|
-
for (const key of sortedKeys) {
|
|
130
|
-
const patternClasses = key.split(" ");
|
|
131
|
-
const mergedClass = mergeMap.get(key)!;
|
|
132
|
-
|
|
133
|
-
let allPresent = true;
|
|
134
|
-
for (const cls of patternClasses) {
|
|
135
|
-
if (!result.includes(cls)) {
|
|
136
|
-
allPresent = false;
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (allPresent) {
|
|
142
|
-
result = result.filter((c) => !patternClasses.includes(c));
|
|
143
|
-
merged.push(mergedClass);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const finalClasses = [...merged, ...result, ...otherClasses].join(" ");
|
|
148
|
-
return `className="${finalClasses}"`;
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Svelte Transformer
|
|
155
|
-
*
|
|
156
|
-
* Transforms Svelte templates by replacing class attribute values.
|
|
157
|
-
* Preserves dynamic {expression} syntax.
|
|
158
|
-
*/
|
|
159
|
-
export class SvelteTransformer implements ClassTransformer {
|
|
160
|
-
name = "svelte";
|
|
161
|
-
|
|
162
|
-
private pattern = /class\s*=\s*"([^"]+)"/g;
|
|
163
|
-
|
|
164
|
-
transform(
|
|
165
|
-
content: string,
|
|
166
|
-
mergeMap: Map<string, string>,
|
|
167
|
-
options: TransformerOptions = {}
|
|
168
|
-
): string {
|
|
169
|
-
if (mergeMap.size === 0) {
|
|
170
|
-
return content;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const { classPrefix = "_" } = options;
|
|
174
|
-
const sortedKeys = [...mergeMap.keys()].sort((a, b) => b.length - a.length);
|
|
175
|
-
|
|
176
|
-
return content.replace(this.pattern, (match, classValue) => {
|
|
177
|
-
// Preserve dynamic expressions
|
|
178
|
-
const expressions: string[] = [];
|
|
179
|
-
const cleanValue = classValue.replace(/\{[^}]+\}/g, (expr: string) => {
|
|
180
|
-
expressions.push(expr);
|
|
181
|
-
return `__EXPR_${expressions.length - 1}__`;
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
const classes = cleanValue.trim().split(/\s+/);
|
|
185
|
-
const prefixedClasses = classes.filter(
|
|
186
|
-
(c: string) => c.startsWith(classPrefix) && !c.startsWith("__EXPR_")
|
|
187
|
-
);
|
|
188
|
-
const otherClasses = classes.filter(
|
|
189
|
-
(c: string) => !c.startsWith(classPrefix) || c.startsWith("__EXPR_")
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
prefixedClasses.sort();
|
|
193
|
-
|
|
194
|
-
let result = [...prefixedClasses];
|
|
195
|
-
const merged: string[] = [];
|
|
196
|
-
|
|
197
|
-
for (const key of sortedKeys) {
|
|
198
|
-
const patternClasses = key.split(" ");
|
|
199
|
-
const mergedClass = mergeMap.get(key)!;
|
|
200
|
-
|
|
201
|
-
let allPresent = true;
|
|
202
|
-
for (const cls of patternClasses) {
|
|
203
|
-
if (!result.includes(cls)) {
|
|
204
|
-
allPresent = false;
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (allPresent) {
|
|
210
|
-
result = result.filter((c) => !patternClasses.includes(c));
|
|
211
|
-
merged.push(mergedClass);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
let finalClasses = [...merged, ...result, ...otherClasses].join(" ");
|
|
216
|
-
|
|
217
|
-
// Restore expressions
|
|
218
|
-
expressions.forEach((expr, i) => {
|
|
219
|
-
finalClasses = finalClasses.replace(`__EXPR_${i}__`, expr);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
return `class="${finalClasses}"`;
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Multi-format transformer
|
|
229
|
-
*
|
|
230
|
-
* Automatically selects the appropriate transformer based on content or file type.
|
|
231
|
-
*/
|
|
232
|
-
export class MultiTransformer implements ClassTransformer {
|
|
233
|
-
name = "multi";
|
|
234
|
-
|
|
235
|
-
private transformers: Map<string, ClassTransformer>;
|
|
236
|
-
|
|
237
|
-
constructor() {
|
|
238
|
-
this.transformers = new Map<string, ClassTransformer>([
|
|
239
|
-
["html", new HtmlTransformer()],
|
|
240
|
-
["jsx", new JsxTransformer()],
|
|
241
|
-
["tsx", new JsxTransformer()],
|
|
242
|
-
["svelte", new SvelteTransformer()],
|
|
243
|
-
]);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Register a custom transformer for a file extension
|
|
248
|
-
*/
|
|
249
|
-
register(extension: string, transformer: ClassTransformer): void {
|
|
250
|
-
this.transformers.set(extension, transformer);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
transform(
|
|
254
|
-
content: string,
|
|
255
|
-
mergeMap: Map<string, string>,
|
|
256
|
-
options?: TransformerOptions
|
|
257
|
-
): string {
|
|
258
|
-
// Default to HTML transformer
|
|
259
|
-
const htmlTransformer = this.transformers.get("html")!;
|
|
260
|
-
return htmlTransformer.transform(content, mergeMap, options);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Transform with explicit file type
|
|
265
|
-
*/
|
|
266
|
-
transformWithType(
|
|
267
|
-
content: string,
|
|
268
|
-
mergeMap: Map<string, string>,
|
|
269
|
-
fileType: string,
|
|
270
|
-
options?: TransformerOptions
|
|
271
|
-
): string {
|
|
272
|
-
const transformer =
|
|
273
|
-
this.transformers.get(fileType) || this.transformers.get("html")!;
|
|
274
|
-
return transformer.transform(content, mergeMap, options);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Transform multiple files
|
|
279
|
-
*/
|
|
280
|
-
transformFiles(
|
|
281
|
-
files: Array<{ content: string; path: string }>,
|
|
282
|
-
mergeMap: Map<string, string>,
|
|
283
|
-
options?: TransformerOptions
|
|
284
|
-
): Array<{ content: string; path: string }> {
|
|
285
|
-
return files.map((file) => {
|
|
286
|
-
const ext = file.path.split(".").pop() || "html";
|
|
287
|
-
const transformer =
|
|
288
|
-
this.transformers.get(ext) || this.transformers.get("html")!;
|
|
289
|
-
return {
|
|
290
|
-
path: file.path,
|
|
291
|
-
content: transformer.transform(file.content, mergeMap, options),
|
|
292
|
-
};
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Default transformers
|
|
298
|
-
export const htmlTransformer = new HtmlTransformer();
|
|
299
|
-
export const jsxTransformer = new JsxTransformer();
|
|
300
|
-
export const svelteTransformer = new SvelteTransformer();
|
|
301
|
-
export const multiTransformer = new MultiTransformer();
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CSS Co-occurrence Optimizer Types
|
|
3
|
-
* Standalone types for CSS class optimization based on co-occurrence analysis
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Represents a set of classes used together on an HTML element
|
|
8
|
-
*/
|
|
9
|
-
export interface ClassUsage {
|
|
10
|
-
/** Array of class names used on the element */
|
|
11
|
-
classes: string[];
|
|
12
|
-
/** Source location for debugging (e.g., "file.html:42") */
|
|
13
|
-
source: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Co-occurrence pair with frequency count
|
|
18
|
-
*/
|
|
19
|
-
export interface CoOccurrence {
|
|
20
|
-
/** First class name (alphabetically) */
|
|
21
|
-
classA: string;
|
|
22
|
-
/** Second class name (alphabetically) */
|
|
23
|
-
classB: string;
|
|
24
|
-
/** Number of times these classes appear together */
|
|
25
|
-
frequency: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* A pattern of classes that frequently appear together
|
|
30
|
-
*/
|
|
31
|
-
export interface MergePattern {
|
|
32
|
-
/** Original class names to merge */
|
|
33
|
-
originalClasses: string[];
|
|
34
|
-
/** New merged class name (generated) */
|
|
35
|
-
mergedClass: string;
|
|
36
|
-
/** Combined CSS declarations */
|
|
37
|
-
declarations: string[];
|
|
38
|
-
/** How many times this pattern appears in HTML */
|
|
39
|
-
frequency: number;
|
|
40
|
-
/** Estimated bytes saved by merging */
|
|
41
|
-
bytesSaved: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Result of CSS optimization
|
|
46
|
-
*/
|
|
47
|
-
export interface OptimizeResult {
|
|
48
|
-
/** Optimized CSS output */
|
|
49
|
-
css: string;
|
|
50
|
-
/** Mapping from original class combination to merged class */
|
|
51
|
-
mergeMap: Map<string, string>;
|
|
52
|
-
/** Patterns that were merged */
|
|
53
|
-
patterns: MergePattern[];
|
|
54
|
-
/** Optimization statistics */
|
|
55
|
-
stats: {
|
|
56
|
-
/** Number of original unique classes */
|
|
57
|
-
originalClasses: number;
|
|
58
|
-
/** Number of patterns merged */
|
|
59
|
-
mergedPatterns: number;
|
|
60
|
-
/** Estimated bytes saved */
|
|
61
|
-
estimatedBytesSaved: number;
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Options for CSS optimization
|
|
67
|
-
*/
|
|
68
|
-
export interface OptimizeOptions {
|
|
69
|
-
/** Minimum frequency for a pattern to be considered (default: 2) */
|
|
70
|
-
minFrequency?: number;
|
|
71
|
-
/** Maximum pattern size to consider (default: 5) */
|
|
72
|
-
maxPatternSize?: number;
|
|
73
|
-
/** Class name prefix filter (only classes starting with this will be optimized) */
|
|
74
|
-
classPrefix?: string;
|
|
75
|
-
/** Pretty print CSS output */
|
|
76
|
-
pretty?: boolean;
|
|
77
|
-
/** Enable verbose logging */
|
|
78
|
-
verbose?: boolean;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Function to generate class names from declarations
|
|
83
|
-
*/
|
|
84
|
-
export type ClassNameGenerator = (decl: string) => string;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* CSS rule with selector and declarations
|
|
88
|
-
*/
|
|
89
|
-
export interface CssRule {
|
|
90
|
-
selector: string;
|
|
91
|
-
declarations: string;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// =============================================================================
|
|
95
|
-
// MoonBit Static Analyzer Types
|
|
96
|
-
// =============================================================================
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* CSS class co-occurrence detected in MoonBit source
|
|
100
|
-
*/
|
|
101
|
-
export interface ClassCooccurrence {
|
|
102
|
-
/** CSS declarations (e.g., ["color:red", "font-size:16px"]) */
|
|
103
|
-
classes: string[];
|
|
104
|
-
/** Source file path */
|
|
105
|
-
file: string;
|
|
106
|
-
/** Line number in source */
|
|
107
|
-
line: number;
|
|
108
|
-
/** Whether this can be statically analyzed (no conditionals) */
|
|
109
|
-
isStatic: boolean;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Warning from static analyzer about non-analyzable patterns
|
|
114
|
-
*/
|
|
115
|
-
export interface AnalyzerWarning {
|
|
116
|
-
/** Warning type */
|
|
117
|
-
kind:
|
|
118
|
-
| "dynamic_conditional"
|
|
119
|
-
| "dynamic_function_call"
|
|
120
|
-
| "untraceable_variable"
|
|
121
|
-
| "dynamic_array_construction";
|
|
122
|
-
/** Source file path */
|
|
123
|
-
file: string;
|
|
124
|
-
/** Line number in source */
|
|
125
|
-
line: number;
|
|
126
|
-
/** Human-readable warning message */
|
|
127
|
-
message: string;
|
|
128
|
-
}
|