@dao-style/cli
Version:
CLI tool for DAO Style projects - providing project scaffolding, template generation and dependency management
863 lines (844 loc) • 29.4 kB
JavaScript
// src/commands/create.ts
import { chmod, writeFile } from "node:fs/promises";
import * as path7 from "path";
import chalk2 from "chalk";
import * as fs from "fs-extra";
import ora from "ora";
// src/templates/base/index.ts
import { fileURLToPath } from "node:url";
import * as path from "path";
// src/utils/npm.ts
import pacote from "pacote";
async function getPackageVersions(packageName, options = {}) {
const { registry = "https://registry.npmmirror.com" } = options;
try {
const manifest = await pacote.manifest(`${packageName}@latest`, {
registry
});
const versions = {
latest: manifest.version
};
if (options.includePrerelease) {
const packument = await pacote.packument(packageName, {
registry,
fullMetadata: true
// 确保获取完整的元数据
});
const allVersions = Object.keys(packument.versions).sort((a, b) => {
const timeA = packument.time[a] || "";
const timeB = packument.time[b] || "";
return new Date(timeB).getTime() - new Date(timeA).getTime();
});
for (const version of allVersions) {
if (version.includes("next") && !versions.next) {
versions.next = version;
} else if (version.includes("beta") && !versions.beta) {
versions.beta = version;
} else if (version.includes("alpha") && !versions.alpha) {
versions.alpha = version;
}
if (versions.next && versions.beta && versions.alpha) {
break;
}
}
}
return versions;
} catch (error) {
throw new Error(`Failed to fetch version for ${packageName}: ${error}`);
}
}
async function getMultiplePackageVersions(packages, options) {
const results = await Promise.all(
packages.map((pkg) => getPackageVersions(pkg, options))
);
return packages.reduce(
(acc, pkg, index) => {
acc[pkg] = results[index];
return acc;
},
{}
);
}
// src/templates/base/index.ts
var currentDir = path.dirname(fileURLToPath(import.meta.url));
var getTemplateFilesPath = () => {
if (currentDir.includes("dist")) {
return path.resolve(currentDir, "../src/templates/base/files");
}
return path.resolve(currentDir, "files");
};
var baseTemplate = {
name: "base",
path: getTemplateFilesPath(),
postInstall: {
files: [
{
path: ".vscode/settings.json",
sourcePath: "_vscode/settings.json",
mergeStrategy: "json"
},
{
path: ".vscode/extensions.json",
sourcePath: "_vscode/extensions.json",
mergeStrategy: "json"
}
]
},
prompts: [
{
type: "input",
name: "port",
message: "Enter the port number for the dev server (default: 8160):",
default: "8160",
validate: (input) => {
const port = parseInt(input);
if (Number.isNaN(port) || port < 8e3 || port > 9e3) {
return "Please enter a valid port number between 8000 and 9000";
}
return true;
}
},
{
type: "checkbox",
name: "packages",
message: "Select DAO Style packages to include:",
choices: [
{ name: "@dao-style/core", checked: true },
{ name: "@dao-style/extend", checked: true },
{ name: "@dao-style/biz", checked: false }
]
}
],
async transform(data, prompt) {
const packages = prompt?.packages || [];
const versions = await getMultiplePackageVersions(packages);
return {
...data,
port: prompt?.port,
packageJSON: {
...data.packageJSON,
scripts: {
...data.packageJSON?.scripts,
serve: "rsbuild dev",
"serve:build": "rsbuild dev -m production",
build: "rsbuild build",
"test:unit": "vitest",
"test:unit:ci": "vitest run --coverage --reporter=junit --outputFile=junit.xml"
},
dependencies: {
...data.packageJSON?.dependencies,
...packages.reduce(
(acc, pkg) => {
acc[pkg] = `^${versions[pkg].latest}`;
return acc;
},
{}
)
}
}
};
}
};
// src/templates/ci/index.ts
import { fileURLToPath as fileURLToPath2 } from "node:url";
import * as path2 from "path";
var currentDir2 = path2.dirname(fileURLToPath2(import.meta.url));
var getTemplateFilesPath2 = () => {
if (currentDir2.includes("dist")) {
return path2.resolve(currentDir2, "../src/templates/ci/files");
}
return path2.resolve(currentDir2, "files");
};
var ciTemplate = {
name: "ci",
path: getTemplateFilesPath2(),
transform(data) {
return {
...data,
packageJSON: {
...data.packageJSON,
scripts: {
...data.packageJSON?.scripts,
"change:version": "esno ./scripts/change-version.ts"
}
}
};
}
};
// src/templates/lint/index.ts
import { fileURLToPath as fileURLToPath3 } from "node:url";
import * as path3 from "path";
var currentDir3 = path3.dirname(fileURLToPath3(import.meta.url));
var getTemplateFilesPath3 = () => {
if (currentDir3.includes("dist")) {
return path3.resolve(currentDir3, "../src/templates/lint/files");
}
return path3.resolve(currentDir3, "files");
};
var lintTemplate = {
name: "lint",
path: getTemplateFilesPath3(),
postInstall: {
files: [
{
path: ".vscode/settings.json",
sourcePath: "_vscode/settings.json",
mergeStrategy: "json"
},
{
path: ".vscode/extensions.json",
sourcePath: "_vscode/extensions.json",
mergeStrategy: "json"
}
]
},
transform(data) {
return {
...data,
packageJSON: {
...data.packageJSON,
scripts: {
...data.packageJSON?.scripts,
// support lint:fix
prepare: "husky install",
commit: "git-cz",
lint: "pnpm run lint:style && pnpm run lint:es && pnpm run lint:type && pnpm run lint:doc",
"lint:doc:fix": 'prettier "**/**.json" --write --ignore-unknown && textlint "**/*.json" --config .textlintrc.json --fix',
"lint:doc": 'prettier "**/**.json" --check --ignore-unknown && textlint "**/*.json" --config .textlintrc.json',
"lint:es": 'eslint "src/**/*.{js,jsx,ts,tsx,vue,json}" --config .eslintrc.js --max-warnings=0',
"lint:fix": "pnpm run lint:style --fix && pnpm run lint:es --fix && pnpm run lint:doc:fix",
"lint:style": 'stylelint "src/**/*.{vue,scss,css}" --config .stylelintrc.js',
"lint:type": "vue-tsc --build --force"
},
devDependencies: {
...data.packageJSON?.devDependencies,
"@commitlint/cli": "^16.0.2",
"@commitlint/config-conventional": "^16.0.0",
"@commitlint/cz-commitlint": "^16.0.0",
"@typescript-eslint/eslint-plugin": "~6.0.0",
"@typescript-eslint/parser": "~6.0.0",
"@vue/eslint-config-typescript": "~13.0.0",
commitizen: "^4.2.4",
eslint: "~8.56.0",
"eslint-config-airbnb-base": "~15.0.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jsonc": "~2.7.0",
"eslint-plugin-node": "~11.1.0",
"eslint-plugin-promise": "~6.4.0",
"eslint-plugin-vue": "~9.27.0",
"lint-staged": "^15.2.7",
husky: "^8.0.3",
stylelint: "~14.5.0",
"stylelint-config-recess-order": "~3.0.0",
"stylelint-config-recommended": "~7.0.0",
"stylelint-config-recommended-vue": "~1.1.0",
"stylelint-config-sass-guidelines": "~9.0.1",
textlint: "~13.4.1",
"textlint-plugin-json": "~0.0.1",
"textlint-rule-ja-space-between-half-and-full-width": "~2.3.0",
"vue-eslint-parser": "~9.1.0"
},
config: {
...data.packageJSON?.config,
commitizen: {
...data.packageJSON?.config?.commitizen,
path: "@commitlint/cz-commitlint"
}
},
gitHooks: {
...data.packageJSON?.gitHooks,
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E GIT_PARAMS"
}
}
};
}
};
// src/utils/process-template.ts
import { readFile } from "node:fs/promises";
import * as path6 from "path";
import chalk from "chalk";
import inquirer from "inquirer";
import { cloneDeep } from "lodash-es";
import { sortPackageJson as sortPackageJson2 } from "sort-package-json";
// src/utils/file.ts
import { readdir } from "node:fs/promises";
import * as path4 from "path";
async function getAllFiles(dir) {
const entries = await readdir(dir, { withFileTypes: true });
const files = await Promise.all(
entries.map((entry) => {
const res = path4.resolve(dir, entry.name);
return entry.isDirectory() ? getAllFiles(res) : res;
})
);
return files.flat();
}
// src/utils/json.ts
import { isArray, isObject, mergeWith } from "lodash-es";
function sortObjectKeys(obj) {
if (Array.isArray(obj)) {
return obj.map(sortObjectKeys);
}
if (isObject(obj)) {
const sorted = {};
Object.keys(obj).sort().forEach((key) => {
sorted[key] = sortObjectKeys(obj[key]);
});
return sorted;
}
return obj;
}
function isJsonSubset(subset, superset) {
if (subset === superset) return true;
if (Array.isArray(subset) && Array.isArray(superset)) {
if (subset.every((item) => !isObject(item)) && superset.every((item) => !isObject(item))) {
return subset.every((item) => superset.includes(item));
}
return subset.every(
(subItem) => superset.some((superItem) => isJsonSubset(subItem, superItem))
);
}
if (isObject(subset) && isObject(superset)) {
return Object.keys(subset).every((key) => {
const subValue = subset[key];
const superValue = superset[key];
return superValue !== void 0 && isJsonSubset(subValue, superValue);
});
}
return false;
}
function mergeJson(target, source) {
return mergeWith({}, target, source, (objValue, srcValue) => {
if (isArray(objValue) && isArray(srcValue)) {
if (objValue.every((item) => !isObject(item)) && srcValue.every((item) => !isObject(item))) {
return [.../* @__PURE__ */ new Set([...objValue, ...srcValue])];
}
return srcValue;
}
});
}
function tryParseJson(content) {
try {
return JSON.parse(content);
} catch {
return null;
}
}
// src/utils/template.ts
import path5 from "path";
import ejs from "ejs";
import { camelCase } from "lodash-es";
import { sortPackageJson } from "sort-package-json";
var capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
var pascalCase = (str) => capitalize(camelCase(str));
function createTemplateData(data) {
return {
...data,
helpers: {
raw: (options) => options.fn(),
capitalize,
camelCase,
formatDate: (date) => date.toLocaleDateString(),
pascalCase
}
};
}
function shouldRenderTemplate(filePath) {
const ext = path5.extname(filePath);
return ext === ".ejs" || ext === ".html" || ext === ".json" || ext === ".js" || ext === ".ts" || ext === ".vue" || ext === ".md" || !ext;
}
function processPackageJson(content, data) {
try {
const pkg = JSON.parse(content);
if (data.packageJSON?.scripts) {
pkg.scripts = { ...pkg.scripts, ...data.packageJSON?.scripts };
}
if (data.packageJSON?.dependencies) {
pkg.dependencies = { ...pkg.dependencies, ...data.packageJSON?.dependencies };
}
if (data.packageJSON?.devDependencies) {
pkg.devDependencies = { ...pkg.devDependencies, ...data.packageJSON?.devDependencies };
}
if (data.packageJSON?.gitHooks) {
pkg.gitHooks = { ...pkg.gitHooks, ...data.packageJSON?.gitHooks };
}
if (data.packageJSON?.["lint-staged"]) {
pkg["lint-staged"] = { ...pkg["lint-staged"], ...data.packageJSON?.["lint-staged"] };
}
if (data.packageJSON?.config) {
pkg.config = { ...pkg.config, ...data.packageJSON?.config };
}
return JSON.stringify(sortPackageJson(pkg), null, 2);
} catch (error) {
console.error("Error processing package.json:", error);
return content;
}
}
async function renderTemplate(content, data, templateDir, filePath) {
if (!shouldRenderTemplate(filePath)) {
return content;
}
try {
const rendered = await ejs.render(content, createTemplateData(data), {
filename: filePath,
async: true
});
if (path5.basename(filePath) === "package.json") {
return processPackageJson(rendered, data);
}
return rendered;
} catch (error) {
console.error(`Error rendering template ${filePath}:`, error);
throw error;
}
}
function processFileName(fileName, data) {
let processedName = fileName;
if (processedName.startsWith("_")) {
processedName = `.${processedName.slice(1)}`;
}
try {
return ejs.render(processedName.replace(/_([^_]+)_/g, "<%= $1 %>"), data);
} catch (error) {
console.error(`Error processing filename ${fileName}:`, error);
return processedName;
}
}
// src/utils/process-template.ts
async function processTemplateFile(filePath, templatePath, data) {
const content = await readFile(filePath, "utf-8");
const relativePath = path6.relative(templatePath, filePath);
const processedPath = processFileName(relativePath, data);
return {
path: processedPath,
content,
originalPath: filePath
};
}
async function processTemplate(template, data, existingFiles) {
const transformedData = template.transform ? template.transform(data) : data;
const files = await getAllFiles(template.path);
const processedFiles = new Map(existingFiles);
for (const file of files) {
const processed = await processTemplateFile(
file,
template.path,
transformedData
);
if (processed.path.endsWith(".json")) {
const existingFile = processedFiles.get(processed.path);
if (existingFile) {
const existingJson = tryParseJson(existingFile.content);
const newJson = tryParseJson(processed.content);
if (existingJson !== null && newJson !== null) {
const mergedJson = mergeJson(existingJson, newJson);
const isPackageJSON = processed.path === "package.json";
const sortedJson = isPackageJSON ? sortPackageJson2(mergedJson) : sortObjectKeys(mergedJson);
processed.content = JSON.stringify(sortedJson, null, 2) + "\n";
} else {
console.log(chalk.red(`Failed to merge JSON files: ${processed.path}`));
throw new Error(`Failed to merge JSON files: ${processed.path}`);
}
}
}
processedFiles.set(processed.path, processed);
}
return processedFiles;
}
async function renderProcessedTemplate(processed, data) {
return renderTemplate(
processed.content,
data,
processed.path,
processed.originalPath
);
}
async function processTemplates(templates, data) {
const processedFiles = /* @__PURE__ */ new Map();
for (const template of templates) {
if (template.validate) {
template.validate(data);
}
const files = await processTemplate(template, data, processedFiles);
for (const [path10, file] of files) {
processedFiles.set(path10, file);
}
}
return Array.from(processedFiles.values());
}
async function processTemplateData(templateData, templates) {
const result = cloneDeep(templateData);
for (const template of templates) {
let promptAnswers;
if (template.prompts) {
const answers = await inquirer.prompt(template.prompts);
promptAnswers = answers;
}
if (template.transform) {
const transformedData = await template.transform(result, promptAnswers);
Object.assign(result, transformedData);
}
}
return result;
}
// src/commands/create.ts
async function addExecutePermissions(projectPath) {
const executableFiles = [
"scripts/cherry-pick.sh",
"scripts/get-version.sh",
".husky/pre-commit"
];
for (const file of executableFiles) {
try {
const filePath = path7.join(projectPath, file);
await chmod(filePath, "755");
} catch (error) {
console.error(chalk2.red(`Failed to add execute permission to ${file}`), error);
continue;
}
}
}
async function create(name) {
const spinner = ora("Creating project...");
try {
const packageName = `${name}-ui`;
const versions = await getMultiplePackageVersions(["@dao-style/cli"]);
const templateData = {
name,
packageName,
packageJSON: {
dependencies: {
"@dao-style/cli": `^${versions["@dao-style/cli"].latest}`
},
scripts: {
postinstall: "dao post-install"
}
}
};
const templates = [baseTemplate, lintTemplate, ciTemplate];
const mergedTemplateData = await processTemplateData(templateData, templates);
const processedFiles = await processTemplates(templates, mergedTemplateData);
spinner.text = "Creating project directory";
spinner.start();
const projectPath = path7.resolve(process.cwd(), packageName);
if (await fs.pathExists(projectPath)) {
spinner.fail(chalk2.red(`Directory ${packageName} already exists`));
process.exit(1);
}
await fs.ensureDir(projectPath);
spinner.succeed(chalk2.green("Project directory created"));
for (const file of processedFiles) {
const targetPath = path7.join(projectPath, file.path);
await fs.ensureDir(path7.dirname(targetPath));
const renderedContent = await renderProcessedTemplate(file, mergedTemplateData);
await writeFile(targetPath, renderedContent);
}
await addExecutePermissions(projectPath);
spinner.succeed(chalk2.green(`Successfully created project ${packageName}`));
console.log("\nNext steps:");
console.log(chalk2.cyan(` cd ${packageName}`));
console.log(chalk2.cyan(" pnpm install"));
console.log(chalk2.cyan(" pnpm serve"));
} catch (error) {
spinner.fail(chalk2.red("Failed to create project"));
console.error(error);
process.exit(1);
}
}
// src/commands/upgrade.ts
import { exec } from "node:child_process";
import { existsSync } from "node:fs";
import { readFile as readFile2 } from "node:fs/promises";
import { promisify } from "node:util";
import * as path8 from "path";
import chalk3 from "chalk";
import { diffLines } from "diff";
import { outputFile } from "fs-extra";
import inquirer2 from "inquirer";
import ora2 from "ora";
import { sortPackageJson as sortPackageJson3 } from "sort-package-json";
var execAsync = promisify(exec);
async function checkGitStatus() {
try {
const { stdout } = await execAsync("git status --porcelain");
return stdout.length === 0;
} catch (error) {
console.error(chalk3.red("Check git status failed:"), error);
throw new Error("Not a git repository");
}
}
async function promptForContinue() {
const { continue: shouldContinue } = await inquirer2.prompt([
{
type: "confirm",
name: "continue",
message: "Working directory is not clean. Continue anyway?",
default: false
}
]);
return shouldContinue;
}
async function selectTemplates() {
const { templates } = await inquirer2.prompt([
{
type: "checkbox",
name: "templates",
message: "Select templates to upgrade:",
choices: [
{ name: "Base Template", value: "base" },
{ name: "CI/CD Template", value: "ci" },
{ name: "Lint Template", value: "lint" }
]
}
]);
return templates;
}
async function mergeFile(processed, projectPath, content) {
const projectFilePath = path8.join(projectPath, processed.path);
let renderedContent = content;
if (!existsSync(projectFilePath)) {
await outputFile(projectFilePath, renderedContent);
return;
}
let projectContent = await readFile2(projectFilePath, "utf-8");
if (processed.path.endsWith(".json")) {
const targetJson = tryParseJson(projectContent);
const sourceJson = tryParseJson(renderedContent);
const mergedJson = mergeJson(targetJson, sourceJson);
const isPackageJSON = processed.path === "package.json";
if (!targetJson || !sourceJson) {
console.log(chalk3.red(`Failed to merge JSON files: ${processed.path}`));
throw new Error(`Failed to merge JSON files: ${processed.path}`);
}
const sortedJson = isPackageJSON ? sortPackageJson3(mergedJson) : sortObjectKeys(mergedJson);
const sortedTargetJson = isPackageJSON ? sortPackageJson3(targetJson) : sortObjectKeys(targetJson);
if (isJsonSubset(sortedJson, sortedTargetJson)) {
return;
}
projectContent = JSON.stringify(sortedTargetJson, null, 2) + "\n";
renderedContent = JSON.stringify(sortedJson, null, 2) + "\n";
}
const differences = diffLines(projectContent, renderedContent);
if (differences.every((part) => !part.added && !part.removed)) {
return;
}
let mergedContent = "";
let currentIndex = 0;
while (currentIndex < differences.length) {
const current = differences[currentIndex];
const next = differences[currentIndex + 1];
if (current.removed && next?.added) {
mergedContent += "<<<<<<< HEAD\n";
mergedContent += current.value;
mergedContent += "=======\n";
mergedContent += next.value;
mergedContent += ">>>>>>> template\n";
currentIndex += 2;
} else if (current.removed) {
mergedContent += "<<<<<<< HEAD\n";
mergedContent += current.value;
mergedContent += "=======\n>>>>>>> template\n";
currentIndex++;
} else if (current.added) {
mergedContent += "<<<<<<< HEAD\n=======\n";
mergedContent += current.value;
mergedContent += ">>>>>>> template\n";
currentIndex++;
} else {
mergedContent += current.value;
currentIndex++;
}
}
return {
path: projectFilePath,
content: mergedContent
};
}
async function upgrade(options) {
const templates = {
base: baseTemplate,
ci: ciTemplate,
lint: lintTemplate
};
try {
const isClean = await checkGitStatus();
if (!isClean && !options.force) {
console.log(chalk3.yellow("Warning: You have uncommitted changes."));
const shouldContinue = await promptForContinue();
if (!shouldContinue) {
console.log(chalk3.blue("Upgrade cancelled."));
return;
}
}
const selectedTemplateNames = await selectTemplates();
if (selectedTemplateNames.length === 0) {
console.log(chalk3.blue("No templates selected. Upgrade cancelled."));
return;
}
const projectPath = process.cwd();
const packageJsonPath = path8.join(projectPath, "package.json");
const packageJson2 = JSON.parse(await readFile2(packageJsonPath, "utf-8"));
const templateData = {
name: packageJson2.name.replace(/-ui$/, ""),
packageJSON: {
...packageJson2
}
};
const selectedTemplates = selectedTemplateNames.filter((name) => templates[name]).map((name) => templates[name]);
const mergedTemplateData = await processTemplateData(templateData, selectedTemplates);
const processedFiles = await processTemplates(selectedTemplates, templateData);
if (!processedFiles.find((file) => file.path === "package.json")) {
processedFiles.push({
content: JSON.stringify(mergedTemplateData.packageJSON, null, 2),
originalPath: "package.json",
path: "package.json"
});
}
const packageJSONFileObj = processedFiles.find((file) => file.path === "package.json");
if (packageJSONFileObj) {
const packageJSON = JSON.parse(packageJSONFileObj.content);
if (packageJSON.version === "0.0.0") {
packageJSON.version = "0.1.0";
}
if (!packageJSON.dependencies) {
packageJSON.dependencies = {};
}
if (!packageJSON.scripts) {
packageJSON.scripts = {};
}
const versions = await getMultiplePackageVersions(["@dao-style/cli"]);
packageJSON.dependencies["@dao-style/cli"] = `^${versions["@dao-style/cli"].latest}`;
const existingPostinstall = packageJSON.scripts.postinstall || "";
const postInstallCmd = "dao post-install";
if (!existingPostinstall.includes(postInstallCmd)) {
packageJSON.scripts.postinstall = existingPostinstall ? `${existingPostinstall} && ${postInstallCmd}` : postInstallCmd;
}
packageJSONFileObj.content = JSON.stringify(packageJSON, null, 2);
}
const upgradeSpinner = ora2(`Upgrading template...`).start();
const mergedFilesMap = /* @__PURE__ */ new Map();
for (const file of processedFiles) {
const renderedContent = await renderProcessedTemplate(file, mergedTemplateData);
const mergedInfo = await mergeFile(file, projectPath, renderedContent);
if (mergedInfo) {
mergedFilesMap.set(mergedInfo.path, mergedInfo.content);
}
}
for (const [path10, content] of mergedFilesMap) {
await outputFile(path10, content);
console.log(chalk3.yellow(`Please resolve the conflicts manually. ${path10}`));
}
upgradeSpinner.succeed(chalk3.green(`Successfully upgraded template`));
console.log(chalk3.yellow("\nPlease review the changes and resolve any conflicts."));
console.log(chalk3.yellow("Files with conflicts will contain markers: <<<<<<< HEAD, =======, and >>>>>>> template"));
} catch (error) {
console.error(chalk3.red("Upgrade failed:"), error);
process.exit(1);
}
}
// src/cli.ts
import { readFileSync } from "node:fs";
import { dirname as dirname6, resolve as resolve6 } from "node:path";
import { fileURLToPath as fileURLToPath4 } from "node:url";
import { Command } from "commander";
// src/commands/post-install.ts
import chalk4 from "chalk";
import ora3 from "ora";
// src/utils/post-install.ts
import { readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
import * as path9 from "node:path";
import * as fs2 from "fs-extra";
import { cloneDeep as cloneDeep2, isArray as isArray2, isObject as isObject2, mergeWith as mergeWith2 } from "lodash-es";
function customizer(objValue, srcValue) {
if (isArray2(objValue) && isArray2(srcValue)) {
if (objValue.every((item) => !isObject2(item)) && srcValue.every((item) => !isObject2(item))) {
return [.../* @__PURE__ */ new Set([...objValue, ...srcValue])];
}
return srcValue;
}
}
async function processPostInstallFile(file, template, projectPath) {
const sourcePath = path9.join(template.path, file.sourcePath);
const targetPath = path9.join(projectPath, file.path);
const sourceContent = await readFile3(sourcePath, "utf-8");
return {
targetPath,
sourceContent,
mergeStrategy: file.mergeStrategy
};
}
async function processPostInstallFiles(templates, projectPath) {
const processedFiles = [];
for (const template of templates) {
if (template.postInstall?.files) {
for (const file of template.postInstall.files) {
const processed = await processPostInstallFile(file, template, projectPath);
processedFiles.push(processed);
}
}
}
return processedFiles;
}
async function renderProcessedPostInstallFile(processed) {
if (processed.mergeStrategy === "json") {
let targetContent = "{}";
if (await fs2.pathExists(processed.targetPath)) {
targetContent = await readFile3(processed.targetPath, "utf-8");
}
const targetJson = JSON.parse(targetContent);
const sourceJson = JSON.parse(processed.sourceContent);
const mergedJson = mergeWith2(
{},
cloneDeep2(targetJson),
sourceJson,
customizer
);
return JSON.stringify(mergedJson, null, 2);
}
return processed.sourceContent;
}
async function writeProcessedPostInstallFile(processed, content) {
if (processed.mergeStrategy !== "json" && await fs2.pathExists(processed.targetPath)) {
return;
}
await fs2.ensureDir(path9.dirname(processed.targetPath));
await writeFile2(processed.targetPath, content);
}
// src/commands/post-install.ts
async function postInstall() {
const spinner = ora3("Running post-install tasks...").start();
try {
const projectPath = process.cwd();
const templates = [baseTemplate, lintTemplate, ciTemplate];
const processedFiles = await processPostInstallFiles(templates, projectPath);
for (const file of processedFiles) {
const renderedContent = await renderProcessedPostInstallFile(file);
await writeProcessedPostInstallFile(file, renderedContent);
}
spinner.succeed(chalk4.green("Post-install tasks completed successfully"));
} catch (error) {
spinner.fail(chalk4.red("Post-install tasks failed"));
console.error(error);
process.exit(1);
}
}
// src/cli.ts
var __filename = fileURLToPath4(import.meta.url);
var __dirname = dirname6(__filename);
var packageJson = JSON.parse(
readFileSync(resolve6(__dirname, "../package.json"), "utf-8")
);
function buildCLI() {
const program = new Command();
program.name("dao").description("DAO Style CLI tool for project management").version(packageJson.version);
program.command("create").description("Create a new project").argument("<name>", "project name").action(create);
program.command("upgrade").description("Upgrade dependencies").action(upgrade);
program.command("post-install").description("Run post-install tasks").action(postInstall);
return program;
}
export {
create,
upgrade,
buildCLI
};