@agametis/create-app-for-fm
Version:
Tool for selecting a starter project for FileMaker applications
248 lines (227 loc) • 7.75 kB
JavaScript
import fs from "fs-extra";
import path from "path";
import prompts from "prompts";
import {GITHUB_CONFIG} from "../config.js";
import {t} from "../i18n.js";
import {
cloneRepository,
initializePackageManager,
installDependencies,
cleanupAndExit,
cancelOnce,
} from "../utils.js";
// Function to initialize the current directory as a project
export async function initProject() {
try {
console.log(t("init.initializingCurrentDirectory"));
// Check if directory is empty
const currentDir = process.cwd();
const dirContents = fs.readdirSync(currentDir);
const isEmpty = dirContents.length === 0;
const projectDir = process.cwd();
// If directory is not empty, ask for confirmation
if (!isEmpty) {
let confirmResponse;
try {
confirmResponse = await prompts({
type: "confirm",
name: "confirm",
message: t("common.directoryNotEmpty"),
initial: false,
}, {
onCancel: () => {
cancelOnce(1);
return true;
},
});
} catch (e) {
if (e instanceof Error && e.message === "canceled") {
cancelOnce(1);
return; // cancelled during confirm
}
throw e;
}
// Check if user aborted (ESC or empty answers)
if (
!confirmResponse ||
Object.values(confirmResponse).length === 0 ||
Object.values(confirmResponse).some((v) => v === undefined)
) {
cancelOnce(1);
return; // ensure no further execution
}
const { confirm } = confirmResponse;
if (!confirm) {
console.log(t("common.operationCancelled"));
return;
}
}
// Always use npm as the package manager
let responses;
const packageManager = "npm";
console.log(`${t("common.selectedPackageManager")}${packageManager}`);
responses = await prompts([
{
type: "select",
name: "template",
message: t("common.selectTemplate"),
choices: GITHUB_CONFIG.repositories.map((repo) => ({
title: repo.name,
value: `${GITHUB_CONFIG.baseUrl}${repo.path}`,
})),
initial: 0,
},
], {
onCancel: () => {
cancelOnce(1);
return true;
},
});
if (!responses.template) {
console.log(t("common.operationCancelled"));
return; // do not proceed without a template
}
// Skip initialization - we'll check if we need it after cloning the template
console.log(t("common.preparingTemplate"));
// Klone und kopiere Vorlagendateien
console.log(t("init.downloadingTemplateFiles"));
// Klone das Repository mit Helper-Funktion
const tempCloneDir = path.join(process.cwd(), "temp-clone");
const cloneSuccess = await cloneRepository(
responses.template,
tempCloneDir
);
if (!cloneSuccess) {
return; // cloning failed; abort
}
// Check if the template has a package.json
const templatePackageJsonPath = path.join(tempCloneDir, "package.json");
const hasTemplatePackageJson = fs.existsSync(templatePackageJsonPath);
// Copy files from the cloned repo
fs.copySync(tempCloneDir, projectDir, {
filter: (src) => {
const relativePath = path.relative(tempCloneDir, src);
// Only skip package.json if we already have one AND the template has one
const shouldSkipPackageJson =
relativePath === "package.json" &&
fs.existsSync(path.join(projectDir, "package.json")) &&
hasTemplatePackageJson;
return !src.includes(".git") && !shouldSkipPackageJson;
},
overwrite: true,
});
// Räume auf
fs.removeSync(tempCloneDir);
console.log(t("common.templateCopied"));
console.log(t("init.projectInitialized"));
// Check if package.json exists after copying
const packageJsonPath = path.join(projectDir, "package.json");
// If no package.json exists, initialize one
if (!fs.existsSync(packageJsonPath)) {
console.log(t("init.noPackageJsonFound"));
initializePackageManager(packageManager, projectDir);
} else {
// If package.json exists, install dependencies
installDependencies(packageManager, projectDir);
}
// Show next steps
console.log(t("common.nextSteps"));
// Only show installation step if it wasn't already done
if (
!fs.existsSync(packageJsonPath) ||
!fs.existsSync(path.join(projectDir, "node_modules"))
) {
console.log(
t("init.installDependenciesStep", {
packageManager: packageManager,
})
);
// Check if package.json contains scripts
if (fs.existsSync(packageJsonPath)) {
try {
const packageJson = JSON.parse(
fs.readFileSync(packageJsonPath, "utf8")
);
if (
packageJson.scripts &&
Object.keys(packageJson.scripts).length > 0
) {
console.log(t("common.availableScripts", { stepNumber: 2 }));
let scriptNumber = 1;
for (const [scriptName, scriptCommand] of Object.entries(
packageJson.scripts
)) {
console.log(
` - ${scriptName}: ${packageManager} ${
packageManager === "npm" ? "run " : ""
}${scriptName}`
);
scriptNumber++;
}
}
} catch (error) {
// Ignore errors when reading package.json
}
}
} else {
let stepNumber = 1;
// Check if package.json contains scripts
if (fs.existsSync(packageJsonPath)) {
try {
const packageJson = JSON.parse(
fs.readFileSync(packageJsonPath, "utf8")
);
if (
packageJson.scripts &&
Object.keys(packageJson.scripts).length > 0
) {
// Check if there's a dev or start script
const hasDevScript = packageJson.scripts.dev !== undefined;
const hasStartScript = packageJson.scripts.start !== undefined;
const hasServeScript = packageJson.scripts.serve !== undefined;
if (hasDevScript || hasStartScript || hasServeScript) {
// Prefer dev, then start, then serve
const devCommand = hasDevScript
? "dev"
: hasStartScript
? "start"
: "serve";
console.log(
` ${stepNumber}. ${t(
"common.startDevServer"
)}: ${packageManager} ${
packageManager === "npm" ? "run " : ""
}${devCommand}`
);
} else {
// If no dev/start script, show available scripts
console.log(t("common.availableScripts", { stepNumber }));
for (const [scriptName, scriptCommand] of Object.entries(
packageJson.scripts
)) {
console.log(
` - ${scriptName}: ${packageManager} ${
packageManager === "npm" ? "run " : ""
}${scriptName}`
);
}
}
stepNumber++;
}
} catch (error) {
// Ignore errors when reading package.json
}
}
}
// Final tips
console.log(t("common.checkReadme"));
console.log(t("init.goodLuck"));
} catch (error) {
if (error instanceof Error && error.message === "canceled") {
cancelOnce(1);
return; // cancelled; stop execution
}
console.error(t("common.error") + error.message.split("\n")[0]);
return;
}
}