@wyw-in-js/transform 0.3.0 → 0.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/esm/transform/Entrypoint.js +2 -1
- package/esm/transform/Entrypoint.js.map +1 -1
- package/esm/transform/generators/createStylisPreprocessor.js +171 -51
- package/esm/transform/generators/createStylisPreprocessor.js.map +1 -1
- package/lib/transform/Entrypoint.js +2 -1
- package/lib/transform/Entrypoint.js.map +1 -1
- package/lib/transform/generators/createStylisPreprocessor.js +176 -51
- package/lib/transform/generators/createStylisPreprocessor.js.map +1 -1
- package/package.json +7 -7
- package/types/transform/Entrypoint.js +4 -1
- package/types/transform/generators/createStylisPreprocessor.d.ts +4 -1
- package/types/transform/generators/createStylisPreprocessor.js +187 -59
|
@@ -23,7 +23,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.createStylisPreprocessor = exports.createStylisUrlReplacePlugin = exports.stylisGlobalPlugin = exports.transformUrl = void 0;
|
|
26
|
+
exports.createStylisPreprocessor = exports.createKeyframeSuffixerPlugin = exports.createStylisUrlReplacePlugin = exports.stylisGlobalPlugin = exports.transformUrl = void 0;
|
|
27
|
+
/* eslint-disable no-continue */
|
|
27
28
|
const path = __importStar(require("path"));
|
|
28
29
|
const stylis_1 = require("stylis");
|
|
29
30
|
const POSIX_SEP = path.posix.sep;
|
|
@@ -38,11 +39,51 @@ function transformUrl(url, outputFilename, sourceFilename, platformPath = path)
|
|
|
38
39
|
return relative.split(platformPath.sep).join(POSIX_SEP);
|
|
39
40
|
}
|
|
40
41
|
exports.transformUrl = transformUrl;
|
|
42
|
+
const DEFINED_KEYFRAMES = Symbol('definedKeyframes');
|
|
43
|
+
const ORIGINAL_VALUE_KEY = Symbol('originalValue');
|
|
44
|
+
const IS_GLOBAL_KEYFRAMES = Symbol('isGlobalKeyframes');
|
|
45
|
+
const getOriginalElementValue = (element) => {
|
|
46
|
+
return element ? element[ORIGINAL_VALUE_KEY] ?? element.value : '';
|
|
47
|
+
};
|
|
48
|
+
function throwIfNotProd(key, value, type) {
|
|
49
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
50
|
+
throw new Error(`"element.${key}" has type "${type}" (${JSON.stringify(value, null, 2)}), it's not expected. Please report a bug if it happens.`);
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
function childrenIsString(children) {
|
|
55
|
+
return (typeof children === 'string' ||
|
|
56
|
+
throwIfNotProd('children', children, 'Element[]'));
|
|
57
|
+
}
|
|
58
|
+
function propsAreStrings(props) {
|
|
59
|
+
return Array.isArray(props) || throwIfNotProd('props', props, 'string');
|
|
60
|
+
}
|
|
61
|
+
function propsIsString(props) {
|
|
62
|
+
return (typeof props === 'string' || throwIfNotProd('props', props, 'string[]'));
|
|
63
|
+
}
|
|
64
|
+
const isDeclaration = (element) => {
|
|
65
|
+
return (element.type === stylis_1.DECLARATION &&
|
|
66
|
+
propsIsString(element.props) &&
|
|
67
|
+
childrenIsString(element.children));
|
|
68
|
+
};
|
|
69
|
+
const isKeyframes = (element) => {
|
|
70
|
+
return element.type === stylis_1.KEYFRAMES && propsAreStrings(element.props);
|
|
71
|
+
};
|
|
72
|
+
const isRuleset = (element) => {
|
|
73
|
+
return element.type === stylis_1.RULESET && propsAreStrings(element.props);
|
|
74
|
+
};
|
|
41
75
|
/**
|
|
42
76
|
* Stylis plugin that mimics :global() selector behavior from Stylis v3.
|
|
43
77
|
*/
|
|
44
78
|
const stylisGlobalPlugin = (element) => {
|
|
45
|
-
function getGlobalSelectorModifiers(
|
|
79
|
+
function getGlobalSelectorModifiers(el) {
|
|
80
|
+
const { parent } = el;
|
|
81
|
+
const value = getOriginalElementValue(el);
|
|
82
|
+
const parentValue = getOriginalElementValue(parent);
|
|
83
|
+
if ((parent?.children.length === 0 && parentValue.includes(':global(')) ||
|
|
84
|
+
(parent && !value.includes(':global('))) {
|
|
85
|
+
return getGlobalSelectorModifiers(parent);
|
|
86
|
+
}
|
|
46
87
|
const match = value.match(/(&\f( )?)?:global\(/);
|
|
47
88
|
if (match === null) {
|
|
48
89
|
throw new Error(`Failed to match :global() selector in "${value}". Please report a bug if it happens.`);
|
|
@@ -53,62 +94,53 @@ const stylisGlobalPlugin = (element) => {
|
|
|
53
94
|
includeSpaceDelimiter: !!spaceDelimiter,
|
|
54
95
|
};
|
|
55
96
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
97
|
+
if (!isRuleset(element)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
Object.assign(element, {
|
|
101
|
+
props: element.props.map((cssSelector) => {
|
|
102
|
+
// The value can be changed by other middlewares, but we need an original one with `&`
|
|
103
|
+
Object.assign(element, { [ORIGINAL_VALUE_KEY]: element.value });
|
|
104
|
+
// Avoids calling tokenize() on every string
|
|
105
|
+
if (!cssSelector.includes(':global(')) {
|
|
106
|
+
return cssSelector;
|
|
63
107
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// Match for ":global()"
|
|
86
|
-
if (tokens[i + 2] === '()') {
|
|
87
|
-
selector = [
|
|
88
|
-
...tokens.slice(i + 4),
|
|
89
|
-
includeSpaceDelimiter ? ' ' : '',
|
|
90
|
-
...(includeBaseSelector ? tokens.slice(0, i - 1) : []),
|
|
91
|
-
includeSpaceDelimiter ? '' : ' ',
|
|
92
|
-
].join('');
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
//
|
|
96
|
-
// Match for ":global(selector)"
|
|
97
|
-
selector = [
|
|
98
|
-
tokens[i + 2].slice(1, -1),
|
|
99
|
-
includeSpaceDelimiter ? ' ' : '',
|
|
100
|
-
...(includeBaseSelector ? tokens.slice(0, i - 1) : []),
|
|
101
|
-
includeSpaceDelimiter ? '' : ' ',
|
|
102
|
-
].join('');
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
108
|
+
if (element.children.length === 0) {
|
|
109
|
+
return cssSelector;
|
|
110
|
+
}
|
|
111
|
+
const { includeBaseSelector, includeSpaceDelimiter } = getGlobalSelectorModifiers(element);
|
|
112
|
+
const tokens = (0, stylis_1.tokenize)(cssSelector);
|
|
113
|
+
let selector = '';
|
|
114
|
+
for (let i = 0, len = tokens.length; i < len; i++) {
|
|
115
|
+
const token = tokens[i];
|
|
116
|
+
//
|
|
117
|
+
// Match for ":global("
|
|
118
|
+
if (token === ':' && tokens[i + 1] === 'global') {
|
|
119
|
+
//
|
|
120
|
+
// Match for ":global()"
|
|
121
|
+
if (tokens[i + 2] === '()') {
|
|
122
|
+
selector = [
|
|
123
|
+
...tokens.slice(i + 4),
|
|
124
|
+
includeSpaceDelimiter ? ' ' : '',
|
|
125
|
+
...(includeBaseSelector ? tokens.slice(0, i - 1) : []),
|
|
126
|
+
includeSpaceDelimiter ? '' : ' ',
|
|
127
|
+
].join('');
|
|
128
|
+
break;
|
|
105
129
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
130
|
+
//
|
|
131
|
+
// Match for ":global(selector)"
|
|
132
|
+
selector = [
|
|
133
|
+
tokens[i + 2].slice(1, -1),
|
|
134
|
+
includeSpaceDelimiter ? ' ' : '',
|
|
135
|
+
...(includeBaseSelector ? tokens.slice(0, i - 1) : []),
|
|
136
|
+
includeSpaceDelimiter ? '' : ' ',
|
|
137
|
+
].join('');
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return selector;
|
|
142
|
+
}),
|
|
143
|
+
});
|
|
112
144
|
};
|
|
113
145
|
exports.stylisGlobalPlugin = stylisGlobalPlugin;
|
|
114
146
|
function createStylisUrlReplacePlugin(filename, outputFilename) {
|
|
@@ -117,20 +149,116 @@ function createStylisUrlReplacePlugin(filename, outputFilename) {
|
|
|
117
149
|
// When writing to a file, we need to adjust the relative paths inside url(..) expressions.
|
|
118
150
|
// It'll allow css-loader to resolve an imported asset properly.
|
|
119
151
|
// eslint-disable-next-line no-param-reassign
|
|
120
|
-
element.return = element.value.replace(/\b(url\((["']?))(\.[^)]+?)(\2\))/g, (
|
|
152
|
+
element.return = element.value.replace(/\b(url\((["']?))(\.[^)]+?)(\2\))/g, (_match, p1, _p2, p3, p4) => p1 + transformUrl(p3, outputFilename, filename) + p4);
|
|
121
153
|
}
|
|
122
154
|
};
|
|
123
155
|
}
|
|
124
156
|
exports.createStylisUrlReplacePlugin = createStylisUrlReplacePlugin;
|
|
157
|
+
function createKeyframeSuffixerPlugin() {
|
|
158
|
+
const prefixes = ['webkit', 'moz', 'ms', 'o', ''].map((i) => i ? `-${i}-` : '');
|
|
159
|
+
const getPrefixedProp = (prop) => prefixes.map((prefix) => `${prefix}${prop}`);
|
|
160
|
+
const buildPropsRegexp = (prop, isAtRule) => {
|
|
161
|
+
const [at, colon] = isAtRule ? ['@', ''] : ['', ':'];
|
|
162
|
+
return new RegExp(`^(${at}(?:${getPrefixedProp(prop).join('|')})${colon})\\s*`);
|
|
163
|
+
};
|
|
164
|
+
const animationNameRegexp = /:global\(([\w_-]+)\)|([\w_-]+)/;
|
|
165
|
+
const getReplacer = (startsWith, searchValue, replacer) => {
|
|
166
|
+
return (input) => {
|
|
167
|
+
const [fullMatch] = input.match(startsWith) ?? [];
|
|
168
|
+
if (fullMatch === undefined) {
|
|
169
|
+
return input;
|
|
170
|
+
}
|
|
171
|
+
const rest = input.slice(fullMatch.length);
|
|
172
|
+
return fullMatch + rest.replace(searchValue, replacer);
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
const elementToKeyframeSuffix = (el) => {
|
|
176
|
+
if (el.parent) {
|
|
177
|
+
return elementToKeyframeSuffix(el.parent);
|
|
178
|
+
}
|
|
179
|
+
return el.value.replaceAll(/[^a-zA-Z0-9_-]/g, '');
|
|
180
|
+
};
|
|
181
|
+
const animationPropsSet = new Set([
|
|
182
|
+
...getPrefixedProp('animation'),
|
|
183
|
+
...getPrefixedProp('animation-name'),
|
|
184
|
+
]);
|
|
185
|
+
const getDefinedKeyframes = (element) => {
|
|
186
|
+
if (element[DEFINED_KEYFRAMES]) {
|
|
187
|
+
return element[DEFINED_KEYFRAMES];
|
|
188
|
+
}
|
|
189
|
+
if (element.parent) {
|
|
190
|
+
return getDefinedKeyframes(element.parent);
|
|
191
|
+
}
|
|
192
|
+
const keyframes = new Set();
|
|
193
|
+
for (const sibling of element.siblings ?? []) {
|
|
194
|
+
if (!isKeyframes(sibling) || sibling[IS_GLOBAL_KEYFRAMES] === true) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
keyframes.add(sibling.props[0]);
|
|
198
|
+
}
|
|
199
|
+
Object.assign(element, { [DEFINED_KEYFRAMES]: keyframes });
|
|
200
|
+
return keyframes;
|
|
201
|
+
};
|
|
202
|
+
return (element) => {
|
|
203
|
+
if (isKeyframes(element) && element.parent) {
|
|
204
|
+
const suffix = elementToKeyframeSuffix(element);
|
|
205
|
+
const replaceFn = (_match, globalMatch, scopedMatch) => globalMatch || `${scopedMatch}-${suffix}`;
|
|
206
|
+
Object.assign(element, {
|
|
207
|
+
[IS_GLOBAL_KEYFRAMES]: element.props[0]?.startsWith(':global(') ?? false,
|
|
208
|
+
props: element.props.map(getReplacer(/^\s*/, animationNameRegexp, replaceFn)),
|
|
209
|
+
value: getReplacer(buildPropsRegexp('keyframes', true), animationNameRegexp, replaceFn)(element.value),
|
|
210
|
+
});
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (isDeclaration(element)) {
|
|
214
|
+
const suffix = elementToKeyframeSuffix(element);
|
|
215
|
+
const keys = [
|
|
216
|
+
'children',
|
|
217
|
+
'return',
|
|
218
|
+
'value',
|
|
219
|
+
];
|
|
220
|
+
if (animationPropsSet.has(element.props)) {
|
|
221
|
+
const scopedKeyframes = getDefinedKeyframes(element);
|
|
222
|
+
const patch = Object.fromEntries(keys.map((key) => {
|
|
223
|
+
const tokens = (0, stylis_1.tokenize)(element[key]);
|
|
224
|
+
let result = '';
|
|
225
|
+
for (let i = 0; i < tokens.length; i += 1) {
|
|
226
|
+
if (tokens[i] === ':' &&
|
|
227
|
+
tokens[i + 1] === 'global' &&
|
|
228
|
+
tokens[i + 2].startsWith('(')) {
|
|
229
|
+
const globalName = tokens[i + 2].substring(1, tokens[i + 2].length - 1);
|
|
230
|
+
i += 2;
|
|
231
|
+
result += globalName;
|
|
232
|
+
if (tokens[i + 1] !== ';') {
|
|
233
|
+
result += ' ';
|
|
234
|
+
}
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (scopedKeyframes.has(tokens[i])) {
|
|
238
|
+
result += `${tokens[i]}-${suffix}`;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
result += tokens[i];
|
|
242
|
+
}
|
|
243
|
+
return [key, result];
|
|
244
|
+
}));
|
|
245
|
+
Object.assign(element, patch);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
exports.createKeyframeSuffixerPlugin = createKeyframeSuffixerPlugin;
|
|
251
|
+
const isMiddleware = (obj) => obj !== null;
|
|
125
252
|
function createStylisPreprocessor(options) {
|
|
126
253
|
function stylisPreprocess(selector, text) {
|
|
127
254
|
const compiled = (0, stylis_1.compile)(`${selector} {${text}}\n`);
|
|
128
255
|
return (0, stylis_1.serialize)(compiled, (0, stylis_1.middleware)([
|
|
129
256
|
createStylisUrlReplacePlugin(options.filename, options.outputFilename),
|
|
130
257
|
exports.stylisGlobalPlugin,
|
|
131
|
-
stylis_1.prefixer,
|
|
258
|
+
options.prefixer === false ? null : stylis_1.prefixer,
|
|
259
|
+
createKeyframeSuffixerPlugin(),
|
|
132
260
|
stylis_1.stringify,
|
|
133
|
-
]));
|
|
261
|
+
].filter(isMiddleware)));
|
|
134
262
|
}
|
|
135
263
|
return stylisPreprocess;
|
|
136
264
|
}
|