UNPKG

create-mori

Version:

Quickly create project templates to support the required repositories as much as possible

160 lines (159 loc) 5.96 kB
import fs from 'fs'; import fsExtra from 'fs-extra/esm'; import { resolve } from 'path'; import { Node, Project, SyntaxKind, } from 'ts-morph'; import { SpecifiedTemplateMap } from './constant.js'; /** * 解析规则: inject.json中: 1. 值为数组,表示直接向路径插入代码 2. 值为对象 & json 文件,向其中插入对应的字段 3. 值为对象 & js 文件,解析js并插入代码 */ export function resolveInject(injectJsonPath) { if (!injectJsonPath) return; const config = fsExtra.readJsonSync(injectJsonPath); const injectJson = config.json; const write = config.write; const injectJs = config.js; return { injectJson, write, injectJs }; } export function processJson(injectJson, root) { for (const key in injectJson) { if (Object.prototype.hasOwnProperty.call(injectJson, key)) { const { path, inject } = injectJson[key]; const targetPath = resolve(root, path); const originalJson = fsExtra.readJSONSync(targetPath); for (const jsonKey in inject) { if (Object.prototype.hasOwnProperty.call(inject, jsonKey)) { originalJson[jsonKey] = { ...originalJson[jsonKey], ...inject[jsonKey], }; } } fsExtra.writeJSONSync(targetPath, originalJson, { spaces: 4, }); } } } export function processWrite(injectWrite, root) { for (const key in injectWrite) { if (Object.prototype.hasOwnProperty.call(injectWrite, key)) { const targetPath = resolve(root, injectWrite[key].path); fsExtra.ensureFileSync(targetPath); const { inject, pos } = injectWrite[key]; if (Array.isArray(inject)) { let injectCode = ''; inject.forEach((code) => { injectCode += `${code}\n`; }); writeContentAfterLine(targetPath, pos, injectCode); } else { writeContentAfterLine(targetPath, pos, inject); } } } } function writeContentAfterLine(filePath, lineNumber, content) { const data = fs.readFileSync(filePath, 'utf8').split(/\r\n|\n|\r/gm); data.splice(lineNumber, 0, content); fs.writeFileSync(filePath, data.join('\n')); } export function processJs(injectJs, root) { for (const key in injectJs) { if (Object.prototype.hasOwnProperty.call(injectJs, key)) { const { path, inject } = injectJs[key]; const targetPath = resolve(root, path); const project = new Project(); const sourceFile = project.addSourceFileAtPath(targetPath); // process vite.config.ts if (path.includes('vite.config')) { processViteConfig(sourceFile, inject); } // save sourceFile.saveSync(); } } } function processViteConfig(sourceFile, inject) { const defaultExport = sourceFile.getDefaultExportSymbol(); const exportedExpr = defaultExport.getDeclarations()[0].getExpression(); if (!Node.isCallExpression(exportedExpr)) { throw new Error('export not a CallExpression'); } const arrowFunc = exportedExpr.getArguments()[0]; if (!Node.isArrowFunction(arrowFunc)) { throw new Error('defineConfig\'s first arg is not a arrow function'); } const returnBlock = arrowFunc.getBody(); if (!Node.isBlock(returnBlock)) { throw new Error('arrow function body is not a block'); } const bodyStatements = returnBlock.getStatements(); bodyStatements.forEach((statement) => { if (Node.isReturnStatement(statement)) { const returnStatement = statement; const defineConfigReturnValue = returnStatement.getExpression(); if (!defineConfigReturnValue) { throw new Error('return statement has no expression'); } processConfigReturnObject(defineConfigReturnValue, inject); } }); } function processConfigReturnObject(defineConfigReturnValue, inject) { if (!Node.isObjectLiteralExpression(defineConfigReturnValue)) { throw new Error('vite config is not a Object'); } for (const key in inject) { if (Object.prototype.hasOwnProperty.call(inject, key)) { switch (key) { case 'plugins': let pluginsArrayExpr = defineConfigReturnValue .getProperty('plugins') ?.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression); if (!pluginsArrayExpr) { const newPluginsArray = defineConfigReturnValue .addPropertyAssignment({ name: 'plugins', initializer: '[]', }) .getFirstChildByKind(SyntaxKind.ArrayLiteralExpression); pluginsArrayExpr = newPluginsArray; } injectPlugins(inject.plugins, pluginsArrayExpr); break; default: break; } } } } function injectPlugins(plugins, pluginsArrayExpr) { if (Array.isArray(plugins)) { plugins.forEach((plugin) => { pluginsArrayExpr.addElement(plugin); }); } else { pluginsArrayExpr.addElement(plugins); } } export function hasSpecificTemplate(tempAlias) { const set = new Set(); SpecifiedTemplateMap.forEach((k, v) => { set.add(k); set.add(v); }); return set.has(tempAlias); } export function convertAliasToTemplateName(alias) { if (SpecifiedTemplateMap.has(alias)) { return SpecifiedTemplateMap.get(alias); } return alias; }