@lcap/builder
Version:
lcap builder utils
707 lines (706 loc) • 40.3 kB
JavaScript
;
/* eslint-disable no-use-before-define */
/* eslint-disable no-prototype-builtins */
/* eslint-disable no-underscore-dangle */
/* eslint-disable no-cond-assign */
/* eslint-disable no-multi-assign */
/* eslint-disable prefer-destructuring */
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-param-reassign */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = buildCSSInfo;
exports.batchDepCSSInfo = batchDepCSSInfo;
exports.batchDepBasicCSSInfo = batchDepBasicCSSInfo;
exports.extendsCSSInfo = extendsCSSInfo;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const postcss = __importStar(require("postcss"));
const postcss_values_parser_1 = require("postcss-values-parser");
const lodash_1 = require("lodash");
const lcap_1 = require("../utils/lcap");
function sortMap(map) {
return Object.fromEntries(Object.entries(map).sort(([a], [b]) => a.localeCompare(b)));
}
function getChildrenValue(val) {
return val.nodes.map((node) => node.toString());
}
function startsWithPrefix(hideSelectorPrefixes, selectorKey) {
return hideSelectorPrefixes.some((selectorPrefix) => selectorKey.startsWith(selectorPrefix) || selectorKey.startsWith(`[class*=${selectorPrefix}`));
}
function parseCSSInfo(cssContent, cssRulesDesc, componentNameMap, options) {
var _a, _b, _c, _d, _e;
const componentNames = Object.keys(componentNameMap);
const allCSSDescMap = Object.values(cssRulesDesc).reduce((acc, item) => Object.assign(acc, item), {});
const root = postcss.parse(cssContent);
const hasPesudoClassRE = /:(hover|active|focus)/;
const hasPesudoStateRE = /(:|\._)(hover|active|focus)/;
const isNonStandardRE = /-(moz|webkit|ms|o)-/;
const hasPesudoElementRE = /::|:(before|after|selection)/;
const hashClassRE = /\.([a-zA-Z0-9][a-zA-Z0-9_-]*?)___[a-zA-Z0-9-]{6,}/;
const warningIgnoreRE = new RegExp((((_a = options.reportCSSInfo) === null || _a === void 0 ? void 0 : _a.warningIgnore) || [/%/]).map((re) => re.source).join('|'));
function getPrefixMap(componentName, parentName) {
var _a, _b, _c, _d;
const firstPrefix = (0, lodash_1.kebabCase)(componentName);
const prefixMap = { [firstPrefix]: true };
const proRE = /^el-(.+)-pro$/;
if (proRE.test(firstPrefix))
prefixMap[firstPrefix.replace(proRE, 'el-p-$1')] = true;
const vanRE = /^van-/;
if (vanRE.test(firstPrefix))
prefixMap[firstPrefix.replace(vanRE, '')] = true;
if (parentName) {
const parentPrefix = (0, lodash_1.kebabCase)(parentName);
if (firstPrefix.startsWith(parentPrefix)) {
const comboPrefix = `${parentPrefix}_${firstPrefix.slice(parentPrefix.length + 1)}`; // u-form_item
prefixMap[comboPrefix] = true;
}
if (firstPrefix.replace(/-multi$/, '').startsWith(parentPrefix.replace(/-multi$/, ''))) {
const comboPrefix = `${parentPrefix}_${firstPrefix.replace(/-multi$/, '').slice(parentPrefix.replace(/-multi$/, '').length + 1)}`; // u-navar-multi_item
prefixMap[comboPrefix] = true;
}
else {
const start = (_a = firstPrefix.match(/^(.+?)-/)) === null || _a === void 0 ? void 0 : _a[1];
if (start) {
const comboPrefix = `${parentPrefix}_${firstPrefix.slice(start.length + 1)}`; // u-radios_radio
prefixMap[comboPrefix] = true;
}
}
}
const selectorPrefixMap = (_d = (_c = (_b = options.reportCSSInfo) === null || _b === void 0 ? void 0 : _b.extraComponentMap) === null || _c === void 0 ? void 0 : _c[componentName]) === null || _d === void 0 ? void 0 : _d.selectorPrefixMap;
selectorPrefixMap && Object.assign(prefixMap, selectorPrefixMap);
return prefixMap;
}
// eslint-disable-next-line no-shadow
const inferSelectorComponentName = ((_b = options.reportCSSInfo) === null || _b === void 0 ? void 0 : _b.inferSelectorComponentName) || ((selector, componentNameMap) => {
return Object.keys(componentNameMap).find((componentName) => {
const prefixMap = getPrefixMap(componentName, componentNameMap[componentName]);
const re = new RegExp(Object.keys(prefixMap).map((prefix) => `^\\.${prefix}(__|--|$|[ +>~\\.:\\[])|^\\[class\\*=${prefix}_`).join('|'));
return re.test(selector);
});
});
function getMainSubSelector(subSelector) {
const cap = subSelector.slice(1).match(/[[.:]/);
let result = cap ? subSelector.slice(0, (cap.index
|| subSelector.length - 1 // 支持 *:last-child 等选择器
) + 1) : subSelector;
if (hasPesudoStateRE.test(result))
result = result.replace(new RegExp(hasPesudoStateRE, 'g'), '');
return result;
}
const isSelectorStartRoot = ((_c = options.reportCSSInfo) === null || _c === void 0 ? void 0 : _c.isSelectorStartRoot) || ((selector, componentName, parentName) => {
const prefixMap = getPrefixMap(componentName, componentNameMap[componentName]);
const notRootPrefixes = [];
const rootPrefixes = [];
Object.entries(prefixMap).forEach(([prefix, isRoot]) => {
(isRoot ? rootPrefixes : notRootPrefixes).push(prefix);
});
let re = new RegExp(notRootPrefixes.map((prefix) => `^\\.${prefix}(--|$|[ +>~\\.:])|^\\[class\\*=${prefix}___`).join('|'));
if (notRootPrefixes.length && re.test(selector))
return false;
re = new RegExp(rootPrefixes.map((prefix) => `^\\.${prefix}(--|$|[ +>~\\.:])|^\\[class\\*=${prefix}___`).join('|'));
return !!rootPrefixes.length && re.test(selector);
});
const componentCSSInfoMap = {};
/** 目前只是用来减少 WARN 日志 */
const allMainSelectorMap = !((_d = options.reportCSSInfo) === null || _d === void 0 ? void 0 : _d.extraComponentMap) ? {} : Object.keys((_e = options.reportCSSInfo) === null || _e === void 0 ? void 0 : _e.extraComponentMap).reduce((obj, componentName) => {
var _a, _b, _c;
const mainSelectorMap = (_c = (_b = (_a = options.reportCSSInfo) === null || _a === void 0 ? void 0 : _a.extraComponentMap) === null || _b === void 0 ? void 0 : _b[componentName]) === null || _c === void 0 ? void 0 : _c.mainSelectorMap;
return Object.assign(Object.assign({}, obj), mainSelectorMap);
}, {});
root.nodes.forEach((node) => {
var _a, _b;
if (node.type === 'rule') {
if (/\([^(),]+?(,[^(),]+?)+\)/.test(node.selector))
return; // 过滤掉含有逗号()的选择器
let selectors = node.selector
.replace(/\s+/g, ' ') // 抹平换行符
.replace(/\s*([>+~,])\s*/g, '$1') // 统一去除空格
.split(/,/g)
.flatMap((sel) => (hasPesudoClassRE.test(sel) && !hasPesudoElementRE.test(sel) ? [sel, sel.replace(new RegExp(hasPesudoClassRE, 'g'), '._$1')] : [sel])); // 增加模拟伪类
let selector = selectors.join(',');
if (/:(before|after)$|vusion|s-empty|_fake|_empty|[dD]esigner|cw-style/.test(selector) || isNonStandardRE.test(selector))
return;
node.selector = selector; // 更新 CSS 代码中的选择器
selectors = selectors
// .filter((sel) => !/|ms|o)-|^_/.test(sel)) // 过滤掉浏览器前缀和 _ 开头的选择器
.map((sel) => sel.replace(new RegExp(hashClassRE, 'g'), '[class*=$1___]')); // hash 类名改为 [class*=] 属性选择器
selector = selectors.join(',');
if (!selector)
return;
const componentName = inferSelectorComponentName === null || inferSelectorComponentName === void 0 ? void 0 : inferSelectorComponentName(selector, componentNameMap);
if (!componentName) {
if ((_a = options.reportCSSInfo) === null || _a === void 0 ? void 0 : _a.verbose) {
const tempComponentName = componentNames.find((name) => {
name = (0, lodash_1.kebabCase)(name);
return new RegExp(`^\\.${name}(_|-)|^\\[class\\*=${name}(_|-)`).test(selector) && !/:(before|after)$/.test(selector);
});
if (tempComponentName && allMainSelectorMap[selector] === undefined && !warningIgnoreRE.test(selector))
console.warn(`[WARN] 未找到可能的组件选择器: ${selector},按照_|-分割推测可能的组件:${tempComponentName}`);
const tempComponentName2 = componentNames.find((name) => {
name = (0, lodash_1.kebabCase)(name);
return new RegExp(`^\\.${name}|^\\[class\\*=${name}`).test(selector) && !/:(before|after)$/.test(selector);
});
if (!tempComponentName && tempComponentName2 && allMainSelectorMap[selector] === undefined
&& !warningIgnoreRE.test(selector))
console.warn(`[WARN] 未找到可能的组件选择器: ${selector},根据前缀连续推测可能的组件:${tempComponentName2}`);
}
return;
}
const componentCSSInfo = componentCSSInfoMap[componentName] = componentCSSInfoMap[componentName] || {
cssRules: [],
cssRuleMap: new Map(),
mainSelectorMap: new Map(),
};
selectors.forEach((sel) => {
let mainSelector = '';
const re = /[ +>~]/g;
let cap;
let lastIndex = 0;
while ((cap = re.exec(sel))) {
mainSelector += getMainSubSelector(sel.slice(lastIndex, cap.index)) + cap[0];
lastIndex = cap.index + 1;
}
mainSelector += getMainSubSelector(sel.slice(lastIndex));
if (mainSelector.endsWith(' *') || mainSelector.endsWith('>*')
|| mainSelector.endsWith('(') // 临时过滤 :not( 错误的选择器
)
return;
componentCSSInfo.mainSelectorMap.set(mainSelector, isSelectorStartRoot(mainSelector, componentName, componentNameMap[componentName]));
});
const parsedStyle = {};
node.nodes.forEach((decl) => {
if (decl.type === 'comment')
return;
if (decl.type !== 'decl')
return;
if (decl.prop.startsWith('--'))
return;
const value = decl.value.replace(/var\(.+?\)/g, (m) => m.replace(/\s+/g, ''));
let match;
const patchImportant = (obj) => (Object.assign(Object.assign({}, obj), { important: decl.important }));
if (decl.prop === 'background') {
parsedStyle.backgroundColor = patchImportant({ defaultValue: decl.value });
}
else if (decl.prop === 'border') {
if (value === undefined || value === null)
return;
const parseVal = (0, postcss_values_parser_1.parse)(value);
const arr = getChildrenValue(parseVal);
// const arr = value.split(/\s+/);
if (arr.length < 3)
return;
const [borderWidth, borderStyle, borderColor] = arr;
parsedStyle.borderLeftWidth = patchImportant({ defaultValue: borderWidth });
parsedStyle.borderLeftStyle = patchImportant({ defaultValue: borderStyle });
parsedStyle.borderLeftColor = patchImportant({ defaultValue: borderColor });
parsedStyle.borderRightWidth = patchImportant({ defaultValue: borderWidth });
parsedStyle.borderRightStyle = patchImportant({ defaultValue: borderStyle });
parsedStyle.borderRightColor = patchImportant({ defaultValue: borderColor });
parsedStyle.borderTopWidth = patchImportant({ defaultValue: borderWidth });
parsedStyle.borderTopStyle = patchImportant({ defaultValue: borderStyle });
parsedStyle.borderTopColor = patchImportant({ defaultValue: borderColor });
parsedStyle.borderBottomWidth = patchImportant({ defaultValue: borderWidth });
parsedStyle.borderBottomStyle = patchImportant({ defaultValue: borderStyle });
parsedStyle.borderBottomColor = patchImportant({ defaultValue: borderColor });
}
else if ((match = decl.prop.match(/^border-(left|right|top|bottom)$/))) {
const borderProp = match[1];
if (value === undefined || value === null)
return;
const parseVal = (0, postcss_values_parser_1.parse)(value);
const arr = getChildrenValue(parseVal);
// const arr = value.split(/\s+/);
if (arr.length < 3)
return;
const [borderWidth, borderStyle, borderColor] = arr;
parsedStyle[`border${(0, lodash_1.capitalize)(borderProp)}Width`] = patchImportant({ defaultValue: borderWidth });
parsedStyle[`border${(0, lodash_1.capitalize)(borderProp)}Style`] = patchImportant({ defaultValue: borderStyle });
parsedStyle[`border${(0, lodash_1.capitalize)(borderProp)}Color`] = patchImportant({ defaultValue: borderColor });
}
else if (decl.prop === 'margin') {
if (value === undefined || value === null)
return;
const parseVal = (0, postcss_values_parser_1.parse)(value);
const arr = getChildrenValue(parseVal);
// const arr = value.split(/\s+/);
if (arr.length === 1) {
parsedStyle.marginTop = patchImportant({ defaultValue: arr[0] });
parsedStyle.marginRight = patchImportant({ defaultValue: arr[0] });
parsedStyle.marginBottom = patchImportant({ defaultValue: arr[0] });
parsedStyle.marginLeft = patchImportant({ defaultValue: arr[0] });
}
else if (arr.length === 2) {
parsedStyle.marginTop = patchImportant({ defaultValue: arr[0] });
parsedStyle.marginRight = patchImportant({ defaultValue: arr[1] });
parsedStyle.marginBottom = patchImportant({ defaultValue: arr[0] });
parsedStyle.marginLeft = patchImportant({ defaultValue: arr[1] });
}
else if (arr.length === 3) {
parsedStyle.marginTop = patchImportant({ defaultValue: arr[0] });
parsedStyle.marginRight = patchImportant({ defaultValue: arr[1] });
parsedStyle.marginBottom = patchImportant({ defaultValue: arr[2] });
parsedStyle.marginLeft = patchImportant({ defaultValue: arr[1] });
}
else if (arr.length === 4) {
parsedStyle.marginTop = patchImportant({ defaultValue: arr[0] });
parsedStyle.marginRight = patchImportant({ defaultValue: arr[1] });
parsedStyle.marginBottom = patchImportant({ defaultValue: arr[2] });
parsedStyle.marginLeft = patchImportant({ defaultValue: arr[3] });
}
}
else if (decl.prop === 'padding') {
if (value === undefined || value === null)
return;
const parseVal = (0, postcss_values_parser_1.parse)(value);
const arr = getChildrenValue(parseVal);
// const arr = value.split(/\s+/);
if (arr.length === 1) {
parsedStyle.paddingTop = patchImportant({ defaultValue: arr[0] });
parsedStyle.paddingRight = patchImportant({ defaultValue: arr[0] });
parsedStyle.paddingBottom = patchImportant({ defaultValue: arr[0] });
parsedStyle.paddingLeft = patchImportant({ defaultValue: arr[0] });
}
else if (arr.length === 2) {
parsedStyle.paddingTop = patchImportant({ defaultValue: arr[0] });
parsedStyle.paddingRight = patchImportant({ defaultValue: arr[1] });
parsedStyle.paddingBottom = patchImportant({ defaultValue: arr[0] });
parsedStyle.paddingLeft = patchImportant({ defaultValue: arr[1] });
}
else if (arr.length === 3) {
parsedStyle.paddingTop = patchImportant({ defaultValue: arr[0] });
parsedStyle.paddingRight = patchImportant({ defaultValue: arr[1] });
parsedStyle.paddingBottom = patchImportant({ defaultValue: arr[2] });
parsedStyle.paddingLeft = patchImportant({ defaultValue: arr[1] });
}
else if (arr.length === 4) {
parsedStyle.paddingTop = patchImportant({ defaultValue: arr[0] });
parsedStyle.paddingRight = patchImportant({ defaultValue: arr[1] });
parsedStyle.paddingBottom = patchImportant({ defaultValue: arr[2] });
parsedStyle.paddingLeft = patchImportant({ defaultValue: arr[3] });
}
}
else if (decl.prop === 'border-radius') {
if (value === undefined || value === null)
return;
const parseVal = (0, postcss_values_parser_1.parse)(value);
const arr = getChildrenValue(parseVal);
// const arr = value.split(/\s+/);
if (arr.length === 1) {
parsedStyle.borderTopLeftRadius = patchImportant({ defaultValue: arr[0] });
parsedStyle.borderTopRightRadius = patchImportant({ defaultValue: arr[0] });
parsedStyle.borderBottomRightRadius = patchImportant({ defaultValue: arr[0] });
parsedStyle.borderBottomLeftRadius = patchImportant({ defaultValue: arr[0] });
}
else if (arr.length === 2) {
parsedStyle.borderTopLeftRadius = patchImportant({ defaultValue: arr[0] });
parsedStyle.borderTopRightRadius = patchImportant({ defaultValue: arr[1] });
parsedStyle.borderBottomRightRadius = patchImportant({ defaultValue: arr[0] });
parsedStyle.borderBottomLeftRadius = patchImportant({ defaultValue: arr[1] });
}
else if (arr.length === 3) {
parsedStyle.borderTopLeftRadius = patchImportant({ defaultValue: arr[0] });
parsedStyle.borderTopRightRadius = patchImportant({ defaultValue: arr[1] });
parsedStyle.borderBottomRightRadius = patchImportant({ defaultValue: arr[2] });
parsedStyle.borderBottomLeftRadius = patchImportant({ defaultValue: arr[1] });
}
else if (arr.length === 4) {
parsedStyle.borderTopLeftRadius = patchImportant({ defaultValue: arr[0] });
parsedStyle.borderTopRightRadius = patchImportant({ defaultValue: arr[1] });
parsedStyle.borderBottomRightRadius = patchImportant({ defaultValue: arr[2] });
parsedStyle.borderBottomLeftRadius = patchImportant({ defaultValue: arr[3] });
}
}
else {
parsedStyle[(0, lodash_1.camelCase)(decl.prop)] = patchImportant({ defaultValue: decl.value });
}
});
const cssRule = {
selector,
isStartRoot: isSelectorStartRoot(selector, componentName, componentNameMap[componentName]),
description: '', // cssRuleSelectors[selector] || lastRuleDesc || '',
// code: node.toString().replace(/^[\s\S]*?\{/, '{'),
parsedStyle,
};
if (componentCSSInfo.cssRuleMap.has(selector)) {
const oldParsedStyle = (_b = componentCSSInfo.cssRuleMap.get(selector)) === null || _b === void 0 ? void 0 : _b.parsedStyle;
Object.keys(parsedStyle).forEach((prop) => {
var _a;
if (((_a = oldParsedStyle[prop]) === null || _a === void 0 ? void 0 : _a.important) && !parsedStyle[prop].important) {
parsedStyle[prop] = oldParsedStyle[prop];
}
});
Object.assign(oldParsedStyle, parsedStyle);
}
else {
componentCSSInfo.cssRules.push(cssRule);
componentCSSInfo.cssRuleMap.set(selector, cssRule);
}
}
});
componentNames.forEach((componentName) => {
var _a, _b, _c;
let componentCSSInfo = componentCSSInfoMap[componentName];
const optMainSelectorMap = (_c = (_b = (_a = options.reportCSSInfo) === null || _a === void 0 ? void 0 : _a.extraComponentMap) === null || _b === void 0 ? void 0 : _b[componentName]) === null || _c === void 0 ? void 0 : _c.mainSelectorMap;
if (optMainSelectorMap) {
if (!componentCSSInfo) {
componentCSSInfo = componentCSSInfoMap[componentName] = {
cssRules: [],
cssRuleMap: new Map(),
mainSelectorMap: new Map(),
};
}
Object.entries(optMainSelectorMap).forEach(([sel, value]) => {
componentCSSInfo.mainSelectorMap.set(sel, value);
});
}
if (!componentCSSInfo)
return;
// eslint-disable-next-line no-restricted-syntax
for (const mainSelector of componentCSSInfo.mainSelectorMap.keys()) {
if (!componentCSSInfo.cssRuleMap.has(mainSelector)) {
const cssRule = {
selector: mainSelector,
isStartRoot: componentCSSInfo.mainSelectorMap.get(mainSelector) || false,
description: '',
parsedStyle: {},
};
componentCSSInfo.cssRules.push(cssRule);
componentCSSInfo.cssRuleMap.set(mainSelector, cssRule);
}
const StateMap = {
hover: '鼠标移入',
active: '鼠标按下',
focus: '获得焦点',
// visited: '已访问',
};
Object.keys(StateMap).forEach((state) => {
const selector = `${mainSelector}:${state},${mainSelector}._${state}`;
// const mainSelectorCSSRule = componentCSSInfo.cssRuleMap.get(mainSelector);
// const mainSelectorDescription = cssRulesDesc[componentName]?.[mainSelector] || mainSelectorCSSRule?.description;
if (!componentCSSInfo.cssRuleMap.has(selector)) {
const cssRule = {
selector,
isStartRoot: componentCSSInfo.mainSelectorMap.get(mainSelector) || false,
description: '', // mainSelectorDescription ? `${mainSelectorDescription}:${StateMap[state]}` : '',
parsedStyle: {},
};
componentCSSInfo.cssRules.push(cssRule);
componentCSSInfo.cssRuleMap.set(selector, cssRule);
}
});
}
let cssDescMap = cssRulesDesc[componentName];
if (!cssDescMap)
cssDescMap = cssRulesDesc[componentName] = {};
componentCSSInfo.cssRules.forEach((rule) => {
const matchedMainSelector = Array.from(componentCSSInfo.mainSelectorMap.keys()).find((mainSelector) => rule.selector.startsWith(mainSelector.split(/[ +>~]/g)[0]));
!matchedMainSelector && console.warn(`selector: ${rule.selector} 匹配 mainSelector: ${matchedMainSelector}`);
rule.description = cssDescMap[rule.selector] = allCSSDescMap[rule.selector] || '';
});
// eslint-disable-next-line no-nested-ternary
// componentCSSInfo.cssRules 不应该排序
Object.keys(cssDescMap).forEach((selector) => {
if (!componentCSSInfo.cssRuleMap.has(selector))
delete cssDescMap[selector];
});
cssRulesDesc[componentName] = cssDescMap;
});
return { componentCSSInfoMap, cssRulesDesc, cssContent: root.toResult().css };
}
function postprocessCSSInfo(componentCSSInfoMap, cssRulesDesc, componentNameMap, options) {
var _a, _b;
const componentNames = Object.keys(componentNameMap);
if ((_a = options.reportCSSInfo) === null || _a === void 0 ? void 0 : _a.extraComponentMap) {
/**
* 根据依赖组件补充信息
* 从上到下的顺序
*/
Object.entries(options.reportCSSInfo.extraComponentMap).forEach(([componentName, extraComponentInfo]) => {
var _a;
const _depComponentMap = {};
Object.entries(extraComponentInfo.depComponentMap || {}).forEach(([depName, depItem]) => {
if (typeof depItem === 'boolean') {
_depComponentMap[depName] = {
componentName: depName,
stillRoot: depItem,
};
}
else if ('stillRoot' in depItem) {
if ('cssInfo' in depItem && !depItem.cssInfo)
throw new Error(`组件 ${componentName} 的依赖组件 ${depName} 配置错误`);
_depComponentMap[depName] = depItem;
}
else {
if (!depItem)
throw new Error(`组件 ${componentName} 的依赖组件 ${depName} 配置错误`);
_depComponentMap[depName] = {
componentName: depName,
cssInfo: depItem,
stillRoot: false,
};
}
});
(_a = extraComponentInfo.depComponents) === null || _a === void 0 ? void 0 : _a.forEach((depItem) => {
let depName = '';
if (typeof depItem === 'string') {
depName = depItem;
if (_depComponentMap[depName])
return;
_depComponentMap[depName] = {
componentName: depName,
stillRoot: false,
};
}
else {
depName = depItem.componentName;
if (_depComponentMap[depName])
return;
if ('cssInfo' in depItem && !depItem.cssInfo)
throw new Error(`组件 ${componentName} 的依赖组件 ${depName} 配置错误`);
_depComponentMap[depName] = depItem;
}
});
if ('extends' in extraComponentInfo && !extraComponentInfo.extends)
throw new Error(`组件 ${componentName} 的 extends 配置错误`);
if (extraComponentInfo.extends) {
const baseName = `_Base${componentName}`;
_depComponentMap[baseName] = {
componentName: baseName,
cssInfo: extraComponentInfo.extends,
stillRoot: true,
};
}
Object.keys(_depComponentMap).forEach((depName) => {
var _a;
const depItem = _depComponentMap[depName];
const stillRoot = depItem.stillRoot;
((_a = options.reportCSSInfo) === null || _a === void 0 ? void 0 : _a.verbose) && console.info(`[INFO] 组件 ${componentName} 依赖 ${depName},且${stillRoot ? '仍为根节点' : '不为根节点'}`);
const _depCSSInfo = componentCSSInfoMap[depName];
if (!_depCSSInfo && !depItem.cssInfo)
throw new Error(`组件 ${componentName} 找不到依赖组件 ${depName} 的配置`);
[_depCSSInfo, depItem.cssInfo && convertFinalCSSInfoToInner(depItem.cssInfo)].forEach((depCSSInfo) => {
if (!depCSSInfo)
return;
let currCSSInfo = componentCSSInfoMap[componentName];
if (!currCSSInfo) {
currCSSInfo = componentCSSInfoMap[componentName] = {
cssRules: [],
cssRuleMap: new Map(),
mainSelectorMap: new Map(),
};
}
// 补充 cssRules 和 cssRuleMap
depCSSInfo.cssRules.forEach((rule) => {
const newRule = Object.assign(Object.assign({}, rule), { isStartRoot: stillRoot && rule.isStartRoot });
// 采取不覆盖策略,保证自定义配置的优先级
if (!currCSSInfo.cssRuleMap.has(rule.selector)) {
currCSSInfo.cssRules.push(newRule);
currCSSInfo.cssRuleMap.set(rule.selector, newRule);
}
// else { // 去重
// const index = currCSSInfo.cssRules.findIndex((item) => item.selector === rule.selector);
// currCSSInfo.cssRules[index] = newRule;
// currCSSInfo.cssRuleMap.set(rule.selector, newRule);
// }
});
// 补充 mainSelectorMap
depCSSInfo.mainSelectorMap.forEach((value, key) => {
// 采取不覆盖策略,保证自定义配置的优先级
if (!currCSSInfo.mainSelectorMap.has(key)) {
currCSSInfo.mainSelectorMap.set(key, stillRoot ? value : false);
}
});
});
// 补充 cssRules 的中文描述
[cssRulesDesc[depName], depItem.cssInfo && convertFinalCSSInfoToDesc(depItem.cssInfo)].forEach((depCSSRulesDesc) => {
if (!depCSSRulesDesc)
return;
Object.entries(depCSSRulesDesc).forEach(([selectorKey, desc]) => {
var _a;
let descObj = cssRulesDesc[componentName];
if (!descObj)
descObj = cssRulesDesc[componentName] = {};
if (!descObj[selectorKey]) {
descObj[selectorKey] = desc; // 采取不覆盖策略,保证自定义配置的优先级
const cssRule = (_a = componentCSSInfoMap[componentName]) === null || _a === void 0 ? void 0 : _a.cssRuleMap.get(selectorKey);
if (cssRule)
cssRule.description = desc;
}
});
});
});
});
/**
* 过滤掉需要隐藏的选择器
*/
Object.entries(options.reportCSSInfo.extraComponentMap).forEach(([componentName, extraComponentInfo]) => {
const compCssDesc = cssRulesDesc[componentName];
const compCssInfo = componentCSSInfoMap[componentName];
if (!compCssDesc || !compCssInfo)
return;
const hideSelectorPrefixes = extraComponentInfo.hideSelectorPrefixes;
const hideSelectorRegexps = extraComponentInfo.hideSelectorRegexps;
const shouldHideSelector = (selectorKey) => {
if (hideSelectorPrefixes && startsWithPrefix(hideSelectorPrefixes, selectorKey))
return true;
if (hideSelectorRegexps && hideSelectorRegexps.some((reg) => reg.test(selectorKey)))
return true;
return false;
};
Object.keys(compCssDesc).forEach((selectorKey) => {
if (shouldHideSelector(selectorKey)) {
delete compCssDesc[selectorKey];
}
});
Array.from(compCssInfo.mainSelectorMap.keys()).forEach((selectorKey) => {
if (shouldHideSelector(selectorKey)) {
compCssInfo.mainSelectorMap.delete(selectorKey);
}
});
compCssInfo.cssRules = compCssInfo.cssRules.filter((rule) => {
return !shouldHideSelector(rule.selector);
});
});
}
/**
* 如果组件已经不存在了,就在描述中也删除掉
*/
Object.keys(cssRulesDesc).forEach((componentName) => {
if (!componentCSSInfoMap[componentName])
delete cssRulesDesc[componentName];
else
cssRulesDesc[componentName] = sortMap(cssRulesDesc[componentName]);
});
if ((_b = options.reportCSSInfo) === null || _b === void 0 ? void 0 : _b.verbose) {
componentNames.forEach((componentName) => {
if (!componentCSSInfoMap[componentName])
console.warn(`[WARN] 组件 ${componentName} 上未匹配到任何选择器`);
});
}
}
function convertCSSInfoMapToFinal(cssInfoMap) {
const final = {};
Object.entries(cssInfoMap).forEach(([componentName, cssInfo]) => {
final[componentName] = {
cssRules: Array.from(cssInfo.cssRules),
mainSelectorMap: Object.fromEntries(cssInfo.mainSelectorMap),
};
});
return final;
}
function convertFinalCSSInfoToInner(cssInfo) {
return {
cssRules: cssInfo.cssRules,
mainSelectorMap: new Map(Object.entries(cssInfo.mainSelectorMap)),
};
}
function convertFinalCSSInfoToDesc(cssInfo) {
const result = {};
cssInfo.cssRules.forEach((rule) => {
result[rule.selector] = rule.description;
});
return result;
}
function buildCSSInfo(options) {
return __awaiter(this, void 0, void 0, function* () {
if (!options.reportCSSInfo || !options.reportCSSInfo.enabled) {
return;
}
const components = yield (0, lcap_1.getComponentMetaInfos)(options.rootPath, true);
const componentNameMap = {}; // { componentName: parentName }
components.forEach((component) => {
var _a;
// 这里用了个技巧,先匹配子组件
(_a = component.children) === null || _a === void 0 ? void 0 : _a.forEach((child) => {
componentNameMap[child.name] = component.name;
});
componentNameMap[component.name] = undefined;
});
const cssContent = fs_extra_1.default.readFileSync(path_1.default.resolve(options.rootPath, options.destDir, 'index.css'), 'utf-8');
const cssRulesDescPath = path_1.default.resolve(options.rootPath, 'index.css-info-desc.json');
const cssRulesDesc = fs_extra_1.default.existsSync(cssRulesDescPath) ? fs_extra_1.default.readJSONSync(cssRulesDescPath) : {};
const result = parseCSSInfo(cssContent, cssRulesDesc, componentNameMap, options);
postprocessCSSInfo(result.componentCSSInfoMap, result.cssRulesDesc, componentNameMap, options);
fs_extra_1.default.writeJSONSync(path_1.default.resolve(options.rootPath, options.destDir, 'index.css-info-map.json'), convertCSSInfoMapToFinal(result.componentCSSInfoMap), { spaces: 2 });
fs_extra_1.default.writeJSONSync(path_1.default.resolve(options.rootPath, 'index.css-info-desc.json'), sortMap(result.cssRulesDesc), { spaces: 2 });
fs_extra_1.default.writeFileSync(path_1.default.resolve(options.rootPath, options.destDir, 'index.css'), result.cssContent);
});
}
function batchDepCSSInfo(originComponentNames, renameComponent, stillRoot = true) {
const result = {};
originComponentNames.forEach((componentName) => {
result[renameComponent(componentName)] = {
depComponentMap: {
[componentName]: stillRoot,
},
};
});
return result;
}
function batchDepBasicCSSInfo(basicCSSInfo, originComponentNames, renameComponent, stillRoot = true) {
const result = {};
originComponentNames.forEach((componentName) => {
result[renameComponent(componentName)] = {
depComponentMap: {
[componentName]: {
componentName,
stillRoot,
cssInfo: basicCSSInfo[componentName],
},
},
};
});
return result;
}
function extendsCSSInfo(cssInfo, renameSelector) {
const result = {
cssRules: cssInfo.cssRules.map((cssRule) => (Object.assign(Object.assign({}, cssRule), { selector: renameSelector ? renameSelector(cssRule.selector) : cssRule.selector }))),
mainSelectorMap: Object.entries(cssInfo.mainSelectorMap).reduce((prev, [selector, isStartRoot]) => (Object.assign(Object.assign({}, prev), { [renameSelector ? renameSelector(selector) : selector]: isStartRoot })), {}),
};
return result;
}