@lcap/builder
Version:
lcap builder utils
322 lines (321 loc) • 13.9 kB
JavaScript
;
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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__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.forkComponent = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const fast_glob_1 = __importDefault(require("fast-glob"));
const vite_1 = require("vite");
const parser = __importStar(require("@babel/parser"));
const traverse_1 = __importDefault(require("@babel/traverse"));
const generator_1 = __importDefault(require("@babel/generator"));
const constants_1 = require("./constants");
const fs_1 = require("../utils/fs");
const logger_1 = __importDefault(require("../utils/logger"));
const suffixes = ['.js', '.jsx', '.ts', '.tsx'];
function isExist(filePath) {
return ['', ...suffixes].some((suffix) => {
const fullPath = filePath + suffix;
return fs_extra_1.default.existsSync(fullPath) && !fs_extra_1.default.lstatSync(fullPath).isDirectory();
});
}
function changeNodeSource(node, filePath, modules) {
if (!node.source) {
return;
}
let sourcePath = node.source.value;
if (sourcePath.startsWith('./') && sourcePath.lastIndexOf('/') === 1) {
const resolvePath = path_1.default.resolve(filePath.substring(0, filePath.lastIndexOf('/')), sourcePath);
if (isExist(resolvePath)) {
return;
}
}
if (sourcePath.startsWith('@components')) {
sourcePath = sourcePath.replace('@components', '@lcap-ui/src/components');
}
else if (sourcePath.startsWith('cloud-ui.vusion/src')) {
sourcePath = sourcePath.replace('cloud-ui.vusion/src', '@lcap-ui/cloudui');
}
else if (sourcePath.startsWith('@/')) {
const srcVusion = fs_extra_1.default.existsSync('.lcap/lcap-ui/src-vusion');
sourcePath = sourcePath.replace('@', srcVusion ? '@lcap-ui/src-vusion' : '@lcap-ui/src');
}
else if (sourcePath.startsWith('../') || sourcePath.startsWith('./')) {
const lastFolderPath = filePath.substring(0, filePath.lastIndexOf('/'));
sourcePath = (0, vite_1.normalizePath)(path_1.default.resolve(lastFolderPath, sourcePath).replace(path_1.default.resolve(process.cwd(), constants_1.LCAP_UI_PACKAGE_PATH), '@lcap-ui'));
}
else if (modules.indexOf(sourcePath) === -1) {
modules.push(sourcePath);
}
node.source.value = sourcePath;
}
function transformScriptAst(ast, filePath, modules) {
let isJSX = false;
(0, traverse_1.default)(ast, {
JSXElement(p) {
isJSX = true;
p.skip();
},
ExportNamedDeclaration(p) {
changeNodeSource(p.node, filePath, modules);
},
ExportAllDeclaration(p) {
changeNodeSource(p.node, filePath, modules);
},
ImportDeclaration(p) {
changeNodeSource(p.node, filePath, modules);
},
});
return {
isJSX,
};
}
function transformCssCode(code, filePath) {
const codes = code.split('\n').map((str) => {
if (!str || !str.trim().startsWith('@import') || !str.trim().endsWith(';')) {
return str;
}
let startIndex = str.indexOf("'") + 1;
let endIndex = str.lastIndexOf("'");
if (startIndex === 0) {
startIndex = str.indexOf('"') + 1;
endIndex = str.lastIndexOf('"');
}
if (startIndex === 0 || startIndex === endIndex) {
return str;
}
const prefixStr = str.substring(0, startIndex);
const suffixStr = str.substring(endIndex);
let sourcePath = str.substring(startIndex, endIndex);
if (sourcePath.startsWith('./') && sourcePath.lastIndexOf('/') === 1) {
return str;
}
if (sourcePath.startsWith('../') || sourcePath.startsWith('./')) {
const lastFolderPath = filePath.substring(0, filePath.lastIndexOf('/'));
sourcePath = (0, vite_1.normalizePath)(path_1.default.resolve(lastFolderPath, sourcePath).replace(path_1.default.resolve(process.cwd(), constants_1.LCAP_UI_PACKAGE_PATH), '@lcap-ui'));
prefixStr.replace('url(', '');
suffixStr.replace(')', '');
}
return [prefixStr, sourcePath, suffixStr].join('');
});
return codes.join('\n');
}
function saveScriptFile(filePath, context, modules) {
const code = fs_extra_1.default.readFileSync(filePath).toString();
const ast = parser.parse(code, {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
});
const ext = path_1.default.extname(filePath);
const basename = path_1.default.basename(filePath, ext);
const { isJSX } = transformScriptAst(ast, filePath, modules);
let resultPath = path_1.default.resolve(context.componentFolderPath, `${basename}${ext}`);
// js 转 jsx
if (isJSX && !ext.endsWith('sx')) {
resultPath = path_1.default.resolve(context.componentFolderPath, `${basename}${ext}x`);
}
fs_extra_1.default.writeFileSync(resultPath, (0, generator_1.default)(ast, {}).code);
}
function parseVueFile(code) {
const result = {
scriptTag: '',
styleTag: '',
templateCodes: [],
scriptCodes: [],
styleCodes: [],
};
let currentScope = '';
code.split('\n').forEach((line) => {
if (line.trim().startsWith('<template') && currentScope !== 'template' && result.templateCodes.length === 0) {
currentScope = 'template';
result.templateCodes.push(line);
return;
}
if (line.trim().startsWith('<style') && !result.styleTag) {
currentScope = 'style';
result.styleTag = line;
return;
}
if (line.trim().startsWith('<script') && !result.scriptTag) {
currentScope = 'script';
result.scriptTag = line;
return;
}
if (line.trim().startsWith('</style>') || line.trim().startsWith('</script>')) {
currentScope = '';
return;
}
switch (currentScope) {
case 'template':
result.templateCodes.push(line);
break;
case 'script':
result.scriptCodes.push(line);
break;
case 'style':
result.styleCodes.push(line);
break;
default: break;
}
});
return result;
}
function saveVueFile(filePath, context, modules) {
const code = fs_extra_1.default.readFileSync(filePath).toString();
const result = parseVueFile(code);
let scriptCode = '';
if (result.scriptCodes.length > 0) {
const ast = parser.parse(result.scriptCodes.join('\n'), {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
});
transformScriptAst(ast, filePath, modules);
scriptCode = (0, generator_1.default)(ast).code;
}
const resultCodes = [];
if (result.templateCodes.length > 0) {
resultCodes.push(...result.templateCodes);
}
if (result.scriptTag) {
resultCodes.push(result.scriptTag, scriptCode, '</script>');
}
if (result.styleTag) {
resultCodes.push(result.styleTag, transformCssCode(result.styleCodes.join('\n'), filePath), result.styleTag.trim().endsWith('</style>') ? '' : '</style>');
}
const basename = path_1.default.basename(filePath);
const resultPath = path_1.default.resolve(context.componentFolderPath, basename);
fs_extra_1.default.writeFileSync(resultPath, resultCodes.join('\n'));
}
function saveCssFile(filePath, context) {
const basename = path_1.default.basename(filePath);
const resultPath = path_1.default.resolve(context.componentFolderPath, basename);
const code = fs_extra_1.default.readFileSync(filePath, 'utf-8').toString();
fs_extra_1.default.writeFileSync(resultPath, transformCssCode(code, filePath), 'utf-8');
}
function addDependices() {
const rootPath = process.cwd();
const sourcePkg = fs_extra_1.default.readJSONSync(path_1.default.resolve(rootPath, constants_1.LCAP_UI_PACKAGE_PATH, 'package.json'));
const pkgPath = path_1.default.resolve(rootPath, 'package.json');
const pkg = fs_extra_1.default.readJSONSync(pkgPath);
if (!pkg.dependencies) {
pkg.dependencies = {};
}
let changed = false;
Object.keys(sourcePkg.dependencies || {}).forEach((name) => {
if (pkg.dependencies[name]) {
return;
}
changed = true;
pkg.dependencies[name] = sourcePkg.dependencies[name];
});
if (changed) {
fs_extra_1.default.writeJSONSync(pkgPath, pkg, { spaces: 2 });
}
}
function addSubExports(context) {
const indexPath = (0, fs_1.getPath)(path_1.default.resolve(context.componentFolderPath, './index'));
const needExportNames = context.replaceNames.filter((name) => context.replaceNameMap[name] && context.replaceNameMap[name] !== context.name);
if (!indexPath || needExportNames.length === 0) {
return;
}
try {
const code = fs_extra_1.default.readFileSync(indexPath, 'utf-8').toString();
const ast = parser.parse(code, {
sourceType: 'module',
plugins: ['typescript', 'jsx'],
});
(0, traverse_1.default)(ast, {
ExportSpecifier(p) {
if (p.node.exported.type === 'Identifier' && needExportNames.includes(p.node.exported.name)) {
// p.node.exported.name = context.replaceNameMap[p.node.exported.name];
const exportPath = p.findParent((n) => n.isExportNamedDeclaration());
// 如果存在 exportPath 且 exportPath 是 ExportNamedDeclaration 类型,则添加新的 ExportSpecifier
if (exportPath && exportPath.node.type === 'ExportNamedDeclaration') {
exportPath.node.specifiers.push({
type: 'ExportSpecifier',
local: p.node.local,
exported: Object.assign(Object.assign({}, p.node.exported), { name: context.replaceNameMap[p.node.exported.name] }),
});
needExportNames.splice(needExportNames.indexOf(p.node.exported.name), 1);
}
}
},
});
let resultCode = (0, generator_1.default)(ast).code;
if (needExportNames.length > 0) {
resultCode = `${resultCode}\nexport { ${needExportNames.map((name) => `${name} as ${context.replaceNameMap[name]}`).join(', ')} } from '${constants_1.LCAP_UI_PACKAGE_NAME}';\n`;
}
fs_extra_1.default.writeFileSync(indexPath, resultCode, 'utf-8');
}
catch (e) {
logger_1.default.warn(e);
}
}
function forkComponent(context) {
return __awaiter(this, void 0, void 0, function* () {
if (!context.fork) {
return;
}
addDependices();
const removeFiles = yield (0, fast_glob_1.default)('index.{jsx,js,ts,tsx,vue}', { cwd: context.componentFolderPath, absolute: true });
removeFiles.forEach((filePath) => {
fs_extra_1.default.unlinkSync(filePath);
});
const files = yield (0, fast_glob_1.default)('*.{vue,jsx,js,ts,tsx,css}', { cwd: context.pkgComponentFolderPath, absolute: true, ignore: ['api.ts'] });
const modules = [];
files.forEach((filePath) => {
const ext = path_1.default.extname(filePath);
switch (ext) {
case '.vue':
saveVueFile(filePath, context, modules);
break;
case '.jsx':
case '.js':
case '.ts':
case '.tsx':
saveScriptFile(filePath, context, modules);
break;
case '.css':
saveCssFile(filePath, context);
break;
default: break;
}
});
addSubExports(context);
});
}
exports.forkComponent = forkComponent;