mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2025-12-12 13:42:50 +00:00
1
This commit is contained in:
parent
e645760760
commit
7c0ccb944d
203
packages/vite-plugin/dist/index.js
vendored
203
packages/vite-plugin/dist/index.js
vendored
@ -226,26 +226,46 @@
|
|||||||
*/
|
*/
|
||||||
const getDynamicClassNames = (value) => {
|
const getDynamicClassNames = (value) => {
|
||||||
const names = new Set();
|
const names = new Set();
|
||||||
// 匹配数组中的字符串元素(如 'text-center')
|
// 匹配函数调用中的对象参数(如 parseClass({'!bg-surface-50': hoverable}))
|
||||||
const arrayRegex = /['"](.*?)['"]/g;
|
const functionCallRegex = /\w+\s*\(\s*\{([^}]*)\}\s*\)/gs;
|
||||||
let arrayMatch;
|
let funcMatch;
|
||||||
while ((arrayMatch = arrayRegex.exec(value)) !== null) {
|
while ((funcMatch = functionCallRegex.exec(value)) !== null) {
|
||||||
arrayMatch[1].trim() && names.add(arrayMatch[1]);
|
const objContent = funcMatch[1];
|
||||||
|
// 提取对象中的键
|
||||||
|
const keyRegex = /['"](.*?)['"]\s*:/gs;
|
||||||
|
let keyMatch;
|
||||||
|
while ((keyMatch = keyRegex.exec(objContent)) !== null) {
|
||||||
|
keyMatch[1].trim() && names.add(keyMatch[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 匹配对象键(如 { 'text-a': 1 })
|
// 匹配对象键(如 { 'text-a': 1 })- 优化版本,避免跨行错误匹配
|
||||||
const objKeyRegex = /[{,]\s*['"](.*?)['"]\s*:/g;
|
const objKeyRegex = /[{,]\s*['"](.*?)['"]\s*:/gs;
|
||||||
let objKeyMatch;
|
let objKeyMatch;
|
||||||
while ((objKeyMatch = objKeyRegex.exec(value)) !== null) {
|
while ((objKeyMatch = objKeyRegex.exec(value)) !== null) {
|
||||||
objKeyMatch[1].trim() && names.add(objKeyMatch[1]);
|
const className = objKeyMatch[1].trim();
|
||||||
|
// 确保是有效的CSS类名,避免匹配到错误内容
|
||||||
|
if (className && !className.includes("\n") && !className.includes("\t")) {
|
||||||
|
names.add(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 匹配数组中的字符串元素(如 'text-center')- 优化版本
|
||||||
|
const arrayStringRegex = /(?:^|[,\[\s])\s*['"](.*?)['"]/gs;
|
||||||
|
let arrayMatch;
|
||||||
|
while ((arrayMatch = arrayStringRegex.exec(value)) !== null) {
|
||||||
|
const className = arrayMatch[1].trim();
|
||||||
|
// 确保是有效的CSS类名
|
||||||
|
if (className && !className.includes("\n") && !className.includes("\t")) {
|
||||||
|
names.add(className);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 匹配三元表达式中的字符串(如 'dark' 和 'light')
|
// 匹配三元表达式中的字符串(如 'dark' 和 'light')
|
||||||
const ternaryRegex = /(\?|:)\s*['"](.*?)['"]/g;
|
const ternaryRegex = /(\?|:)\s*['"](.*?)['"]/gs;
|
||||||
let ternaryMatch;
|
let ternaryMatch;
|
||||||
while ((ternaryMatch = ternaryRegex.exec(value)) !== null) {
|
while ((ternaryMatch = ternaryRegex.exec(value)) !== null) {
|
||||||
ternaryMatch[2].trim() && names.add(ternaryMatch[2]);
|
ternaryMatch[2].trim() && names.add(ternaryMatch[2]);
|
||||||
}
|
}
|
||||||
// 匹配反引号模板字符串
|
// 匹配反引号模板字符串 - 改进版本
|
||||||
const templateRegex = /`([^`]*)`/g;
|
const templateRegex = /`([^`]*)`/gs;
|
||||||
let templateMatch;
|
let templateMatch;
|
||||||
while ((templateMatch = templateRegex.exec(value)) !== null) {
|
while ((templateMatch = templateRegex.exec(value)) !== null) {
|
||||||
const templateContent = templateMatch[1];
|
const templateContent = templateMatch[1];
|
||||||
@ -259,7 +279,7 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
// 提取模板字符串中 ${} 表达式内的字符串
|
// 提取模板字符串中 ${} 表达式内的字符串
|
||||||
const expressionRegex = /\$\{([^}]*)\}/g;
|
const expressionRegex = /\$\{([^}]*)\}/gs;
|
||||||
let expressionMatch;
|
let expressionMatch;
|
||||||
while ((expressionMatch = expressionRegex.exec(templateContent)) !== null) {
|
while ((expressionMatch = expressionRegex.exec(templateContent)) !== null) {
|
||||||
const expression = expressionMatch[1];
|
const expression = expressionMatch[1];
|
||||||
@ -267,38 +287,183 @@
|
|||||||
getDynamicClassNames(expression).forEach((name) => names.add(name));
|
getDynamicClassNames(expression).forEach((name) => names.add(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 处理混合字符串(模板字符串 + 普通文本),如 "`text-red-900` text-red-1000"
|
||||||
|
const mixedStringRegex = /`[^`]*`\s+([a-zA-Z0-9\-_\s]+)/g;
|
||||||
|
let mixedMatch;
|
||||||
|
while ((mixedMatch = mixedStringRegex.exec(value)) !== null) {
|
||||||
|
const additionalClasses = mixedMatch[1].trim().split(/\s+/);
|
||||||
|
additionalClasses.forEach((className) => {
|
||||||
|
className.trim() && names.add(className.trim());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 处理普通字符串,多个类名用空格分割
|
||||||
|
const stringRegex = /['"]([\w\s\-!:\/]+?)['"]/gs;
|
||||||
|
let stringMatch;
|
||||||
|
while ((stringMatch = stringRegex.exec(value)) !== null) {
|
||||||
|
const classNames = stringMatch[1].trim().split(/\s+/);
|
||||||
|
classNames.forEach((className) => {
|
||||||
|
className.trim() && names.add(className.trim());
|
||||||
|
});
|
||||||
|
}
|
||||||
return Array.from(names);
|
return Array.from(names);
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* 获取类名
|
* 获取类名
|
||||||
*/
|
*/
|
||||||
function getClassNames(code) {
|
function getClassNames(code) {
|
||||||
const classRegex = /(?:class|:class|:pt)\s*=\s*(['"`])([\s\S]*?)\1/gi;
|
// 修改正则表达式以支持多行匹配,避免内层引号冲突
|
||||||
|
const classRegex = /(?:class|:class|:pt|:hover-class)\s*=\s*(['"`])((?:[^'"`\\]|\\.|`[^`]*`|'[^']*'|"[^"]*")*?)\1/gis;
|
||||||
const classNames = new Set();
|
const classNames = new Set();
|
||||||
let match;
|
let match;
|
||||||
while ((match = classRegex.exec(code)) !== null) {
|
while ((match = classRegex.exec(code)) !== null) {
|
||||||
const isStaticClass = match[0].startsWith("class");
|
const attribute = match[0].split("=")[0].trim();
|
||||||
|
const isStaticClass = attribute === "class" || attribute === "hover-class";
|
||||||
|
const isPtAttribute = attribute.includes("pt");
|
||||||
const value = match[2].trim();
|
const value = match[2].trim();
|
||||||
if (isStaticClass) {
|
if (isStaticClass) {
|
||||||
// 处理静态 class
|
// 处理静态 class 和 hover-class
|
||||||
value.split(/\s+/).forEach((name) => name && classNames.add(name));
|
value.split(/\s+/).forEach((name) => name && classNames.add(name));
|
||||||
}
|
}
|
||||||
|
else if (isPtAttribute) {
|
||||||
|
// 处理 :pt 属性中的 className
|
||||||
|
parseClasNameFromPt(value, classNames);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
// 处理动态 :class
|
// 处理动态 :class 和 :hover-class
|
||||||
getDynamicClassNames(value).forEach((name) => classNames.add(name));
|
getDynamicClassNames(value).forEach((name) => classNames.add(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Array.from(classNames);
|
return Array.from(classNames);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 从 :pt 属性中解析 className
|
||||||
|
*/
|
||||||
|
function parseClasNameFromPt(value, classNames) {
|
||||||
|
// 递归查找所有 className 属性
|
||||||
|
const classNameRegex = /className\s*:\s*/g;
|
||||||
|
let match;
|
||||||
|
while ((match = classNameRegex.exec(value)) !== null) {
|
||||||
|
const startPos = match.index + match[0].length;
|
||||||
|
const classNameValue = extractComplexValue(value, startPos);
|
||||||
|
if (classNameValue) {
|
||||||
|
// 如果是字符串字面量
|
||||||
|
if (classNameValue.startsWith('"') ||
|
||||||
|
classNameValue.startsWith("'") ||
|
||||||
|
classNameValue.startsWith("`")) {
|
||||||
|
if (classNameValue.startsWith("`")) {
|
||||||
|
// 处理模板字符串
|
||||||
|
getDynamicClassNames(classNameValue).forEach((name) => classNames.add(name));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 处理普通字符串
|
||||||
|
const strMatch = classNameValue.match(/['"](.*?)['"]/);
|
||||||
|
if (strMatch) {
|
||||||
|
strMatch[1].split(/\s+/).forEach((name) => name && classNames.add(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 处理动态值(如函数调用、对象等)
|
||||||
|
getDynamicClassNames(classNameValue).forEach((name) => classNames.add(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 提取复杂值(支持嵌套引号和括号)
|
||||||
|
*/
|
||||||
|
function extractComplexValue(text, startPos) {
|
||||||
|
let pos = startPos;
|
||||||
|
let depth = 0;
|
||||||
|
let inString = false;
|
||||||
|
let stringChar = "";
|
||||||
|
let result = "";
|
||||||
|
// 跳过开头的空白字符
|
||||||
|
while (pos < text.length && /\s/.test(text[pos])) {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
while (pos < text.length) {
|
||||||
|
const char = text[pos];
|
||||||
|
if (!inString) {
|
||||||
|
if (char === '"' || char === "'" || char === "`") {
|
||||||
|
inString = true;
|
||||||
|
stringChar = char;
|
||||||
|
result += char;
|
||||||
|
}
|
||||||
|
else if (char === "{" || char === "(" || char === "[") {
|
||||||
|
depth++;
|
||||||
|
result += char;
|
||||||
|
}
|
||||||
|
else if (char === "}" || char === ")" || char === "]") {
|
||||||
|
if (depth === 0 && char === "}") {
|
||||||
|
// 遇到顶层的 } 时结束
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
depth--;
|
||||||
|
result += char;
|
||||||
|
}
|
||||||
|
else if (char === "," && depth === 0) {
|
||||||
|
// 遇到顶层的逗号时结束
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (char === "\n" && depth === 0 && result.trim() !== "") {
|
||||||
|
// 如果遇到换行且不在嵌套结构中,且已有内容,则结束
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += char;
|
||||||
|
if (char === stringChar && text[pos - 1] !== "\\") {
|
||||||
|
inString = false;
|
||||||
|
stringChar = "";
|
||||||
|
// 如果字符串结束且depth为0,检查是否应该结束
|
||||||
|
if (depth === 0) {
|
||||||
|
// 看看下一个非空白字符是什么
|
||||||
|
let nextPos = pos + 1;
|
||||||
|
while (nextPos < text.length && /\s/.test(text[nextPos])) {
|
||||||
|
nextPos++;
|
||||||
|
}
|
||||||
|
if (nextPos < text.length && (text[nextPos] === "," || text[nextPos] === "}")) {
|
||||||
|
// 如果下一个字符是逗号或右括号,则结束
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return result.trim() || null;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 获取 class 内容
|
* 获取 class 内容
|
||||||
*/
|
*/
|
||||||
function getClassContent(code) {
|
function getClassContent(code) {
|
||||||
const regex = /(?:class|:class|:pt)\s*=\s*(['"`])([\s\S]*?)\1/g;
|
// 修改正则表达式以支持多行匹配,避免内层引号冲突
|
||||||
|
const regex = /(?:class|:class|:pt|:hover-class)\s*=\s*(['"`])((?:[^'"`\\]|\\.|`[^`]*`|'[^']*'|"[^"]*")*?)\1/gis;
|
||||||
const texts = [];
|
const texts = [];
|
||||||
let match;
|
let match;
|
||||||
while ((match = regex.exec(code)) !== null) {
|
while ((match = regex.exec(code)) !== null) {
|
||||||
texts.push(match[2]);
|
const attribute = match[0].split("=")[0].trim();
|
||||||
|
const isPtAttribute = attribute.includes("pt");
|
||||||
|
const value = match[2];
|
||||||
|
if (isPtAttribute) {
|
||||||
|
// 手动解析 className 值
|
||||||
|
const classNameRegex = /className\s*:\s*/g;
|
||||||
|
let classNameMatchResult;
|
||||||
|
while ((classNameMatchResult = classNameRegex.exec(value)) !== null) {
|
||||||
|
const startPos = classNameMatchResult.index + classNameMatchResult[0].length;
|
||||||
|
const classNameValue = extractComplexValue(value, startPos);
|
||||||
|
if (classNameValue) {
|
||||||
|
texts.push(classNameValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
texts.push(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return texts;
|
return texts;
|
||||||
}
|
}
|
||||||
@ -522,6 +687,8 @@
|
|||||||
return `type ${name}${extendsStr} = {${content}}`;
|
return `type ${name}${extendsStr} = {${content}}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// test();
|
||||||
|
// npx ./src/uniapp-x/utils.ts
|
||||||
|
|
||||||
// 全局 service 对象,用于存储服务结构
|
// 全局 service 对象,用于存储服务结构
|
||||||
const service = {};
|
const service = {};
|
||||||
|
|||||||
@ -26,3 +26,4 @@ export declare function isTailwindClass(className: string): boolean;
|
|||||||
* 将 interface 转换为 type
|
* 将 interface 转换为 type
|
||||||
*/
|
*/
|
||||||
export declare function interfaceToType(code: string): string;
|
export declare function interfaceToType(code: string): string;
|
||||||
|
export declare function test(): void;
|
||||||
|
|||||||
@ -4,29 +4,50 @@
|
|||||||
export const getDynamicClassNames = (value: string): string[] => {
|
export const getDynamicClassNames = (value: string): string[] => {
|
||||||
const names = new Set<string>();
|
const names = new Set<string>();
|
||||||
|
|
||||||
// 匹配数组中的字符串元素(如 'text-center')
|
// 匹配函数调用中的对象参数(如 parseClass({'!bg-surface-50': hoverable}))
|
||||||
const arrayRegex = /['"](.*?)['"]/g;
|
const functionCallRegex = /\w+\s*\(\s*\{([^}]*)\}\s*\)/gs;
|
||||||
let arrayMatch;
|
let funcMatch;
|
||||||
while ((arrayMatch = arrayRegex.exec(value)) !== null) {
|
while ((funcMatch = functionCallRegex.exec(value)) !== null) {
|
||||||
arrayMatch[1].trim() && names.add(arrayMatch[1]);
|
const objContent = funcMatch[1];
|
||||||
|
// 提取对象中的键
|
||||||
|
const keyRegex = /['"](.*?)['"]\s*:/gs;
|
||||||
|
let keyMatch;
|
||||||
|
while ((keyMatch = keyRegex.exec(objContent)) !== null) {
|
||||||
|
keyMatch[1].trim() && names.add(keyMatch[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 匹配对象键(如 { 'text-a': 1 })
|
// 匹配对象键(如 { 'text-a': 1 })- 优化版本,避免跨行错误匹配
|
||||||
const objKeyRegex = /[{,]\s*['"](.*?)['"]\s*:/g;
|
const objKeyRegex = /[{,]\s*['"](.*?)['"]\s*:/gs;
|
||||||
let objKeyMatch;
|
let objKeyMatch;
|
||||||
while ((objKeyMatch = objKeyRegex.exec(value)) !== null) {
|
while ((objKeyMatch = objKeyRegex.exec(value)) !== null) {
|
||||||
objKeyMatch[1].trim() && names.add(objKeyMatch[1]);
|
const className = objKeyMatch[1].trim();
|
||||||
|
// 确保是有效的CSS类名,避免匹配到错误内容
|
||||||
|
if (className && !className.includes("\n") && !className.includes("\t")) {
|
||||||
|
names.add(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配数组中的字符串元素(如 'text-center')- 优化版本
|
||||||
|
const arrayStringRegex = /(?:^|[,\[\s])\s*['"](.*?)['"]/gs;
|
||||||
|
let arrayMatch;
|
||||||
|
while ((arrayMatch = arrayStringRegex.exec(value)) !== null) {
|
||||||
|
const className = arrayMatch[1].trim();
|
||||||
|
// 确保是有效的CSS类名
|
||||||
|
if (className && !className.includes("\n") && !className.includes("\t")) {
|
||||||
|
names.add(className);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 匹配三元表达式中的字符串(如 'dark' 和 'light')
|
// 匹配三元表达式中的字符串(如 'dark' 和 'light')
|
||||||
const ternaryRegex = /(\?|:)\s*['"](.*?)['"]/g;
|
const ternaryRegex = /(\?|:)\s*['"](.*?)['"]/gs;
|
||||||
let ternaryMatch;
|
let ternaryMatch;
|
||||||
while ((ternaryMatch = ternaryRegex.exec(value)) !== null) {
|
while ((ternaryMatch = ternaryRegex.exec(value)) !== null) {
|
||||||
ternaryMatch[2].trim() && names.add(ternaryMatch[2]);
|
ternaryMatch[2].trim() && names.add(ternaryMatch[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 匹配反引号模板字符串
|
// 匹配反引号模板字符串 - 改进版本
|
||||||
const templateRegex = /`([^`]*)`/g;
|
const templateRegex = /`([^`]*)`/gs;
|
||||||
let templateMatch;
|
let templateMatch;
|
||||||
while ((templateMatch = templateRegex.exec(value)) !== null) {
|
while ((templateMatch = templateRegex.exec(value)) !== null) {
|
||||||
const templateContent = templateMatch[1];
|
const templateContent = templateMatch[1];
|
||||||
@ -42,7 +63,7 @@ export const getDynamicClassNames = (value: string): string[] => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 提取模板字符串中 ${} 表达式内的字符串
|
// 提取模板字符串中 ${} 表达式内的字符串
|
||||||
const expressionRegex = /\$\{([^}]*)\}/g;
|
const expressionRegex = /\$\{([^}]*)\}/gs;
|
||||||
let expressionMatch;
|
let expressionMatch;
|
||||||
while ((expressionMatch = expressionRegex.exec(templateContent)) !== null) {
|
while ((expressionMatch = expressionRegex.exec(templateContent)) !== null) {
|
||||||
const expression = expressionMatch[1];
|
const expression = expressionMatch[1];
|
||||||
@ -51,6 +72,26 @@ export const getDynamicClassNames = (value: string): string[] => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理混合字符串(模板字符串 + 普通文本),如 "`text-red-900` text-red-1000"
|
||||||
|
const mixedStringRegex = /`[^`]*`\s+([a-zA-Z0-9\-_\s]+)/g;
|
||||||
|
let mixedMatch;
|
||||||
|
while ((mixedMatch = mixedStringRegex.exec(value)) !== null) {
|
||||||
|
const additionalClasses = mixedMatch[1].trim().split(/\s+/);
|
||||||
|
additionalClasses.forEach((className) => {
|
||||||
|
className.trim() && names.add(className.trim());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理普通字符串,多个类名用空格分割
|
||||||
|
const stringRegex = /['"]([\w\s\-!:\/]+?)['"]/gs;
|
||||||
|
let stringMatch;
|
||||||
|
while ((stringMatch = stringRegex.exec(value)) !== null) {
|
||||||
|
const classNames = stringMatch[1].trim().split(/\s+/);
|
||||||
|
classNames.forEach((className) => {
|
||||||
|
className.trim() && names.add(className.trim());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Array.from(names);
|
return Array.from(names);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,19 +99,26 @@ export const getDynamicClassNames = (value: string): string[] => {
|
|||||||
* 获取类名
|
* 获取类名
|
||||||
*/
|
*/
|
||||||
export function getClassNames(code: string): string[] {
|
export function getClassNames(code: string): string[] {
|
||||||
const classRegex = /(?:class|:class|:pt)\s*=\s*(['"`])([\s\S]*?)\1/gi;
|
// 修改正则表达式以支持多行匹配,避免内层引号冲突
|
||||||
|
const classRegex =
|
||||||
|
/(?:class|:class|:pt|:hover-class)\s*=\s*(['"`])((?:[^'"`\\]|\\.|`[^`]*`|'[^']*'|"[^"]*")*?)\1/gis;
|
||||||
const classNames = new Set<string>();
|
const classNames = new Set<string>();
|
||||||
let match;
|
let match;
|
||||||
|
|
||||||
while ((match = classRegex.exec(code)) !== null) {
|
while ((match = classRegex.exec(code)) !== null) {
|
||||||
const isStaticClass = match[0].startsWith("class");
|
const attribute = match[0].split("=")[0].trim();
|
||||||
|
const isStaticClass = attribute === "class" || attribute === "hover-class";
|
||||||
|
const isPtAttribute = attribute.includes("pt");
|
||||||
const value = match[2].trim();
|
const value = match[2].trim();
|
||||||
|
|
||||||
if (isStaticClass) {
|
if (isStaticClass) {
|
||||||
// 处理静态 class
|
// 处理静态 class 和 hover-class
|
||||||
value.split(/\s+/).forEach((name) => name && classNames.add(name));
|
value.split(/\s+/).forEach((name) => name && classNames.add(name));
|
||||||
|
} else if (isPtAttribute) {
|
||||||
|
// 处理 :pt 属性中的 className
|
||||||
|
parseClasNameFromPt(value, classNames);
|
||||||
} else {
|
} else {
|
||||||
// 处理动态 :class
|
// 处理动态 :class 和 :hover-class
|
||||||
getDynamicClassNames(value).forEach((name) => classNames.add(name));
|
getDynamicClassNames(value).forEach((name) => classNames.add(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,16 +126,141 @@ export function getClassNames(code: string): string[] {
|
|||||||
return Array.from(classNames);
|
return Array.from(classNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 :pt 属性中解析 className
|
||||||
|
*/
|
||||||
|
function parseClasNameFromPt(value: string, classNames: Set<string>) {
|
||||||
|
// 递归查找所有 className 属性
|
||||||
|
const classNameRegex = /className\s*:\s*/g;
|
||||||
|
let match;
|
||||||
|
|
||||||
|
while ((match = classNameRegex.exec(value)) !== null) {
|
||||||
|
const startPos = match.index + match[0].length;
|
||||||
|
const classNameValue = extractComplexValue(value, startPos);
|
||||||
|
|
||||||
|
if (classNameValue) {
|
||||||
|
// 如果是字符串字面量
|
||||||
|
if (
|
||||||
|
classNameValue.startsWith('"') ||
|
||||||
|
classNameValue.startsWith("'") ||
|
||||||
|
classNameValue.startsWith("`")
|
||||||
|
) {
|
||||||
|
if (classNameValue.startsWith("`")) {
|
||||||
|
// 处理模板字符串
|
||||||
|
getDynamicClassNames(classNameValue).forEach((name) => classNames.add(name));
|
||||||
|
} else {
|
||||||
|
// 处理普通字符串
|
||||||
|
const strMatch = classNameValue.match(/['"](.*?)['"]/);
|
||||||
|
if (strMatch) {
|
||||||
|
strMatch[1].split(/\s+/).forEach((name) => name && classNames.add(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 处理动态值(如函数调用、对象等)
|
||||||
|
getDynamicClassNames(classNameValue).forEach((name) => classNames.add(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提取复杂值(支持嵌套引号和括号)
|
||||||
|
*/
|
||||||
|
function extractComplexValue(text: string, startPos: number): string | null {
|
||||||
|
let pos = startPos;
|
||||||
|
let depth = 0;
|
||||||
|
let inString = false;
|
||||||
|
let stringChar = "";
|
||||||
|
let result = "";
|
||||||
|
|
||||||
|
// 跳过开头的空白字符
|
||||||
|
while (pos < text.length && /\s/.test(text[pos])) {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pos < text.length) {
|
||||||
|
const char = text[pos];
|
||||||
|
|
||||||
|
if (!inString) {
|
||||||
|
if (char === '"' || char === "'" || char === "`") {
|
||||||
|
inString = true;
|
||||||
|
stringChar = char;
|
||||||
|
result += char;
|
||||||
|
} else if (char === "{" || char === "(" || char === "[") {
|
||||||
|
depth++;
|
||||||
|
result += char;
|
||||||
|
} else if (char === "}" || char === ")" || char === "]") {
|
||||||
|
if (depth === 0 && char === "}") {
|
||||||
|
// 遇到顶层的 } 时结束
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
depth--;
|
||||||
|
result += char;
|
||||||
|
} else if (char === "," && depth === 0) {
|
||||||
|
// 遇到顶层的逗号时结束
|
||||||
|
break;
|
||||||
|
} else if (char === "\n" && depth === 0 && result.trim() !== "") {
|
||||||
|
// 如果遇到换行且不在嵌套结构中,且已有内容,则结束
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
result += char;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += char;
|
||||||
|
if (char === stringChar && text[pos - 1] !== "\\") {
|
||||||
|
inString = false;
|
||||||
|
stringChar = "";
|
||||||
|
|
||||||
|
// 如果字符串结束且depth为0,检查是否应该结束
|
||||||
|
if (depth === 0) {
|
||||||
|
// 看看下一个非空白字符是什么
|
||||||
|
let nextPos = pos + 1;
|
||||||
|
while (nextPos < text.length && /\s/.test(text[nextPos])) {
|
||||||
|
nextPos++;
|
||||||
|
}
|
||||||
|
if (nextPos < text.length && (text[nextPos] === "," || text[nextPos] === "}")) {
|
||||||
|
// 如果下一个字符是逗号或右括号,则结束
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.trim() || null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 class 内容
|
* 获取 class 内容
|
||||||
*/
|
*/
|
||||||
export function getClassContent(code: string) {
|
export function getClassContent(code: string) {
|
||||||
const regex = /(?:class|:class|:pt)\s*=\s*(['"`])([\s\S]*?)\1/g;
|
// 修改正则表达式以支持多行匹配,避免内层引号冲突
|
||||||
|
const regex =
|
||||||
|
/(?:class|:class|:pt|:hover-class)\s*=\s*(['"`])((?:[^'"`\\]|\\.|`[^`]*`|'[^']*'|"[^"]*")*?)\1/gis;
|
||||||
const texts: string[] = [];
|
const texts: string[] = [];
|
||||||
|
|
||||||
let match;
|
let match;
|
||||||
while ((match = regex.exec(code)) !== null) {
|
while ((match = regex.exec(code)) !== null) {
|
||||||
texts.push(match[2]);
|
const attribute = match[0].split("=")[0].trim();
|
||||||
|
const isPtAttribute = attribute.includes("pt");
|
||||||
|
const value = match[2];
|
||||||
|
|
||||||
|
if (isPtAttribute) {
|
||||||
|
// 手动解析 className 值
|
||||||
|
const classNameRegex = /className\s*:\s*/g;
|
||||||
|
let classNameMatchResult;
|
||||||
|
while ((classNameMatchResult = classNameRegex.exec(value)) !== null) {
|
||||||
|
const startPos = classNameMatchResult.index + classNameMatchResult[0].length;
|
||||||
|
const classNameValue = extractComplexValue(value, startPos);
|
||||||
|
if (classNameValue) {
|
||||||
|
texts.push(classNameValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
texts.push(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return texts;
|
return texts;
|
||||||
@ -349,3 +522,66 @@ export function interfaceToType(code: string) {
|
|||||||
return `type ${name}${extendsStr} = {${content}}`;
|
return `type ${name}${extendsStr} = {${content}}`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function test() {
|
||||||
|
const html = `
|
||||||
|
<template>
|
||||||
|
<text :class="parseClass({'!bg-red-50': hoverable})"></text>
|
||||||
|
<text :class="a ? 'text-red-100' : 'text-red-200'"></text>
|
||||||
|
<text :class="\`text-red-300 \${true ? 'text-red-310' : 'text-red-320'}\`"></text>
|
||||||
|
<text class="text-red-330"></text>
|
||||||
|
<text :class="{
|
||||||
|
'text-red-400': a,
|
||||||
|
'text-red-500': b,
|
||||||
|
}"></text>
|
||||||
|
<text :class="[
|
||||||
|
'text-red-600',
|
||||||
|
'text-red-700',
|
||||||
|
{
|
||||||
|
'text-red-800': c,
|
||||||
|
}
|
||||||
|
]"></text>
|
||||||
|
<text :class="\`text-red-900\` text-red-1000"></text>
|
||||||
|
<text :pt="{
|
||||||
|
className: '!text-green-50'
|
||||||
|
}"></text>
|
||||||
|
<text :pt="{
|
||||||
|
className: parseClass({
|
||||||
|
'!text-green-100': hoverable,
|
||||||
|
}),
|
||||||
|
item: {
|
||||||
|
className: 'text-green-200'
|
||||||
|
}
|
||||||
|
}"></text>
|
||||||
|
<text :pt="{
|
||||||
|
className: \`text-green-300 \${true ? 'text-red-310' : 'text-red-320'}\`
|
||||||
|
}"></text>
|
||||||
|
<text hover-class="text-green-400"></text>
|
||||||
|
<text :hover-class="\`text-green-400\`"></text>
|
||||||
|
<text :hover-class="parseClass({'!text-green-450': hoverable})"></text>
|
||||||
|
<text :hover-class="a ? 'text-green-500' : 'text-green-600'"></text>
|
||||||
|
<text :hover-class="\`text-green-700 \${true ? 'text-red-310' : 'text-red-320'}\`"></text>
|
||||||
|
</template>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const nodes = getNodes(html);
|
||||||
|
|
||||||
|
console.log("所有节点:");
|
||||||
|
nodes.forEach((node, index) => {
|
||||||
|
console.log(`第${index + 1}个节点:`, node);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("\n详细分析:");
|
||||||
|
nodes.forEach((node, index) => {
|
||||||
|
const classContents = getClassContent(node);
|
||||||
|
const classNames = getClassNames(node);
|
||||||
|
console.log(`第${index + 1}个节点:`);
|
||||||
|
console.log("classContents", classContents);
|
||||||
|
console.log("classNames", classNames);
|
||||||
|
console.log("---");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// test();
|
||||||
|
|
||||||
|
// npx ./src/uniapp-x/utils.ts
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user