import fs from "node:fs" import { fileURLToPath } from "node:url" import validateProjectName from "validate-npm-package-name" import { isExistingPath } from "../utils/isExistingPath.js" import { template } from "./Template.js" export interface ChallengeOptions { name: string } export interface GenerateChallengeOptions extends ChallengeOptions { githubUser: string } export class Challenge implements ChallengeOptions { public static BASE_URL = new URL("../../challenges/", import.meta.url) public name: string public path: string constructor(options: ChallengeOptions) { const { name } = options this.name = name this.path = fileURLToPath(new URL(`./${name}`, Challenge.BASE_URL)) } public static async getChallenges(): Promise { const challengeNames = await fs.promises.readdir(Challenge.BASE_URL) return challengeNames.map((challengeName) => { return new Challenge({ name: challengeName }) }) } public static async generate( options: GenerateChallengeOptions, ): Promise { const { name, githubUser } = options const challenge = new Challenge({ name }) if (await isExistingPath(challenge.path)) { throw new Error(`The challenge already exists: ${name}.`) } const isValidName = validateProjectName(name).validForNewPackages if (!isValidName) { throw new Error("Invalid challenge name.") } await fs.promises.mkdir(challenge.path) await template.challenge({ destination: challenge.path, githubUser, name, }) return challenge } }