@tailwindcss-mangle/core 1.2.7
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 +7 -0
- package/dist/index.cjs +325 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.mjs +302 -0
- package/package.json +61 -0
package/README.md
ADDED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const postcss = require('postcss');
|
|
4
|
+
const parser = require('postcss-selector-parser');
|
|
5
|
+
const parse5 = require('parse5');
|
|
6
|
+
const shared = require('@tailwindcss-mangle/shared');
|
|
7
|
+
const t = require('@babel/types');
|
|
8
|
+
const core = require('@babel/core');
|
|
9
|
+
|
|
10
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
11
|
+
|
|
12
|
+
function _interopNamespaceCompat(e) {
|
|
13
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
14
|
+
const n = Object.create(null);
|
|
15
|
+
if (e) {
|
|
16
|
+
for (const k in e) {
|
|
17
|
+
n[k] = e[k];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
n.default = e;
|
|
21
|
+
return n;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const postcss__default = /*#__PURE__*/_interopDefaultCompat(postcss);
|
|
25
|
+
const parser__default = /*#__PURE__*/_interopDefaultCompat(parser);
|
|
26
|
+
const t__namespace = /*#__PURE__*/_interopNamespaceCompat(t);
|
|
27
|
+
|
|
28
|
+
function isObject(value) {
|
|
29
|
+
return value !== null && typeof value === "object";
|
|
30
|
+
}
|
|
31
|
+
function _defu(baseObject, defaults, namespace = ".", merger) {
|
|
32
|
+
if (!isObject(defaults)) {
|
|
33
|
+
return _defu(baseObject, {}, namespace, merger);
|
|
34
|
+
}
|
|
35
|
+
const object = Object.assign({}, defaults);
|
|
36
|
+
for (const key in baseObject) {
|
|
37
|
+
if (key === "__proto__" || key === "constructor") {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const value = baseObject[key];
|
|
41
|
+
if (value === null || value === void 0) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (merger && merger(object, key, value, namespace)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(value) && Array.isArray(object[key])) {
|
|
48
|
+
object[key] = [...value, ...object[key]];
|
|
49
|
+
} else if (isObject(value) && isObject(object[key])) {
|
|
50
|
+
object[key] = _defu(
|
|
51
|
+
value,
|
|
52
|
+
object[key],
|
|
53
|
+
(namespace ? `${namespace}.` : "") + key.toString(),
|
|
54
|
+
merger
|
|
55
|
+
);
|
|
56
|
+
} else {
|
|
57
|
+
object[key] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return object;
|
|
61
|
+
}
|
|
62
|
+
function createDefu(merger) {
|
|
63
|
+
return (...arguments_) => (
|
|
64
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
65
|
+
arguments_.reduce((p, c) => _defu(p, c, "", merger), {})
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
const defu = createDefu();
|
|
69
|
+
|
|
70
|
+
const postcssPlugin = "postcss-mangle-tailwindcss-plugin";
|
|
71
|
+
function isVueScoped(s) {
|
|
72
|
+
if (s.parent) {
|
|
73
|
+
const index = s.parent.nodes.indexOf(s);
|
|
74
|
+
if (index > -1) {
|
|
75
|
+
const nextNode = s.parent.nodes[index + 1];
|
|
76
|
+
if (nextNode && nextNode.type === "attribute" && nextNode.attribute.includes("data-v-")) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const postcssMangleTailwindcssPlugin = (options) => {
|
|
84
|
+
const { ignoreVueScoped } = defu(options, {
|
|
85
|
+
ignoreVueScoped: true
|
|
86
|
+
});
|
|
87
|
+
if (options?.scene === "loader") {
|
|
88
|
+
let set = /* @__PURE__ */ new Set();
|
|
89
|
+
if (options && options.runtimeSet) {
|
|
90
|
+
set = options.runtimeSet;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
postcssPlugin,
|
|
94
|
+
Rule(rule) {
|
|
95
|
+
rule.selector = parser__default((selectors) => {
|
|
96
|
+
selectors.walkClasses((s) => {
|
|
97
|
+
if (s.value) {
|
|
98
|
+
const existed = set.has(s.value);
|
|
99
|
+
if (existed) {
|
|
100
|
+
if (ignoreVueScoped && isVueScoped(s)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
s.value = options.classGenerator.generateClassName(s.value).name;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}).processSync(rule.selector);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
} else {
|
|
111
|
+
let newClassMap = {};
|
|
112
|
+
if (options && options.classGenerator) {
|
|
113
|
+
newClassMap = options.classGenerator.newClassMap;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
postcssPlugin,
|
|
117
|
+
Rule(rule) {
|
|
118
|
+
rule.selector = parser__default((selectors) => {
|
|
119
|
+
selectors.walkClasses((s) => {
|
|
120
|
+
if (s.value) {
|
|
121
|
+
const hit = newClassMap[s.value];
|
|
122
|
+
const existed = Boolean(hit);
|
|
123
|
+
if (existed) {
|
|
124
|
+
if (ignoreVueScoped && isVueScoped(s)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
s.value = hit.name;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}).processSync(rule.selector);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
postcssMangleTailwindcssPlugin.postcss = true;
|
|
137
|
+
|
|
138
|
+
function cssHandler(rawSource, options) {
|
|
139
|
+
const acceptedPlugins = [postcssMangleTailwindcssPlugin(options)];
|
|
140
|
+
return postcss__default(acceptedPlugins).process(rawSource).css;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
({
|
|
144
|
+
HTML: parse5.html.NS.HTML,
|
|
145
|
+
XML: parse5.html.NS.XML,
|
|
146
|
+
MATHML: parse5.html.NS.MATHML,
|
|
147
|
+
SVG: parse5.html.NS.SVG,
|
|
148
|
+
XLINK: parse5.html.NS.XLINK,
|
|
149
|
+
XMLNS: parse5.html.NS.XMLNS
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Determines if a given node is a document or not
|
|
154
|
+
* @param {Node} node Node to test
|
|
155
|
+
* @return {boolean}
|
|
156
|
+
*/
|
|
157
|
+
function isDocument(node) {
|
|
158
|
+
return node.nodeName === '#document';
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Determines if a given node is a document fragment or not
|
|
162
|
+
* @param {Node} node Node to test
|
|
163
|
+
* @return {boolean}
|
|
164
|
+
*/
|
|
165
|
+
function isDocumentFragment(node) {
|
|
166
|
+
return node.nodeName === '#document-fragment';
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Determines if a given node is a template node or not
|
|
170
|
+
* @param {Node} node Node to test
|
|
171
|
+
* @return {boolean}
|
|
172
|
+
*/
|
|
173
|
+
function isTemplateNode(node) {
|
|
174
|
+
return node.nodeName === 'template';
|
|
175
|
+
}
|
|
176
|
+
const isElementNode = parse5.defaultTreeAdapter.isElementNode;
|
|
177
|
+
const isCommentNode = parse5.defaultTreeAdapter.isCommentNode;
|
|
178
|
+
const isDocumentTypeNode = parse5.defaultTreeAdapter.isDocumentTypeNode;
|
|
179
|
+
const isTextNode = parse5.defaultTreeAdapter.isTextNode;
|
|
180
|
+
/**
|
|
181
|
+
* Determines if a given node is a parent or not
|
|
182
|
+
* @param {Node} node Node to test
|
|
183
|
+
* @return {boolean}
|
|
184
|
+
*/
|
|
185
|
+
function isParentNode(node) {
|
|
186
|
+
return (isDocument(node) ||
|
|
187
|
+
isDocumentFragment(node) ||
|
|
188
|
+
isElementNode(node) ||
|
|
189
|
+
isTemplateNode(node));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
parse5.defaultTreeAdapter.appendChild;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Traverses the tree of a given node
|
|
196
|
+
* @param {Node} node Node to traverse
|
|
197
|
+
* @param {Visitor} visitor Visitor to apply
|
|
198
|
+
* @param {ParentNode=} parent Parent node of the current node
|
|
199
|
+
* @return {void}
|
|
200
|
+
*/
|
|
201
|
+
function traverse(node, visitor, parent) {
|
|
202
|
+
const shouldVisitChildren = typeof visitor['pre:node'] !== 'function' ||
|
|
203
|
+
visitor['pre:node'](node, parent) !== false;
|
|
204
|
+
if (shouldVisitChildren && isParentNode(node)) {
|
|
205
|
+
for (const child of node.childNodes) {
|
|
206
|
+
traverse(child, visitor, node);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (typeof visitor.node === 'function') {
|
|
210
|
+
visitor.node(node, parent);
|
|
211
|
+
}
|
|
212
|
+
if (typeof visitor.document === 'function' && isDocument(node)) {
|
|
213
|
+
visitor.document(node);
|
|
214
|
+
}
|
|
215
|
+
if (typeof visitor.documentFragment === 'function' &&
|
|
216
|
+
isDocumentFragment(node)) {
|
|
217
|
+
visitor.documentFragment(node, parent);
|
|
218
|
+
}
|
|
219
|
+
if (typeof visitor.element === 'function' && isElementNode(node)) {
|
|
220
|
+
visitor.element(node, parent);
|
|
221
|
+
}
|
|
222
|
+
if (typeof visitor.template === 'function' && isTemplateNode(node)) {
|
|
223
|
+
visitor.template(node, parent);
|
|
224
|
+
}
|
|
225
|
+
if (typeof visitor.comment === 'function' && isCommentNode(node)) {
|
|
226
|
+
visitor.comment(node, parent);
|
|
227
|
+
}
|
|
228
|
+
if (typeof visitor.text === 'function' && isTextNode(node)) {
|
|
229
|
+
visitor.text(node, parent);
|
|
230
|
+
}
|
|
231
|
+
if (typeof visitor.documentType === 'function' && isDocumentTypeNode(node)) {
|
|
232
|
+
visitor.documentType(node, parent);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function htmlHandler(rawSource, options) {
|
|
237
|
+
const { runtimeSet, classGenerator } = options;
|
|
238
|
+
const fragment = parse5.parse(rawSource);
|
|
239
|
+
traverse(fragment, {
|
|
240
|
+
element(node) {
|
|
241
|
+
const attribute = node.attrs.find((x) => x.name === "class");
|
|
242
|
+
if (attribute) {
|
|
243
|
+
const array = shared.splitCode(attribute.value, {
|
|
244
|
+
splitQuote: false
|
|
245
|
+
});
|
|
246
|
+
for (const v of array) {
|
|
247
|
+
if (runtimeSet.has(v)) {
|
|
248
|
+
attribute.value = attribute.value.replace(shared.makeRegex(v), classGenerator.generateClassName(v).name);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
return parse5.serialize(fragment);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const isProd = () => process.env.NODE_ENV === "production";
|
|
258
|
+
|
|
259
|
+
function handleValue(string_, node, options) {
|
|
260
|
+
const { runtimeSet: set, classGenerator: clsGen, splitQuote = true } = options;
|
|
261
|
+
const array = shared.splitCode(string_, {
|
|
262
|
+
splitQuote
|
|
263
|
+
});
|
|
264
|
+
let rawString = string_;
|
|
265
|
+
for (const v of array) {
|
|
266
|
+
if (set.has(v)) {
|
|
267
|
+
let ignoreFlag = false;
|
|
268
|
+
if (Array.isArray(node.leadingComments)) {
|
|
269
|
+
ignoreFlag = node.leadingComments.findIndex((x) => x.value.includes("tw-mangle") && x.value.includes("ignore")) > -1;
|
|
270
|
+
}
|
|
271
|
+
if (!ignoreFlag) {
|
|
272
|
+
rawString = rawString.replace(shared.makeRegex(v), clsGen.generateClassName(v).name);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return rawString;
|
|
277
|
+
}
|
|
278
|
+
function jsHandler(rawSource, options) {
|
|
279
|
+
const result = core.transformSync(rawSource, {
|
|
280
|
+
babelrc: false,
|
|
281
|
+
ast: true,
|
|
282
|
+
plugins: [
|
|
283
|
+
() => {
|
|
284
|
+
return {
|
|
285
|
+
visitor: {
|
|
286
|
+
StringLiteral: {
|
|
287
|
+
enter(p) {
|
|
288
|
+
const n = p.node;
|
|
289
|
+
n.value = handleValue(n.value, n, options);
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
TemplateElement: {
|
|
293
|
+
enter(p) {
|
|
294
|
+
const n = p.node;
|
|
295
|
+
n.value.raw = handleValue(n.value.raw, n, options);
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
CallExpression: {
|
|
299
|
+
enter(p) {
|
|
300
|
+
const n = p.node;
|
|
301
|
+
if (t__namespace.isIdentifier(n.callee) && n.callee.name === "eval" && t__namespace.isStringLiteral(n.arguments[0])) {
|
|
302
|
+
const res = jsHandler(n.arguments[0].value, options);
|
|
303
|
+
if (res.code) {
|
|
304
|
+
n.arguments[0].value = res.code;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// noScope: true
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
],
|
|
314
|
+
minified: options.minified ?? isProd(),
|
|
315
|
+
sourceMaps: false,
|
|
316
|
+
configFile: false
|
|
317
|
+
});
|
|
318
|
+
return result;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
exports.ClassGenerator = shared.ClassGenerator;
|
|
322
|
+
exports.cssHandler = cssHandler;
|
|
323
|
+
exports.handleValue = handleValue;
|
|
324
|
+
exports.htmlHandler = htmlHandler;
|
|
325
|
+
exports.jsHandler = jsHandler;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ClassGenerator } from '@tailwindcss-mangle/shared';
|
|
2
|
+
export { ClassGenerator } from '@tailwindcss-mangle/shared';
|
|
3
|
+
import { StringLiteral, TemplateElement } from '@babel/types';
|
|
4
|
+
import { BabelFileResult } from '@babel/core';
|
|
5
|
+
|
|
6
|
+
interface IClassGeneratorContextItem {
|
|
7
|
+
name: string;
|
|
8
|
+
usedBy: any[];
|
|
9
|
+
}
|
|
10
|
+
interface IClassGeneratorOptions {
|
|
11
|
+
reserveClassName?: (string | RegExp)[];
|
|
12
|
+
customGenerate?: (original: string, opts: IClassGeneratorOptions, context: Record<string, any>) => string | undefined;
|
|
13
|
+
log?: boolean;
|
|
14
|
+
exclude?: (string | RegExp)[];
|
|
15
|
+
include?: (string | RegExp)[];
|
|
16
|
+
ignoreClass?: (string | RegExp)[];
|
|
17
|
+
classPrefix?: string;
|
|
18
|
+
}
|
|
19
|
+
interface IHandlerOptions {
|
|
20
|
+
runtimeSet: Set<string>;
|
|
21
|
+
classGenerator: ClassGenerator;
|
|
22
|
+
}
|
|
23
|
+
interface IHtmlHandlerOptions extends IHandlerOptions {
|
|
24
|
+
}
|
|
25
|
+
interface IJsHandlerOptions extends IHandlerOptions {
|
|
26
|
+
splitQuote?: boolean;
|
|
27
|
+
minified?: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface ICssHandlerOptions extends IHandlerOptions {
|
|
30
|
+
scene?: 'loader' | 'process';
|
|
31
|
+
ignoreVueScoped?: boolean;
|
|
32
|
+
}
|
|
33
|
+
interface ClassSetOutputOptions {
|
|
34
|
+
filename: string;
|
|
35
|
+
dir?: string;
|
|
36
|
+
type: 'all' | 'partial';
|
|
37
|
+
}
|
|
38
|
+
interface ClassMapOutputOptions {
|
|
39
|
+
filename: string;
|
|
40
|
+
dir?: string;
|
|
41
|
+
}
|
|
42
|
+
interface Options {
|
|
43
|
+
classGenerator?: IClassGeneratorOptions;
|
|
44
|
+
exclude?: string[];
|
|
45
|
+
include?: string[];
|
|
46
|
+
classSetOutput?: boolean | ClassSetOutputOptions;
|
|
47
|
+
classMapOutput?: boolean | ClassMapOutputOptions;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
declare function cssHandler(rawSource: string, options: ICssHandlerOptions): string;
|
|
51
|
+
|
|
52
|
+
declare function htmlHandler(rawSource: string, options: IHtmlHandlerOptions): string;
|
|
53
|
+
|
|
54
|
+
declare function handleValue(string_: string, node: StringLiteral | TemplateElement, options: IJsHandlerOptions): string;
|
|
55
|
+
declare function jsHandler(rawSource: string, options: IJsHandlerOptions): BabelFileResult;
|
|
56
|
+
|
|
57
|
+
export { ClassMapOutputOptions, ClassSetOutputOptions, IClassGeneratorContextItem, IClassGeneratorOptions, ICssHandlerOptions, IHandlerOptions, IHtmlHandlerOptions, IJsHandlerOptions, Options, cssHandler, handleValue, htmlHandler, jsHandler };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import postcss from 'postcss';
|
|
2
|
+
import parser from 'postcss-selector-parser';
|
|
3
|
+
import { html, defaultTreeAdapter, parse, serialize } from 'parse5';
|
|
4
|
+
import { splitCode, makeRegex } from '@tailwindcss-mangle/shared';
|
|
5
|
+
export { ClassGenerator } from '@tailwindcss-mangle/shared';
|
|
6
|
+
import * as t from '@babel/types';
|
|
7
|
+
import { transformSync } from '@babel/core';
|
|
8
|
+
|
|
9
|
+
function isObject(value) {
|
|
10
|
+
return value !== null && typeof value === "object";
|
|
11
|
+
}
|
|
12
|
+
function _defu(baseObject, defaults, namespace = ".", merger) {
|
|
13
|
+
if (!isObject(defaults)) {
|
|
14
|
+
return _defu(baseObject, {}, namespace, merger);
|
|
15
|
+
}
|
|
16
|
+
const object = Object.assign({}, defaults);
|
|
17
|
+
for (const key in baseObject) {
|
|
18
|
+
if (key === "__proto__" || key === "constructor") {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const value = baseObject[key];
|
|
22
|
+
if (value === null || value === void 0) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (merger && merger(object, key, value, namespace)) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(value) && Array.isArray(object[key])) {
|
|
29
|
+
object[key] = [...value, ...object[key]];
|
|
30
|
+
} else if (isObject(value) && isObject(object[key])) {
|
|
31
|
+
object[key] = _defu(
|
|
32
|
+
value,
|
|
33
|
+
object[key],
|
|
34
|
+
(namespace ? `${namespace}.` : "") + key.toString(),
|
|
35
|
+
merger
|
|
36
|
+
);
|
|
37
|
+
} else {
|
|
38
|
+
object[key] = value;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return object;
|
|
42
|
+
}
|
|
43
|
+
function createDefu(merger) {
|
|
44
|
+
return (...arguments_) => (
|
|
45
|
+
// eslint-disable-next-line unicorn/no-array-reduce
|
|
46
|
+
arguments_.reduce((p, c) => _defu(p, c, "", merger), {})
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const defu = createDefu();
|
|
50
|
+
|
|
51
|
+
const postcssPlugin = "postcss-mangle-tailwindcss-plugin";
|
|
52
|
+
function isVueScoped(s) {
|
|
53
|
+
if (s.parent) {
|
|
54
|
+
const index = s.parent.nodes.indexOf(s);
|
|
55
|
+
if (index > -1) {
|
|
56
|
+
const nextNode = s.parent.nodes[index + 1];
|
|
57
|
+
if (nextNode && nextNode.type === "attribute" && nextNode.attribute.includes("data-v-")) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const postcssMangleTailwindcssPlugin = (options) => {
|
|
65
|
+
const { ignoreVueScoped } = defu(options, {
|
|
66
|
+
ignoreVueScoped: true
|
|
67
|
+
});
|
|
68
|
+
if (options?.scene === "loader") {
|
|
69
|
+
let set = /* @__PURE__ */ new Set();
|
|
70
|
+
if (options && options.runtimeSet) {
|
|
71
|
+
set = options.runtimeSet;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
postcssPlugin,
|
|
75
|
+
Rule(rule) {
|
|
76
|
+
rule.selector = parser((selectors) => {
|
|
77
|
+
selectors.walkClasses((s) => {
|
|
78
|
+
if (s.value) {
|
|
79
|
+
const existed = set.has(s.value);
|
|
80
|
+
if (existed) {
|
|
81
|
+
if (ignoreVueScoped && isVueScoped(s)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
s.value = options.classGenerator.generateClassName(s.value).name;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}).processSync(rule.selector);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
} else {
|
|
92
|
+
let newClassMap = {};
|
|
93
|
+
if (options && options.classGenerator) {
|
|
94
|
+
newClassMap = options.classGenerator.newClassMap;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
postcssPlugin,
|
|
98
|
+
Rule(rule) {
|
|
99
|
+
rule.selector = parser((selectors) => {
|
|
100
|
+
selectors.walkClasses((s) => {
|
|
101
|
+
if (s.value) {
|
|
102
|
+
const hit = newClassMap[s.value];
|
|
103
|
+
const existed = Boolean(hit);
|
|
104
|
+
if (existed) {
|
|
105
|
+
if (ignoreVueScoped && isVueScoped(s)) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
s.value = hit.name;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}).processSync(rule.selector);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
postcssMangleTailwindcssPlugin.postcss = true;
|
|
118
|
+
|
|
119
|
+
function cssHandler(rawSource, options) {
|
|
120
|
+
const acceptedPlugins = [postcssMangleTailwindcssPlugin(options)];
|
|
121
|
+
return postcss(acceptedPlugins).process(rawSource).css;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
({
|
|
125
|
+
HTML: html.NS.HTML,
|
|
126
|
+
XML: html.NS.XML,
|
|
127
|
+
MATHML: html.NS.MATHML,
|
|
128
|
+
SVG: html.NS.SVG,
|
|
129
|
+
XLINK: html.NS.XLINK,
|
|
130
|
+
XMLNS: html.NS.XMLNS
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Determines if a given node is a document or not
|
|
135
|
+
* @param {Node} node Node to test
|
|
136
|
+
* @return {boolean}
|
|
137
|
+
*/
|
|
138
|
+
function isDocument(node) {
|
|
139
|
+
return node.nodeName === '#document';
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Determines if a given node is a document fragment or not
|
|
143
|
+
* @param {Node} node Node to test
|
|
144
|
+
* @return {boolean}
|
|
145
|
+
*/
|
|
146
|
+
function isDocumentFragment(node) {
|
|
147
|
+
return node.nodeName === '#document-fragment';
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Determines if a given node is a template node or not
|
|
151
|
+
* @param {Node} node Node to test
|
|
152
|
+
* @return {boolean}
|
|
153
|
+
*/
|
|
154
|
+
function isTemplateNode(node) {
|
|
155
|
+
return node.nodeName === 'template';
|
|
156
|
+
}
|
|
157
|
+
const isElementNode = defaultTreeAdapter.isElementNode;
|
|
158
|
+
const isCommentNode = defaultTreeAdapter.isCommentNode;
|
|
159
|
+
const isDocumentTypeNode = defaultTreeAdapter.isDocumentTypeNode;
|
|
160
|
+
const isTextNode = defaultTreeAdapter.isTextNode;
|
|
161
|
+
/**
|
|
162
|
+
* Determines if a given node is a parent or not
|
|
163
|
+
* @param {Node} node Node to test
|
|
164
|
+
* @return {boolean}
|
|
165
|
+
*/
|
|
166
|
+
function isParentNode(node) {
|
|
167
|
+
return (isDocument(node) ||
|
|
168
|
+
isDocumentFragment(node) ||
|
|
169
|
+
isElementNode(node) ||
|
|
170
|
+
isTemplateNode(node));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
defaultTreeAdapter.appendChild;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Traverses the tree of a given node
|
|
177
|
+
* @param {Node} node Node to traverse
|
|
178
|
+
* @param {Visitor} visitor Visitor to apply
|
|
179
|
+
* @param {ParentNode=} parent Parent node of the current node
|
|
180
|
+
* @return {void}
|
|
181
|
+
*/
|
|
182
|
+
function traverse(node, visitor, parent) {
|
|
183
|
+
const shouldVisitChildren = typeof visitor['pre:node'] !== 'function' ||
|
|
184
|
+
visitor['pre:node'](node, parent) !== false;
|
|
185
|
+
if (shouldVisitChildren && isParentNode(node)) {
|
|
186
|
+
for (const child of node.childNodes) {
|
|
187
|
+
traverse(child, visitor, node);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (typeof visitor.node === 'function') {
|
|
191
|
+
visitor.node(node, parent);
|
|
192
|
+
}
|
|
193
|
+
if (typeof visitor.document === 'function' && isDocument(node)) {
|
|
194
|
+
visitor.document(node);
|
|
195
|
+
}
|
|
196
|
+
if (typeof visitor.documentFragment === 'function' &&
|
|
197
|
+
isDocumentFragment(node)) {
|
|
198
|
+
visitor.documentFragment(node, parent);
|
|
199
|
+
}
|
|
200
|
+
if (typeof visitor.element === 'function' && isElementNode(node)) {
|
|
201
|
+
visitor.element(node, parent);
|
|
202
|
+
}
|
|
203
|
+
if (typeof visitor.template === 'function' && isTemplateNode(node)) {
|
|
204
|
+
visitor.template(node, parent);
|
|
205
|
+
}
|
|
206
|
+
if (typeof visitor.comment === 'function' && isCommentNode(node)) {
|
|
207
|
+
visitor.comment(node, parent);
|
|
208
|
+
}
|
|
209
|
+
if (typeof visitor.text === 'function' && isTextNode(node)) {
|
|
210
|
+
visitor.text(node, parent);
|
|
211
|
+
}
|
|
212
|
+
if (typeof visitor.documentType === 'function' && isDocumentTypeNode(node)) {
|
|
213
|
+
visitor.documentType(node, parent);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function htmlHandler(rawSource, options) {
|
|
218
|
+
const { runtimeSet, classGenerator } = options;
|
|
219
|
+
const fragment = parse(rawSource);
|
|
220
|
+
traverse(fragment, {
|
|
221
|
+
element(node) {
|
|
222
|
+
const attribute = node.attrs.find((x) => x.name === "class");
|
|
223
|
+
if (attribute) {
|
|
224
|
+
const array = splitCode(attribute.value, {
|
|
225
|
+
splitQuote: false
|
|
226
|
+
});
|
|
227
|
+
for (const v of array) {
|
|
228
|
+
if (runtimeSet.has(v)) {
|
|
229
|
+
attribute.value = attribute.value.replace(makeRegex(v), classGenerator.generateClassName(v).name);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
return serialize(fragment);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const isProd = () => process.env.NODE_ENV === "production";
|
|
239
|
+
|
|
240
|
+
function handleValue(string_, node, options) {
|
|
241
|
+
const { runtimeSet: set, classGenerator: clsGen, splitQuote = true } = options;
|
|
242
|
+
const array = splitCode(string_, {
|
|
243
|
+
splitQuote
|
|
244
|
+
});
|
|
245
|
+
let rawString = string_;
|
|
246
|
+
for (const v of array) {
|
|
247
|
+
if (set.has(v)) {
|
|
248
|
+
let ignoreFlag = false;
|
|
249
|
+
if (Array.isArray(node.leadingComments)) {
|
|
250
|
+
ignoreFlag = node.leadingComments.findIndex((x) => x.value.includes("tw-mangle") && x.value.includes("ignore")) > -1;
|
|
251
|
+
}
|
|
252
|
+
if (!ignoreFlag) {
|
|
253
|
+
rawString = rawString.replace(makeRegex(v), clsGen.generateClassName(v).name);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return rawString;
|
|
258
|
+
}
|
|
259
|
+
function jsHandler(rawSource, options) {
|
|
260
|
+
const result = transformSync(rawSource, {
|
|
261
|
+
babelrc: false,
|
|
262
|
+
ast: true,
|
|
263
|
+
plugins: [
|
|
264
|
+
() => {
|
|
265
|
+
return {
|
|
266
|
+
visitor: {
|
|
267
|
+
StringLiteral: {
|
|
268
|
+
enter(p) {
|
|
269
|
+
const n = p.node;
|
|
270
|
+
n.value = handleValue(n.value, n, options);
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
TemplateElement: {
|
|
274
|
+
enter(p) {
|
|
275
|
+
const n = p.node;
|
|
276
|
+
n.value.raw = handleValue(n.value.raw, n, options);
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
CallExpression: {
|
|
280
|
+
enter(p) {
|
|
281
|
+
const n = p.node;
|
|
282
|
+
if (t.isIdentifier(n.callee) && n.callee.name === "eval" && t.isStringLiteral(n.arguments[0])) {
|
|
283
|
+
const res = jsHandler(n.arguments[0].value, options);
|
|
284
|
+
if (res.code) {
|
|
285
|
+
n.arguments[0].value = res.code;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// noScope: true
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
],
|
|
295
|
+
minified: options.minified ?? isProd(),
|
|
296
|
+
sourceMaps: false,
|
|
297
|
+
configFile: false
|
|
298
|
+
});
|
|
299
|
+
return result;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export { cssHandler, handleValue, htmlHandler, jsHandler };
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tailwindcss-mangle/core",
|
|
3
|
+
"version": "1.2.7",
|
|
4
|
+
"description": "The core of tailwindcss-mangle",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"import": "./dist/index.mjs",
|
|
9
|
+
"require": "./dist/index.cjs"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"typesVersions": {
|
|
13
|
+
"*": {
|
|
14
|
+
"*": [
|
|
15
|
+
"./dist/*",
|
|
16
|
+
"./dist/index.d.ts"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"main": "./dist/index.cjs",
|
|
21
|
+
"module": "./dist/index.mjs",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"tailwindcss",
|
|
28
|
+
"patch",
|
|
29
|
+
"core",
|
|
30
|
+
"mangle"
|
|
31
|
+
],
|
|
32
|
+
"author": "SonOfMagic <qq1324318532@gmail.com>",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public",
|
|
36
|
+
"registry": "https://registry.npmjs.org/"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@babel/core": "^7.22.10",
|
|
40
|
+
"@babel/types": "^7.22.10",
|
|
41
|
+
"parse5": "^7.1.2",
|
|
42
|
+
"postcss": "^8.4.27",
|
|
43
|
+
"postcss-selector-parser": "^6.0.13",
|
|
44
|
+
"@tailwindcss-mangle/shared": "^1.2.7"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@parse5/tools": "^0.2.0",
|
|
48
|
+
"@types/babel__core": "^7.20.1"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/sonofmagic/tailwindcss-mangle",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/sonofmagic/tailwindcss-mangle.git"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "unbuild",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"test:dev": "vitest",
|
|
59
|
+
"coverage": "vitest run --coverage"
|
|
60
|
+
}
|
|
61
|
+
}
|