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.
- package/CHANGELOG.md +81 -0
- package/LICENSE +2 -3
- package/README.md +239 -114
- package/dist/cli/commands/build.d.ts +3 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/compile.d.ts +3 -0
- package/dist/cli/commands/compile.d.ts.map +1 -0
- package/dist/cli/commands/init.d.ts +5 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/timeline.d.ts +2 -0
- package/dist/cli/commands/timeline.d.ts.map +1 -0
- package/dist/cli/commands/watch.d.ts +6 -0
- package/dist/cli/commands/watch.d.ts.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +5960 -0
- package/dist/cli/types.d.ts +51 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/utils/config-loader.d.ts +8 -0
- package/dist/cli/utils/config-loader.d.ts.map +1 -0
- package/dist/cli/utils/file-utils.d.ts +9 -0
- package/dist/cli/utils/file-utils.d.ts.map +1 -0
- package/dist/cli/utils/logger.d.ts +17 -0
- package/dist/cli/utils/logger.d.ts.map +1 -0
- package/dist/compiler/atomic-optimizer.d.ts +76 -0
- package/dist/compiler/atomic-optimizer.d.ts.map +1 -0
- package/dist/compiler/btt.d.ts +138 -0
- package/dist/compiler/btt.d.ts.map +1 -0
- package/dist/compiler/cache-manager.d.ts +20 -0
- package/dist/compiler/cache-manager.d.ts.map +1 -0
- package/dist/compiler/commonProps.d.ts +2 -0
- package/dist/compiler/commonProps.d.ts.map +1 -0
- package/dist/compiler/index.d.ts +12 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/index.js +5177 -0
- package/dist/compiler/prefixer.d.ts +42 -0
- package/dist/compiler/prefixer.d.ts.map +1 -0
- package/dist/compiler/theme-contract.d.ts +61 -0
- package/dist/compiler/theme-contract.d.ts.map +1 -0
- package/dist/compiler/tokens.d.ts +52 -0
- package/dist/compiler/tokens.d.ts.map +1 -0
- package/dist/compiler/types.d.ts +57 -0
- package/dist/compiler/types.d.ts.map +1 -0
- package/dist/core/compiler.d.ts +32 -0
- package/dist/core/compiler.d.ts.map +1 -0
- package/dist/core/constants.d.ts +129 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/types.d.ts +88 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/utils.d.ts +37 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5667 -0
- package/dist/plugins/vite.d.ts +11 -0
- package/dist/plugins/vite.d.ts.map +1 -0
- package/dist/plugins/vite.js +25839 -0
- package/dist/plugins/webpack.d.ts +45 -0
- package/dist/plugins/webpack.d.ts.map +1 -0
- package/dist/plugins/webpack.js +107 -0
- package/dist/runtime/hmr.d.ts +3 -0
- package/dist/runtime/hmr.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +15 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +552 -0
- package/dist/runtime/injector.d.ts +85 -0
- package/dist/runtime/injector.d.ts.map +1 -0
- package/dist/runtime/react.d.ts +54 -0
- package/dist/runtime/react.d.ts.map +1 -0
- package/dist/runtime/react.js +270 -0
- package/dist/runtime/types.d.ts +45 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/utils.d.ts +62 -0
- package/dist/runtime/utils.d.ts.map +1 -0
- package/dist/runtime/vue.d.ts +52 -0
- package/dist/runtime/vue.d.ts.map +1 -0
- package/dist/runtime/vue.js +232 -0
- package/package.json +90 -109
- package/browser/commonProps.js +0 -14
- package/browser/index.js +0 -3
- package/browser/react-hooks.js +0 -162
- package/browser/rtt.js +0 -370
- package/node/atomic-optimizer.js +0 -391
- package/node/btt.js +0 -962
- package/node/cache-manager.js +0 -56
- package/node/chaincss.js +0 -489
- package/node/css-properties.json +0 -633
- package/node/index.js +0 -2
- package/node/loaders/chaincss-loader.js +0 -62
- package/node/plugins/next-plugin.js +0 -120
- package/node/plugins/vite-plugin.js +0 -383
- package/node/plugins/webpack-plugin.js +0 -41
- package/node/prefixer.js +0 -237
- package/node/strVal.js +0 -106
- package/node/theme-validator.js +0 -32
- package/shared/theme-contract.js +0 -98
- package/shared/tokens.cjs +0 -256
- package/shared/tokens.mjs +0 -320
- package/types.d.ts +0 -277
package/node/prefixer.js
DELETED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
let postcss, browserslist, caniuse, autoprefixer;
|
|
2
|
-
try {
|
|
3
|
-
postcss = require('postcss');
|
|
4
|
-
browserslist = require('browserslist');
|
|
5
|
-
caniuse = require('caniuse-db/fulldata-json/data-2.0.json');
|
|
6
|
-
} catch (err) {
|
|
7
|
-
}
|
|
8
|
-
try {
|
|
9
|
-
autoprefixer = require('autoprefixer');
|
|
10
|
-
} catch (err) {
|
|
11
|
-
}
|
|
12
|
-
class ChainCSSPrefixer {
|
|
13
|
-
constructor(config = {}) {
|
|
14
|
-
this.config = {
|
|
15
|
-
browsers: config.browsers || ['> 0.5%', 'last 2 versions', 'not dead'],
|
|
16
|
-
enabled: config.enabled !== false,
|
|
17
|
-
mode: config.mode || 'auto',
|
|
18
|
-
sourceMap: config.sourceMap !== false, // Enable source maps by default
|
|
19
|
-
sourceMapInline: config.sourceMapInline || false,
|
|
20
|
-
...config
|
|
21
|
-
};
|
|
22
|
-
this.hasBuiltInDeps = !!(postcss && browserslist && caniuse);
|
|
23
|
-
this.hasAutoprefixer = !!autoprefixer;
|
|
24
|
-
this.prefixerMode = this.determineMode();
|
|
25
|
-
this.caniuseData = caniuse ? caniuse.data : null;
|
|
26
|
-
this.commonProperties = this.getCommonProperties();
|
|
27
|
-
this.specialValues = {
|
|
28
|
-
'display': ['flex', 'inline-flex', 'grid', 'inline-grid'],
|
|
29
|
-
'background-clip': ['text'],
|
|
30
|
-
'position': ['sticky']
|
|
31
|
-
};
|
|
32
|
-
this.browserPrefixMap = {
|
|
33
|
-
'chrome': 'webkit', 'safari': 'webkit', 'firefox': 'moz',
|
|
34
|
-
'ie': 'ms', 'edge': 'webkit', 'ios_saf': 'webkit',
|
|
35
|
-
'and_chr': 'webkit', 'android': 'webkit', 'opera': 'webkit',
|
|
36
|
-
'op_mob': 'webkit', 'samsung': 'webkit', 'and_ff': 'moz'
|
|
37
|
-
};
|
|
38
|
-
this.targetBrowsers = null;
|
|
39
|
-
}
|
|
40
|
-
determineMode() {
|
|
41
|
-
if (this.config.mode === 'full' && !this.hasAutoprefixer) {
|
|
42
|
-
console.warn('ā ļø Full mode requested but autoprefixer not installed. Falling back to lightweight mode.');
|
|
43
|
-
console.warn(' To use full mode install this devDenpendecies: "npm install -D autoprefixer postcss caniuse-db browserslist"\n');
|
|
44
|
-
return 'lightweight';
|
|
45
|
-
}
|
|
46
|
-
if (this.config.mode === 'lightweight') {
|
|
47
|
-
return 'lightweight';
|
|
48
|
-
}
|
|
49
|
-
if (this.config.mode === 'full' && this.hasAutoprefixer) {
|
|
50
|
-
return 'full';
|
|
51
|
-
}
|
|
52
|
-
if (this.config.mode === 'auto') {
|
|
53
|
-
return this.hasAutoprefixer ? 'full' : 'lightweight';
|
|
54
|
-
}
|
|
55
|
-
return 'lightweight';
|
|
56
|
-
}
|
|
57
|
-
async process(cssString, options = {}) {
|
|
58
|
-
if (!this.config.enabled) {
|
|
59
|
-
return { css: cssString, map: null };
|
|
60
|
-
}
|
|
61
|
-
try {
|
|
62
|
-
const mapOptions = {
|
|
63
|
-
inline: this.config.sourceMapInline,
|
|
64
|
-
annotation: false,
|
|
65
|
-
sourcesContent: true
|
|
66
|
-
};
|
|
67
|
-
if (this.prefixerMode === 'full') {
|
|
68
|
-
return await this.processWithAutoprefixer(cssString, options, mapOptions);
|
|
69
|
-
}
|
|
70
|
-
return await this.processWithBuiltIn(cssString, options, mapOptions);
|
|
71
|
-
} catch (err) {
|
|
72
|
-
console.error('Prefixer error:', err.message);
|
|
73
|
-
return { css: cssString, map: null };
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
async processWithAutoprefixer(cssString, options, mapOptions) {
|
|
77
|
-
const from = options.from || 'input.css';
|
|
78
|
-
const to = options.to || 'output.css';
|
|
79
|
-
const result = await postcss([
|
|
80
|
-
autoprefixer({ overrideBrowserslist: this.config.browsers })
|
|
81
|
-
]).process(cssString, {
|
|
82
|
-
from,
|
|
83
|
-
to,
|
|
84
|
-
map: this.config.sourceMap ? mapOptions : false
|
|
85
|
-
});
|
|
86
|
-
return {
|
|
87
|
-
css: result.css,
|
|
88
|
-
map: result.map ? result.map.toString() : null
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
async processWithBuiltIn(cssString, options, mapOptions) {
|
|
92
|
-
if (!this.hasBuiltInDeps) {
|
|
93
|
-
return { css: cssString, map: null };
|
|
94
|
-
}
|
|
95
|
-
this.targetBrowsers = browserslist(this.config.browsers);
|
|
96
|
-
const from = options.from || 'input.css';
|
|
97
|
-
const to = options.to || 'output.css';
|
|
98
|
-
const result = await postcss([
|
|
99
|
-
this.createBuiltInPlugin()
|
|
100
|
-
]).process(cssString, {
|
|
101
|
-
from,
|
|
102
|
-
to,
|
|
103
|
-
map: this.config.sourceMap ? mapOptions : false
|
|
104
|
-
});
|
|
105
|
-
return {
|
|
106
|
-
css: result.css,
|
|
107
|
-
map: result.map ? result.map.toString() : null
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
createBuiltInPlugin() {
|
|
111
|
-
return (root) => {
|
|
112
|
-
root.walkDecls(decl => {
|
|
113
|
-
this.processBuiltInDeclaration(decl);
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
processBuiltInDeclaration(decl) {
|
|
118
|
-
const { prop, value } = decl;
|
|
119
|
-
if (this.commonProperties.includes(prop)) {
|
|
120
|
-
this.addPrefixesFromCaniuse(decl);
|
|
121
|
-
}
|
|
122
|
-
if (this.specialValues[prop]?.includes(value)) {
|
|
123
|
-
this.addSpecialValuePrefixes(decl);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
addPrefixesFromCaniuse(decl) {
|
|
127
|
-
if (!this.caniuseData) return;
|
|
128
|
-
const feature = this.findFeature(decl.prop);
|
|
129
|
-
if (!feature) return;
|
|
130
|
-
const prefixes = new Set();
|
|
131
|
-
this.targetBrowsers.forEach(browser => {
|
|
132
|
-
const [id, versionStr] = browser.split(' ');
|
|
133
|
-
const version = parseFloat(versionStr.split('-')[0]);
|
|
134
|
-
const stats = feature.stats[id];
|
|
135
|
-
if (stats) {
|
|
136
|
-
const versions = Object.keys(stats)
|
|
137
|
-
.map(v => parseFloat(v.split('-')[0]))
|
|
138
|
-
.filter(v => !isNaN(v))
|
|
139
|
-
.sort((a, b) => a - b);
|
|
140
|
-
const closestVersion = versions.find(v => v <= version) || versions[0];
|
|
141
|
-
if (closestVersion) {
|
|
142
|
-
const support = stats[closestVersion.toString()];
|
|
143
|
-
if (support && support.includes('x')) {
|
|
144
|
-
const prefix = this.browserPrefixMap[id.split('-')[0]];
|
|
145
|
-
if (prefix) prefixes.add(prefix);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
prefixes.forEach(prefix => {
|
|
152
|
-
decl.cloneBefore({
|
|
153
|
-
prop: `-${prefix}-${decl.prop}`,
|
|
154
|
-
value: decl.value
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
addSpecialValuePrefixes(decl) {
|
|
159
|
-
const { prop, value } = decl;
|
|
160
|
-
if (prop === 'display') {
|
|
161
|
-
if (value === 'flex' || value === 'inline-flex') {
|
|
162
|
-
decl.cloneBefore({ prop: 'display', value: `-webkit-${value}` });
|
|
163
|
-
decl.cloneBefore({
|
|
164
|
-
prop: 'display',
|
|
165
|
-
value: value === 'flex' ? '-ms-flexbox' : '-ms-inline-flexbox'
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
if (value === 'grid' || value === 'inline-grid') {
|
|
169
|
-
decl.cloneBefore({
|
|
170
|
-
prop: 'display',
|
|
171
|
-
value: value === 'grid' ? '-ms-grid' : '-ms-inline-grid'
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
if (prop === 'background-clip' && value === 'text') {
|
|
176
|
-
decl.cloneBefore({ prop: '-webkit-background-clip', value: 'text' });
|
|
177
|
-
}
|
|
178
|
-
if (prop === 'position' && value === 'sticky') {
|
|
179
|
-
decl.cloneBefore({ prop: 'position', value: '-webkit-sticky' });
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
findFeature(property) {
|
|
184
|
-
if (!this.caniuseData) return null;
|
|
185
|
-
const featureMap = {
|
|
186
|
-
'transform': 'transforms2d',
|
|
187
|
-
'transform-origin': 'transforms2d',
|
|
188
|
-
'transform-style': 'transforms3d',
|
|
189
|
-
'perspective': 'transforms3d',
|
|
190
|
-
'backface-visibility': 'transforms3d',
|
|
191
|
-
'transition': 'css-transitions',
|
|
192
|
-
'animation': 'css-animation',
|
|
193
|
-
'backdrop-filter': 'backdrop-filter',
|
|
194
|
-
'filter': 'css-filters',
|
|
195
|
-
'user-select': 'user-select-none',
|
|
196
|
-
'appearance': 'css-appearance',
|
|
197
|
-
'mask-image': 'css-masks',
|
|
198
|
-
'box-shadow': 'css-boxshadow',
|
|
199
|
-
'border-radius': 'border-radius',
|
|
200
|
-
'text-fill-color': 'text-stroke',
|
|
201
|
-
'text-stroke': 'text-stroke',
|
|
202
|
-
'background-clip': 'background-img-opts',
|
|
203
|
-
'flex': 'flexbox',
|
|
204
|
-
'flex-grow': 'flexbox',
|
|
205
|
-
'flex-shrink': 'flexbox',
|
|
206
|
-
'flex-basis': 'flexbox',
|
|
207
|
-
'justify-content': 'flexbox',
|
|
208
|
-
'align-items': 'flexbox',
|
|
209
|
-
'grid': 'css-grid',
|
|
210
|
-
'grid-template': 'css-grid',
|
|
211
|
-
'grid-column': 'css-grid',
|
|
212
|
-
'grid-row': 'css-grid'
|
|
213
|
-
};
|
|
214
|
-
const featureId = featureMap[property];
|
|
215
|
-
return featureId ? this.caniuseData[featureId] : null;
|
|
216
|
-
}
|
|
217
|
-
getCommonProperties() {
|
|
218
|
-
return [
|
|
219
|
-
'transform', 'transform-origin', 'transform-style',
|
|
220
|
-
'transition', 'transition-property', 'transition-duration', 'transition-timing-function',
|
|
221
|
-
'animation', 'animation-name', 'animation-duration', 'animation-timing-function',
|
|
222
|
-
'animation-delay', 'animation-iteration-count', 'animation-direction',
|
|
223
|
-
'animation-fill-mode', 'animation-play-state',
|
|
224
|
-
'backdrop-filter', 'filter',
|
|
225
|
-
'user-select', 'appearance',
|
|
226
|
-
'text-fill-color', 'text-stroke', 'text-stroke-color', 'text-stroke-width',
|
|
227
|
-
'background-clip',
|
|
228
|
-
'mask-image', 'mask-clip', 'mask-composite', 'mask-origin',
|
|
229
|
-
'mask-position', 'mask-repeat', 'mask-size',
|
|
230
|
-
'box-shadow', 'border-radius', 'box-sizing',
|
|
231
|
-
'display', 'flex', 'flex-grow', 'flex-shrink', 'flex-basis',
|
|
232
|
-
'justify-content', 'align-items', 'align-self', 'align-content',
|
|
233
|
-
'grid', 'grid-template', 'grid-column', 'grid-row'
|
|
234
|
-
];
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
module.exports = ChainCSSPrefixer;
|
package/node/strVal.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
const strVal = {
|
|
2
|
-
userConf: `// Project Configuration
|
|
3
|
-
module.exports = {
|
|
4
|
-
atomic: {
|
|
5
|
-
enabled: true,
|
|
6
|
-
threshold: 3,
|
|
7
|
-
naming: 'hash',
|
|
8
|
-
cache: true,
|
|
9
|
-
cachePath: './.chaincss-cache',
|
|
10
|
-
minify: true
|
|
11
|
-
},
|
|
12
|
-
prefixer: {
|
|
13
|
-
mode: 'auto',
|
|
14
|
-
browsers: ['> 0.5%', 'last 2 versions', 'not dead'],
|
|
15
|
-
enabled: true,
|
|
16
|
-
sourceMap: true,
|
|
17
|
-
sourceMapInline: false
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
`,
|
|
21
|
-
cli_opt_guide: `
|
|
22
|
-
ChainCSS - JavaScript-powered CSS preprocessor
|
|
23
|
-
|
|
24
|
-
Usage:
|
|
25
|
-
chaincss <inputFile> <outputFile> [options]
|
|
26
|
-
|
|
27
|
-
Options:
|
|
28
|
-
--watch Watch for changes and auto-recompile
|
|
29
|
-
--no-prefix Disable automatic prefixing
|
|
30
|
-
--prefixer-mode <mode> Set prefixer mode (auto|lightweight|full)
|
|
31
|
-
--browsers <list> Browser support list (comma-separated)
|
|
32
|
-
--no-source-map Disable source maps
|
|
33
|
-
--source-map-inline Use inline source maps
|
|
34
|
-
|
|
35
|
-
# Atomic CSS Optimization
|
|
36
|
-
--atomic Enable atomic CSS optimization
|
|
37
|
-
--threshold <number> Minimum usage count for atomic classes (default: 3)
|
|
38
|
-
--atomic-naming <type> Atomic class naming (hash|readable) (default: hash)
|
|
39
|
-
--no-atomic-cache Disable atomic CSS cache
|
|
40
|
-
|
|
41
|
-
# Performance & Debug
|
|
42
|
-
--verbose Enable verbose logging
|
|
43
|
-
--debug Enable debug mode with detailed output
|
|
44
|
-
--tree-shake Remove unused CSS classes (dead code elimination)
|
|
45
|
-
|
|
46
|
-
# Output Control
|
|
47
|
-
--minify Minify CSS output (default: true in production)
|
|
48
|
-
--no-minify Disable CSS minification
|
|
49
|
-
--out-dir <dir> Output directory (default: same as outputFile dir)
|
|
50
|
-
--manifest Generate build manifest file
|
|
51
|
-
|
|
52
|
-
# Configuration
|
|
53
|
-
--config <path> Path to config file (default: chaincss.config.cjs)
|
|
54
|
-
--no-config Ignore config file, use CLI options only
|
|
55
|
-
|
|
56
|
-
# Theme Validation
|
|
57
|
-
--validate-themes Validate theme contracts during build
|
|
58
|
-
|
|
59
|
-
# Help
|
|
60
|
-
--help, -h Show this help message
|
|
61
|
-
--version, -v Show version number
|
|
62
|
-
|
|
63
|
-
Examples:
|
|
64
|
-
# Basic compilation
|
|
65
|
-
chaincss style.jcss style.css
|
|
66
|
-
|
|
67
|
-
# Watch mode for development
|
|
68
|
-
chaincss style.jcss style.css --watch
|
|
69
|
-
|
|
70
|
-
# Atomic CSS optimization
|
|
71
|
-
chaincss style.jcss style.css --atomic
|
|
72
|
-
|
|
73
|
-
# With custom threshold for atomic classes
|
|
74
|
-
chaincss style.jcss style.css --atomic --threshold 5
|
|
75
|
-
|
|
76
|
-
# Full production build with all optimizations
|
|
77
|
-
chaincss style.jcss style.css --atomic --minify --tree-shake --source-map
|
|
78
|
-
|
|
79
|
-
# Custom browser support
|
|
80
|
-
chaincss style.jcss style.css --browsers "> 1%, last 2 versions, not dead"
|
|
81
|
-
|
|
82
|
-
# Full autoprefixer mode
|
|
83
|
-
chaincss style.jcss style.css --prefixer-mode full
|
|
84
|
-
|
|
85
|
-
# Validate themes during build
|
|
86
|
-
chaincss style.jcss style.css --validate-themes
|
|
87
|
-
|
|
88
|
-
# Debug mode with verbose output
|
|
89
|
-
chaincss style.jcss style.css --debug --verbose
|
|
90
|
-
|
|
91
|
-
# Disable prefixing (for modern browsers only)
|
|
92
|
-
chaincss style.jcss style.css --no-prefix
|
|
93
|
-
|
|
94
|
-
# With custom config file
|
|
95
|
-
chaincss style.jcss style.css --config ./my-chaincss.config.cjs
|
|
96
|
-
|
|
97
|
-
Notes:
|
|
98
|
-
- Atomic CSS optimization reduces CSS size by reusing common style patterns
|
|
99
|
-
- Tree shaking removes unused CSS classes from final bundle
|
|
100
|
-
- Theme validation ensures all themes have required tokens
|
|
101
|
-
- Use --watch during development for instant updates
|
|
102
|
-
- Use --atomic --minify --tree-shake for production builds
|
|
103
|
-
`
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
module.exports = strVal;
|
package/node/theme-validator.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export function validateThemeFiles(configPath) {
|
|
5
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
6
|
-
|
|
7
|
-
if (!config.themes) return;
|
|
8
|
-
|
|
9
|
-
const { contract, themes } = config;
|
|
10
|
-
|
|
11
|
-
console.log('\nšØ Validating Theme Contract...\n');
|
|
12
|
-
|
|
13
|
-
const errors = [];
|
|
14
|
-
|
|
15
|
-
themes.forEach((theme, index) => {
|
|
16
|
-
const themeName = theme.name || `theme-${index}`;
|
|
17
|
-
try {
|
|
18
|
-
validateTheme(contract, theme.values);
|
|
19
|
-
console.log(`ā
${themeName}: Valid`);
|
|
20
|
-
} catch (err) {
|
|
21
|
-
errors.push(`ā ${themeName}: ${err.message}`);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
if (errors.length > 0) {
|
|
26
|
-
console.error('\nTheme Contract Validation Failed:\n');
|
|
27
|
-
errors.forEach(err => console.error(err));
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
console.log('\nā
All themes valid!\n');
|
|
32
|
-
}
|
package/shared/theme-contract.js
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
export function createThemeContract(contractShape) {
|
|
2
|
-
// Store the contract for validation
|
|
3
|
-
const contract = contractShape;
|
|
4
|
-
|
|
5
|
-
// Create a proxy that validates token access
|
|
6
|
-
const contractProxy = new Proxy(contract, {
|
|
7
|
-
get(target, prop) {
|
|
8
|
-
if (prop === '__isContract') return true;
|
|
9
|
-
if (prop === '__validate') return (theme) => validateTheme(contract, theme);
|
|
10
|
-
return target[prop];
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
return contractProxy;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function validateTheme(contract, theme, path = '') {
|
|
18
|
-
const errors = [];
|
|
19
|
-
|
|
20
|
-
function validate(contractPart, themePart, currentPath) {
|
|
21
|
-
if (typeof contractPart === 'object' && contractPart !== null) {
|
|
22
|
-
// Check if theme has all required keys
|
|
23
|
-
const requiredKeys = Object.keys(contractPart);
|
|
24
|
-
const themeKeys = Object.keys(themePart || {});
|
|
25
|
-
|
|
26
|
-
requiredKeys.forEach(key => {
|
|
27
|
-
const newPath = currentPath ? `${currentPath}.${key}` : key;
|
|
28
|
-
|
|
29
|
-
if (!themePart || !themePart.hasOwnProperty(key)) {
|
|
30
|
-
errors.push(` Missing required token: "${newPath}"`);
|
|
31
|
-
} else {
|
|
32
|
-
validate(contractPart[key], themePart[key], newPath);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Warn about extra keys (optional, could be allowed)
|
|
37
|
-
themeKeys.forEach(key => {
|
|
38
|
-
if (!contractPart.hasOwnProperty(key)) {
|
|
39
|
-
const newPath = currentPath ? `${currentPath}.${key}` : key;
|
|
40
|
-
console.warn(` Extra token not in contract: "${newPath}"`);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
} else {
|
|
44
|
-
// Leaf node - just check type (optional)
|
|
45
|
-
if (typeof themePart !== 'string') {
|
|
46
|
-
errors.push(` Token "${currentPath}" must be a string, got ${typeof themePart}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
validate(contract, theme, path);
|
|
52
|
-
|
|
53
|
-
if (errors.length > 0) {
|
|
54
|
-
throw new Error(`Theme Contract Validation Failed:\n${errors.join('\n')}`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function createTheme(contract, themeValues) {
|
|
61
|
-
// Validate at creation time
|
|
62
|
-
if (contract.__isContract) {
|
|
63
|
-
contract.__validate(themeValues);
|
|
64
|
-
} else {
|
|
65
|
-
validateTheme(contract, themeValues);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Create the actual theme tokens
|
|
69
|
-
const tokens = {};
|
|
70
|
-
|
|
71
|
-
function buildTokens(contractPart, themePart, target, path = '') {
|
|
72
|
-
Object.keys(contractPart).forEach(key => {
|
|
73
|
-
const newPath = path ? `${path}.${key}` : key;
|
|
74
|
-
|
|
75
|
-
if (typeof contractPart[key] === 'object' && contractPart[key] !== null) {
|
|
76
|
-
target[key] = {};
|
|
77
|
-
buildTokens(contractPart[key], themePart[key] || {}, target[key], newPath);
|
|
78
|
-
} else {
|
|
79
|
-
target[key] = themePart[key];
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
buildTokens(contract, themeValues, tokens);
|
|
85
|
-
|
|
86
|
-
// Add getter method
|
|
87
|
-
tokens.get = (path) => {
|
|
88
|
-
const parts = path.split('.');
|
|
89
|
-
let current = tokens;
|
|
90
|
-
for (const part of parts) {
|
|
91
|
-
if (current === undefined) return undefined;
|
|
92
|
-
current = current[part];
|
|
93
|
-
}
|
|
94
|
-
return current;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
return tokens;
|
|
98
|
-
}
|