From e02f03e7739621de0754bf49b849842af628d9b0 Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Sat, 9 Dec 2023 22:44:49 +0100 Subject: [PATCH 1/2] Add ts-check and fix a small bug --- index.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.mjs b/index.mjs index 89b0f9e..5068a68 100755 --- a/index.mjs +++ b/index.mjs @@ -1,4 +1,5 @@ #!/usr/bin/env node +// @ts-check import * as p from "@clack/prompts"; import path from "path"; @@ -120,9 +121,9 @@ https://www.rescript-lang.org\n\nCreate a new ReScript 11 project with modern de }); checkCancel(templateName); - try { - const s = p.spinner(); + const s = p.spinner(); + try { s.start("Loading available versions..."); const [rescriptVersions, rescriptCoreVersions] = await Promise.all([ getPackageVersions("rescript", rescriptVersionRange), From 29f23fcc2baf546ebca5d1d02378290b1bd3369c Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Sat, 9 Dec 2023 22:45:25 +0100 Subject: [PATCH 2/2] Add-to-existing-project mode --- index.mjs | 123 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 113 insertions(+), 10 deletions(-) diff --git a/index.mjs b/index.mjs index 5068a68..d24395a 100755 --- a/index.mjs +++ b/index.mjs @@ -4,6 +4,7 @@ import * as p from "@clack/prompts"; import path from "path"; import fs from "fs"; +import os from "os"; import { fileURLToPath } from "url"; import { exec } from "child_process"; import { promisify } from "util"; @@ -78,10 +79,15 @@ async function updatePackageJson(projectName) { ); } -async function updateRescriptJson(projectName) { +async function updateRescriptJson(projectName, sourceDir) { await updateFile("rescript.json", contents => { const config = JSON.parse(contents); config["name"] = projectName; + + if (sourceDir) { + config["sources"]["dir"] = sourceDir; + } + return JSON.stringify(config, null, 2); }); } @@ -96,18 +102,94 @@ function getVersion() { return JSON.parse(contents).version; } -async function main() { - console.clear(); +function getProjectPackageJson() { + const packageJsonPath = path.join(process.cwd(), "package.json"); + const contents = fs.readFileSync(packageJsonPath, "utf8"); + return JSON.parse(contents); +} - p.intro(c.dim("create-rescript-app " + getVersion())); +async function addToExistingProject() { + const projectName = getProjectPackageJson().name; - p.note( - `${c.cyan("Fast, Simple, Fully Typed JavaScript from the Future")} -https://www.rescript-lang.org\n\nCreate a new ReScript 11 project with modern defaults -("Core" standard library, JSX 4 automatic mode)`, - "Welcome to ReScript!" - ); + const templatePath = path.join(__dirname, "templates", "rescript-template-basic"); + const projectPath = process.cwd(); + const gitignorePath = path.join(projectPath, ".gitignore"); + + const s = p.spinner(); + + try { + const addToProj = await p.confirm({ + message: `Detected a package.json file. Do you want to add ReScript to "${projectName}"?`, + }); + checkCancel(addToProj); + + s.start("Loading available versions..."); + const [rescriptVersions, rescriptCoreVersions] = await Promise.all([ + getPackageVersions("rescript", rescriptVersionRange), + getPackageVersions("@rescript/core", rescriptCoreVersionRange), + ]); + s.stop("Versions loaded."); + const rescriptVersion = await p.select({ + message: "ReScript version?", + options: rescriptVersions.map(v => ({ value: v })), + }); + checkCancel(rescriptVersion); + + const rescriptCoreVersion = await p.select({ + message: "ReScript Core version?", + options: rescriptCoreVersions.map(v => ({ value: v })), + }); + checkCancel(rescriptCoreVersion); + + const sourceDir = await p.text({ + message: "Where will you put your ReScript source files?", + defaultValue: "src", + placeholder: "src", + initialValue: "src", + }); + checkCancel(sourceDir); + + await fs.promises.copyFile( + path.join(templatePath, "rescript.json"), + path.join(projectPath, "rescript.json") + ); + + if (fs.existsSync(gitignorePath)) { + await fs.promises.appendFile(gitignorePath, "/lib/" + os.EOL + ".bsb.lock" + os.EOL); + } + + await updateRescriptJson(projectName, sourceDir); + + const sourceDirPath = path.join(projectPath, sourceDir); + + if (!fs.existsSync(sourceDirPath)) { + fs.mkdirSync(sourceDirPath); + } + + await fs.promises.copyFile( + path.join(templatePath, "src", "Demo.res"), + path.join(sourceDirPath, "Demo.res") + ); + + const packages = [`rescript@${rescriptVersion}`, `@rescript/core@${rescriptCoreVersion}`]; + + await promisify(exec)("npm add " + packages.join(" ")); + + s.stop("Added ReScript to your project."); + p.note(`cd ${projectName}\nnpm run res:dev`, "Next steps"); + p.outro(`Happy hacking!`); + } catch (error) { + console.warn(error); + s.stop("Installation error."); + + p.outro(`Adding ReScript to project failed.`); + + p.log.error(error); + } +} + +async function createNewProject() { const projectName = await p.text({ message: "What is the name of your new ReScript project?", placeholder: process.argv[2] || "my-rescript-app", @@ -176,4 +258,25 @@ Change to the ${c.cyan(projectName)} folder and view ${c.cyan("README.md")} for } } +async function main() { + console.clear(); + + p.intro(c.dim("create-rescript-app " + getVersion())); + + p.note( + `${c.cyan("Fast, Simple, Fully Typed JavaScript from the Future")} +https://www.rescript-lang.org\n\nCreate a new ReScript 11 project with modern defaults +("Core" standard library, JSX 4 automatic mode)`, + "Welcome to ReScript!" + ); + + const existingPackageJson = fs.existsSync(path.join(process.cwd(), "package.json")); + + if (existingPackageJson) { + addToExistingProject(); + } else { + createNewProject(); + } +} + main();