-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathgiant.compiler.js
More file actions
137 lines (111 loc) · 5.87 KB
/
Copy pathgiant.compiler.js
File metadata and controls
137 lines (111 loc) · 5.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import fs from 'node:fs';
import path from 'node:path';
import zlib from 'node:zlib';
import crypto from 'node:crypto';
// --- Configuration ---
const CSS_PATH = path.join(import.meta.dirname, 'giant.css');
const JS_IN_PATH = path.join(import.meta.dirname, 'src/giant.source.js');
const PKG_PATH = path.join(import.meta.dirname, 'package.json');
const JS_OUT_PATH = path.join(import.meta.dirname, 'giant.js');
const JS_MIN_OUT_PATH = path.join(import.meta.dirname, 'giant.min.js');
const DTS_OUT_PATH = path.join(import.meta.dirname, 'giant.d.ts');
console.log('Starting zero-dependency GIANT.JS compilation...');
const safeMinify = (code) => {
return code.split('\n').map(line => line.trim()).filter(Boolean).join('\n');
};
try {
// 1. CSS Parsing
if (!fs.existsSync(CSS_PATH)) throw new Error(`Could not find CSS file at ${CSS_PATH}`);
const cssString = fs.readFileSync(CSS_PATH, 'utf8');
const classMatches = cssString.match(/\.[a-zA-Z_-][\w-]*(?:\\:[\w-]+)*/g) || [];
const classes = new Set(classMatches);
const bags = `color bg fg border layout spacing size typography shape effect animation interaction responsive state misc`.split` `;
const design = Object.fromEntries(bags.map(k => [k, {}]));
const camel = s => s.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
const add = (bag, key, cls) => { design[bag][camel(key)] = cls; };
// --- Parse Utility Classes ---
for (const m of classes) {
const cls = m.slice(1).replaceAll('\\:', ':');
const c = cls.replace(':', '-');
if (cls.includes(':')) add(/^(sm|md|lg|cq):/.test(cls) ? 'responsive' : 'state', c, cls);
else if (/^layout-/.test(cls) && !/^layout-(gap|margin|padding|width|height|size|ratio)/.test(cls)) add('layout', cls.slice(7), cls);
else if (/^(p|m|gap)-|^layout-(padding|margin|gap)/.test(cls)) add('spacing', cls, cls);
else if (/^(w|h)-|^layout-(width|height|size|ratio)/.test(cls) || cls == 'min-h-screen') add('size', cls, cls);
else if (/^(typography|shape|effect|animation|interaction)-/.test(cls)) {
const [, bag, key] = cls.match(/^([^-]+)-(.+)/);
add(bag, key, cls);
}
else if (cls.startsWith('color-')) {
const key = cls.slice(6);
add(key.includes('bg') ? 'bg' : key.includes('fg') ? 'fg' : key.includes('border') ? 'border' : 'color', key, cls);
}
else if (cls.includes('bg')) add('bg', cls, cls);
else if (cls.includes('fg')) add('fg', cls, cls);
else if (cls.includes('border') || cls == 'border-color') add('border', cls.replace('border-color', 'border'), cls);
else add('misc', cls, cls);
}
// --- NEW: Parse CSS Variable Palettes ---
// Looks for strings like "--color-primary-3:" and grabs "primary" and "3"
const paletteMatches = cssString.matchAll(/--color-([a-z]+)-(\d+)\s*:/g);
for (const match of paletteMatches) {
const family = match[1]; // e.g., "primary", "neutral", "danger"
const scaleIndex = parseInt(match[2], 10); // e.g., 0, 1, 3
// Initialize the array for this color family if it doesn't exist yet
if (!design.color[family]) {
design.color[family] = [];
}
// Inject the mapped CSS variable string
design.color[family][scaleIndex] = `var(--color-${family}-${scaleIndex})`;
}
// 2. Read Source and Package data
if (!fs.existsSync(JS_IN_PATH)) throw new Error(`Could not find JS source file at ${JS_IN_PATH}`);
let jsSource = fs.readFileSync(JS_IN_PATH, 'utf8');
let pkgSource = fs.existsSync(PKG_PATH) ? fs.readFileSync(PKG_PATH, 'utf8') : '';
// 3. Generate SHA-256 Hash
const hash = crypto.createHash('sha256');
hash.update(jsSource).update(pkgSource);
const sha256Hex = hash.digest('hex');
const buildDate = new Date().toISOString();
const header = `/**\n * GIANT.JS\n * Build Date: ${buildDate}\n * Integrity: sha256-${sha256Hex}\n */\n`;
// 4. Inject JS Object & Minify
// JSON.stringify will automatically handle the nested arrays we created!
const compiledJs = header + jsSource.replace('__GIANT_DESIGN_INJECT__', JSON.stringify(design));
fs.writeFileSync(JS_OUT_PATH, compiledJs, 'utf8');
const lightMinified = safeMinify(compiledJs);
fs.writeFileSync(JS_MIN_OUT_PATH, lightMinified, 'utf8');
// 5. Build TypeScript Definitions (.d.ts)
console.log('Generating TypeScript definitions...');
let dtsString = `${header}\n`;
dtsString += `export declare const design: {\n`;
for (const bag of bags) {
dtsString += ` ${bag}: {\n`;
for (const [key, value] of Object.entries(design[bag])) {
// NEW: Handle nested arrays for color palettes in TypeScript
if (Array.isArray(value)) {
// Convert the JS array into a TypeScript literal tuple (e.g. readonly ["var(--color-primary-0)", ...])
const tupleTypes = Array.from(value).map(v => v ? `"${v}"` : 'undefined').join(', ');
dtsString += ` readonly "${key}": readonly [${tupleTypes}];\n`;
} else {
dtsString += ` readonly "${key}": "${value}";\n`;
}
}
dtsString += ` };\n`;
}
dtsString += `};\n\n`;
dtsString += `export declare function createRoot(Fn: any): any;\n`;
dtsString += `export declare function createElement(type: any, ...args: any[]): any;\n`;
dtsString += `export declare function component(Fn: any, tagName?: string): any;\n`;
dtsString += `export declare const html: Record<string, (...args: any[]) => any>;\n`;
dtsString += `export declare function match(p: Element | null, s?: string): Element | null;\n`;
fs.writeFileSync(DTS_OUT_PATH, dtsString, 'utf8');
// 6. Calculate Metrics
const rawSize = Buffer.byteLength(lightMinified, 'utf8');
const gzipSize = zlib.gzipSync(lightMinified).length;
console.log(`\nCompilation Complete!`);
console.log(`Integrity: sha256-${sha256Hex}`);
console.log(`Typings: Saved to giant.d.ts`);
console.log(`Size: ${(rawSize / 1024).toFixed(2)} KB raw / ${(gzipSize / 1024).toFixed(2)} KB gzip`);
} catch (err) {
console.error('Compilation failed:', err);
process.exit(1);
}