@plumeria/unplugin 18.3.17 → 18.4.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/README.md +4 -0
- package/dist/core.d.ts +2 -1
- package/dist/core.js +69 -37
- package/dist/core.mjs +70 -38
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -156,6 +156,10 @@ plumeria.vite({
|
|
|
156
156
|
| `exclude` | — | Files to skip. |
|
|
157
157
|
| `devEmitToDisk` | `false` | Write CSS to disk in development so the bundler's watcher drives HMR. |
|
|
158
158
|
| `styleProp` | `'classStyle'` | The JSX prop that carries styles. |
|
|
159
|
+
| `withoutLogicalProperties` | `false` | Reject the logical name of a property that also has a physical name. Takes `true` or `{ sizes?: boolean }`. |
|
|
160
|
+
| `withoutPhysicalProperties` | `false` | Reject the physical name of a property that also has a logical name. Takes `true` or `{ sizes?: boolean }`. |
|
|
161
|
+
|
|
162
|
+
The two spelling options contradict each other, so enabling both is a configuration error. See [the docs](https://plumeria.dev/docs/api-reference/plugins/unplugin) for why the pair has to be settled and how it lines up with the lint rules.
|
|
159
163
|
|
|
160
164
|
### styleProp
|
|
161
165
|
|
package/dist/core.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { UnpluginFactory } from 'unplugin';
|
|
2
|
-
|
|
2
|
+
import type { PropertyPolicyOptions } from '@plumeria/utils';
|
|
3
|
+
export interface PluginOptions extends PropertyPolicyOptions {
|
|
3
4
|
include?: string | RegExp | Array<string | RegExp>;
|
|
4
5
|
exclude?: string | RegExp | Array<string | RegExp>;
|
|
5
6
|
devEmitToDisk?: boolean;
|
package/dist/core.js
CHANGED
|
@@ -167,6 +167,46 @@ const foldDynamicVars = (vars) => {
|
|
|
167
167
|
return `"${cssVar}": ${value}`;
|
|
168
168
|
});
|
|
169
169
|
};
|
|
170
|
+
const isUnitlessProp = (prop) => zss_engine_1.exceptionCamelCase.includes(prop) || prop.startsWith('--');
|
|
171
|
+
const collectVarProps = (style, cssVar, props) => {
|
|
172
|
+
const reference = `var(${cssVar})`;
|
|
173
|
+
for (const [prop, value] of Object.entries(style)) {
|
|
174
|
+
if (typeof value === 'string' && value.includes(reference))
|
|
175
|
+
props.push(prop);
|
|
176
|
+
else if (value !== null && typeof value === 'object')
|
|
177
|
+
collectVarProps(value, cssVar, props);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
const retargetVar = (style, cssVar, next, unitless) => {
|
|
181
|
+
const reference = `var(${cssVar})`;
|
|
182
|
+
for (const [prop, value] of Object.entries(style)) {
|
|
183
|
+
if (typeof value === 'string' && value.includes(reference)) {
|
|
184
|
+
if (isUnitlessProp(prop) === unitless)
|
|
185
|
+
style[prop] = value
|
|
186
|
+
.split(reference)
|
|
187
|
+
.join(`var(${next})`);
|
|
188
|
+
}
|
|
189
|
+
else if (value !== null && typeof value === 'object') {
|
|
190
|
+
retargetVar(value, cssVar, next, unitless);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const splitVarByUnit = (style, cssVar) => {
|
|
195
|
+
const props = [];
|
|
196
|
+
collectVarProps(style, cssVar, props);
|
|
197
|
+
if (props.length === 0)
|
|
198
|
+
return [];
|
|
199
|
+
const lead = props[0];
|
|
200
|
+
const split = props.find((prop) => isUnitlessProp(prop) !== isUnitlessProp(lead));
|
|
201
|
+
if (!split)
|
|
202
|
+
return [{ cssVar, prop: lead }];
|
|
203
|
+
const splitVar = `${cssVar}-${(0, zss_engine_1.camelToKebabCase)(split).replace(/^-+/, '')}`;
|
|
204
|
+
retargetVar(style, cssVar, splitVar, isUnitlessProp(split));
|
|
205
|
+
return [
|
|
206
|
+
{ cssVar, prop: lead },
|
|
207
|
+
{ cssVar: splitVar, prop: split },
|
|
208
|
+
];
|
|
209
|
+
};
|
|
170
210
|
const applyVarFallback = (style, cssVar, literal) => {
|
|
171
211
|
const reference = `var(${cssVar})`;
|
|
172
212
|
for (const [prop, value] of Object.entries(style)) {
|
|
@@ -180,20 +220,9 @@ const applyVarFallback = (style, cssVar, literal) => {
|
|
|
180
220
|
}
|
|
181
221
|
}
|
|
182
222
|
};
|
|
183
|
-
const findVarProp = (style, cssVar) => {
|
|
184
|
-
for (const [prop, value] of Object.entries(style)) {
|
|
185
|
-
if (typeof value === 'string' && value.includes(cssVar))
|
|
186
|
-
return prop;
|
|
187
|
-
if (value !== null && typeof value === 'object') {
|
|
188
|
-
const nested = findVarProp(value, cssVar);
|
|
189
|
-
if (nested)
|
|
190
|
-
return nested;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return undefined;
|
|
194
|
-
};
|
|
195
223
|
const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
196
224
|
const filter = (0, pluginutils_1.createFilter)(options.include, options.exclude);
|
|
225
|
+
const propertyPolicy = (0, utils_1.resolvePropertyPolicy)(options);
|
|
197
226
|
const styleProp = options.styleProp ?? utils_1.DEFAULT_STYLE_PROP;
|
|
198
227
|
const cssLookup = new Map();
|
|
199
228
|
const cssFileLookup = new Map();
|
|
@@ -263,6 +292,7 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
263
292
|
tsx: true,
|
|
264
293
|
target: 'es2022',
|
|
265
294
|
});
|
|
295
|
+
(0, utils_1.assertPropertyPolicy)(ast, propertyPolicy, id);
|
|
266
296
|
const leadingLen = (0, utils_1.getLeadingCommentLength)(source);
|
|
267
297
|
const sourceBuffer = Buffer.from(source, 'utf-8');
|
|
268
298
|
const leadingBytes = Buffer.byteLength(source.slice(0, leadingLen), 'utf-8');
|
|
@@ -1050,47 +1080,49 @@ const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1050
1080
|
const style = (0, utils_1.objectExpressionToObject)(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
1051
1081
|
if (!style)
|
|
1052
1082
|
return null;
|
|
1053
|
-
|
|
1083
|
+
const varGroups = new Map();
|
|
1084
|
+
varParams.forEach((param) => {
|
|
1054
1085
|
const cssVar = cssVars[param];
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1086
|
+
if (cssVar)
|
|
1087
|
+
varGroups.set(param, splitVarByUnit(style, cssVar));
|
|
1088
|
+
});
|
|
1089
|
+
withDefault.forEach(([param, expr]) => {
|
|
1058
1090
|
const literal = expr.type === 'StringLiteral' || expr.type === 'NumericLiteral'
|
|
1059
1091
|
? expr.value
|
|
1060
1092
|
: undefined;
|
|
1061
1093
|
if (literal === undefined)
|
|
1062
1094
|
return;
|
|
1063
|
-
applyVarFallback(style, cssVar, literal);
|
|
1095
|
+
(varGroups.get(param) ?? []).forEach(({ cssVar }) => applyVarFallback(style, cssVar, literal));
|
|
1064
1096
|
});
|
|
1065
1097
|
const vars = [];
|
|
1066
1098
|
runtime.forEach(({ param, source }) => {
|
|
1067
|
-
const
|
|
1068
|
-
|
|
1069
|
-
if (!targetProp)
|
|
1099
|
+
const groups = varGroups.get(param);
|
|
1100
|
+
if (!groups?.length)
|
|
1070
1101
|
return;
|
|
1071
1102
|
const argStart = source.span.start - baseByteOffset;
|
|
1072
1103
|
const argEnd = source.span.end - baseByteOffset;
|
|
1073
1104
|
const argSource = sourceBuffer
|
|
1074
1105
|
.subarray(argStart, argEnd)
|
|
1075
1106
|
.toString('utf-8');
|
|
1076
|
-
let valueExpr;
|
|
1077
|
-
const kebabProp = (0, zss_engine_1.camelToKebabCase)(targetProp);
|
|
1078
|
-
const isUnitless = zss_engine_1.exceptionCamelCase.includes(targetProp) ||
|
|
1079
|
-
targetProp.startsWith('--');
|
|
1080
1107
|
const maybeNumber = Number(argSource);
|
|
1081
|
-
|
|
1082
|
-
valueExpr
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1108
|
+
groups.forEach(({ cssVar, prop }) => {
|
|
1109
|
+
let valueExpr;
|
|
1110
|
+
const kebabProp = (0, zss_engine_1.camelToKebabCase)(prop);
|
|
1111
|
+
if (!isNaN(maybeNumber) &&
|
|
1112
|
+
argSource.trim() === String(maybeNumber)) {
|
|
1113
|
+
valueExpr = JSON.stringify((0, zss_engine_1.applyCssValue)(maybeNumber, kebabProp));
|
|
1114
|
+
}
|
|
1115
|
+
else if ((argSource.startsWith('"') && argSource.endsWith('"')) ||
|
|
1116
|
+
(argSource.startsWith("'") && argSource.endsWith("'"))) {
|
|
1117
|
+
valueExpr = JSON.stringify((0, zss_engine_1.applyCssValue)(argSource.slice(1, -1), kebabProp));
|
|
1118
|
+
}
|
|
1119
|
+
else {
|
|
1120
|
+
valueExpr = isUnitlessProp(prop)
|
|
1121
|
+
? argSource
|
|
1122
|
+
: `(typeof (${argSource}) === 'number' ? (${argSource}) + 'px' : (${argSource}))`;
|
|
1123
|
+
}
|
|
1124
|
+
vars.push({ cssVar, valueExpr });
|
|
1125
|
+
});
|
|
1094
1126
|
});
|
|
1095
1127
|
return { style, vars };
|
|
1096
1128
|
};
|
package/dist/core.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { createFilter } from '@rollup/pluginutils';
|
|
|
2
2
|
import { parseSync } from '@swc/core';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { applyCssValue, genBase36Hash, exceptionCamelCase, camelToKebabCase, isAtRule, } from 'zss-engine';
|
|
5
|
-
import { traverse, collectReferenceIdentifiers, getStyleRecords, getStateWeights, collectLocalConsts, objectExpressionToObject, t, getRootIdentifier, extractOndemandStyles, deepMerge, scanAll, resolveFileError, resolveImportPath, getLeadingCommentLength, optimizer, themeHashOf, getFileDependencies, resolveExport, resolveComponentKey, resolveThemeSelector, DEFAULT_STYLE_PROP, } from '@plumeria/utils';
|
|
5
|
+
import { traverse, resolvePropertyPolicy, assertPropertyPolicy, collectReferenceIdentifiers, getStyleRecords, getStateWeights, collectLocalConsts, objectExpressionToObject, t, getRootIdentifier, extractOndemandStyles, deepMerge, scanAll, resolveFileError, resolveImportPath, getLeadingCommentLength, optimizer, themeHashOf, getFileDependencies, resolveExport, resolveComponentKey, resolveThemeSelector, DEFAULT_STYLE_PROP, } from '@plumeria/utils';
|
|
6
6
|
export const TARGET_EXTENSIONS = ['ts', 'tsx', 'js', 'jsx'];
|
|
7
7
|
export const EXTENSION_PATTERN = /\.(ts|tsx|js|jsx)$/;
|
|
8
8
|
const unwrapExport = (node) => {
|
|
@@ -131,6 +131,46 @@ const foldDynamicVars = (vars) => {
|
|
|
131
131
|
return `"${cssVar}": ${value}`;
|
|
132
132
|
});
|
|
133
133
|
};
|
|
134
|
+
const isUnitlessProp = (prop) => exceptionCamelCase.includes(prop) || prop.startsWith('--');
|
|
135
|
+
const collectVarProps = (style, cssVar, props) => {
|
|
136
|
+
const reference = `var(${cssVar})`;
|
|
137
|
+
for (const [prop, value] of Object.entries(style)) {
|
|
138
|
+
if (typeof value === 'string' && value.includes(reference))
|
|
139
|
+
props.push(prop);
|
|
140
|
+
else if (value !== null && typeof value === 'object')
|
|
141
|
+
collectVarProps(value, cssVar, props);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
const retargetVar = (style, cssVar, next, unitless) => {
|
|
145
|
+
const reference = `var(${cssVar})`;
|
|
146
|
+
for (const [prop, value] of Object.entries(style)) {
|
|
147
|
+
if (typeof value === 'string' && value.includes(reference)) {
|
|
148
|
+
if (isUnitlessProp(prop) === unitless)
|
|
149
|
+
style[prop] = value
|
|
150
|
+
.split(reference)
|
|
151
|
+
.join(`var(${next})`);
|
|
152
|
+
}
|
|
153
|
+
else if (value !== null && typeof value === 'object') {
|
|
154
|
+
retargetVar(value, cssVar, next, unitless);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
const splitVarByUnit = (style, cssVar) => {
|
|
159
|
+
const props = [];
|
|
160
|
+
collectVarProps(style, cssVar, props);
|
|
161
|
+
if (props.length === 0)
|
|
162
|
+
return [];
|
|
163
|
+
const lead = props[0];
|
|
164
|
+
const split = props.find((prop) => isUnitlessProp(prop) !== isUnitlessProp(lead));
|
|
165
|
+
if (!split)
|
|
166
|
+
return [{ cssVar, prop: lead }];
|
|
167
|
+
const splitVar = `${cssVar}-${camelToKebabCase(split).replace(/^-+/, '')}`;
|
|
168
|
+
retargetVar(style, cssVar, splitVar, isUnitlessProp(split));
|
|
169
|
+
return [
|
|
170
|
+
{ cssVar, prop: lead },
|
|
171
|
+
{ cssVar: splitVar, prop: split },
|
|
172
|
+
];
|
|
173
|
+
};
|
|
134
174
|
const applyVarFallback = (style, cssVar, literal) => {
|
|
135
175
|
const reference = `var(${cssVar})`;
|
|
136
176
|
for (const [prop, value] of Object.entries(style)) {
|
|
@@ -144,20 +184,9 @@ const applyVarFallback = (style, cssVar, literal) => {
|
|
|
144
184
|
}
|
|
145
185
|
}
|
|
146
186
|
};
|
|
147
|
-
const findVarProp = (style, cssVar) => {
|
|
148
|
-
for (const [prop, value] of Object.entries(style)) {
|
|
149
|
-
if (typeof value === 'string' && value.includes(cssVar))
|
|
150
|
-
return prop;
|
|
151
|
-
if (value !== null && typeof value === 'object') {
|
|
152
|
-
const nested = findVarProp(value, cssVar);
|
|
153
|
-
if (nested)
|
|
154
|
-
return nested;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return undefined;
|
|
158
|
-
};
|
|
159
187
|
export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
160
188
|
const filter = createFilter(options.include, options.exclude);
|
|
189
|
+
const propertyPolicy = resolvePropertyPolicy(options);
|
|
161
190
|
const styleProp = options.styleProp ?? DEFAULT_STYLE_PROP;
|
|
162
191
|
const cssLookup = new Map();
|
|
163
192
|
const cssFileLookup = new Map();
|
|
@@ -227,6 +256,7 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
227
256
|
tsx: true,
|
|
228
257
|
target: 'es2022',
|
|
229
258
|
});
|
|
259
|
+
assertPropertyPolicy(ast, propertyPolicy, id);
|
|
230
260
|
const leadingLen = getLeadingCommentLength(source);
|
|
231
261
|
const sourceBuffer = Buffer.from(source, 'utf-8');
|
|
232
262
|
const leadingBytes = Buffer.byteLength(source.slice(0, leadingLen), 'utf-8');
|
|
@@ -1014,47 +1044,49 @@ export const unpluginFactory = (options = {}, unpluginMeta) => {
|
|
|
1014
1044
|
const style = objectExpressionToObject(func.body, tempStaticTable, mergedKeyframesTable, mergedViewTransitionTable, mergedCreateThemeHashTable, scannedTables.createThemeObjectTable, mergedCreateTable, mergedCreateStaticHashTable, scannedTables.createStaticObjectTable, mergedVariantsTable);
|
|
1015
1045
|
if (!style)
|
|
1016
1046
|
return null;
|
|
1017
|
-
|
|
1047
|
+
const varGroups = new Map();
|
|
1048
|
+
varParams.forEach((param) => {
|
|
1018
1049
|
const cssVar = cssVars[param];
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1050
|
+
if (cssVar)
|
|
1051
|
+
varGroups.set(param, splitVarByUnit(style, cssVar));
|
|
1052
|
+
});
|
|
1053
|
+
withDefault.forEach(([param, expr]) => {
|
|
1022
1054
|
const literal = expr.type === 'StringLiteral' || expr.type === 'NumericLiteral'
|
|
1023
1055
|
? expr.value
|
|
1024
1056
|
: undefined;
|
|
1025
1057
|
if (literal === undefined)
|
|
1026
1058
|
return;
|
|
1027
|
-
applyVarFallback(style, cssVar, literal);
|
|
1059
|
+
(varGroups.get(param) ?? []).forEach(({ cssVar }) => applyVarFallback(style, cssVar, literal));
|
|
1028
1060
|
});
|
|
1029
1061
|
const vars = [];
|
|
1030
1062
|
runtime.forEach(({ param, source }) => {
|
|
1031
|
-
const
|
|
1032
|
-
|
|
1033
|
-
if (!targetProp)
|
|
1063
|
+
const groups = varGroups.get(param);
|
|
1064
|
+
if (!groups?.length)
|
|
1034
1065
|
return;
|
|
1035
1066
|
const argStart = source.span.start - baseByteOffset;
|
|
1036
1067
|
const argEnd = source.span.end - baseByteOffset;
|
|
1037
1068
|
const argSource = sourceBuffer
|
|
1038
1069
|
.subarray(argStart, argEnd)
|
|
1039
1070
|
.toString('utf-8');
|
|
1040
|
-
let valueExpr;
|
|
1041
|
-
const kebabProp = camelToKebabCase(targetProp);
|
|
1042
|
-
const isUnitless = exceptionCamelCase.includes(targetProp) ||
|
|
1043
|
-
targetProp.startsWith('--');
|
|
1044
1071
|
const maybeNumber = Number(argSource);
|
|
1045
|
-
|
|
1046
|
-
valueExpr
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1072
|
+
groups.forEach(({ cssVar, prop }) => {
|
|
1073
|
+
let valueExpr;
|
|
1074
|
+
const kebabProp = camelToKebabCase(prop);
|
|
1075
|
+
if (!isNaN(maybeNumber) &&
|
|
1076
|
+
argSource.trim() === String(maybeNumber)) {
|
|
1077
|
+
valueExpr = JSON.stringify(applyCssValue(maybeNumber, kebabProp));
|
|
1078
|
+
}
|
|
1079
|
+
else if ((argSource.startsWith('"') && argSource.endsWith('"')) ||
|
|
1080
|
+
(argSource.startsWith("'") && argSource.endsWith("'"))) {
|
|
1081
|
+
valueExpr = JSON.stringify(applyCssValue(argSource.slice(1, -1), kebabProp));
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
valueExpr = isUnitlessProp(prop)
|
|
1085
|
+
? argSource
|
|
1086
|
+
: `(typeof (${argSource}) === 'number' ? (${argSource}) + 'px' : (${argSource}))`;
|
|
1087
|
+
}
|
|
1088
|
+
vars.push({ cssVar, valueExpr });
|
|
1089
|
+
});
|
|
1058
1090
|
});
|
|
1059
1091
|
return { style, vars };
|
|
1060
1092
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumeria/unplugin",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.4.0",
|
|
4
4
|
"description": "Universal Plumeria plugin for various build tools",
|
|
5
5
|
"author": "Refirst 11",
|
|
6
6
|
"license": "MIT",
|
|
@@ -94,12 +94,12 @@
|
|
|
94
94
|
"dependencies": {
|
|
95
95
|
"@rollup/pluginutils": "^5.4.0",
|
|
96
96
|
"unplugin": "^3.0.0",
|
|
97
|
-
"@plumeria/utils": "^18.
|
|
97
|
+
"@plumeria/utils": "^18.4.0"
|
|
98
98
|
},
|
|
99
99
|
"devDependencies": {
|
|
100
100
|
"@swc/core": "1.15.47",
|
|
101
101
|
"vite": "^8.0.13",
|
|
102
|
-
"zss-engine": "2.
|
|
102
|
+
"zss-engine": "2.8.0"
|
|
103
103
|
},
|
|
104
104
|
"publishConfig": {
|
|
105
105
|
"access": "public",
|