@roboplay/sage
Version:
Codemod for Robo.js
168 lines (166 loc) • 6.11 kB
JavaScript
import path from 'node:path';
import { mkdirSync, createWriteStream } from 'node:fs';
import { pipeline, Readable } from 'node:stream';
import { promisify } from 'node:util';
import { readFile } from 'node:fs/promises';
import { logger } from './logger.js';
import { color } from './color.js';
import { FLASHCORE_KEYS } from 'robo.js/dist/core/constants.js';
import { spawn } from 'node:child_process';
import { Flashcore } from 'robo.js';
import { packageJson } from '../index.js';
import { select } from '@inquirer/prompts';
const pipelineAsync = promisify(pipeline);
const IS_WINDOWS = /^win/.test(process.platform);
async function checkSageUpdates(skipPrompt = false) {
logger.debug(`Checking for updates...`);
const response = await fetch(`https://registry.npmjs.org/${packageJson.name}/latest`);
const latestVersion = (await response.json()).version;
logger.debug(`Latest version on NPM Registry: ${latestVersion}`);
if (packageJson.version !== latestVersion) {
logger.info(color.green(`A new version of ${color.bold("@roboplay/sage")} is available! (v${latestVersion})
`));
if (skipPrompt) {
logger.debug(`Skipping prompt due to flag...`);
return;
}
const useLatest = await select({
message: "Would you like to use the latest version?",
choices: [
{ name: "Yes, use latest", value: true },
{ name: "No, stick with v" + packageJson.version, value: false }
]
});
logger.log("");
if (useLatest) {
const packageExecutor = getPackageExecutor();
let cliPackage = process.argv[1] ?? packageJson.name;
if (path.isAbsolute(cliPackage)) {
cliPackage = path.basename(cliPackage);
}
await exec(`${packageExecutor} ${cliPackage}@${packageJson.version} ${process.argv.slice(2).join(" ")}`.trim());
process.exit(0);
}
}
}
async function checkUpdates(packageJson2, config, forceCheck = false) {
const { updateCheckInterval = 60 * 60 } = config;
logger.debug(`Checking for updates for package.json:`, packageJson2);
const update = {
changelogUrl: "",
currentVersion: packageJson2.version,
hasUpdate: false,
latestVersion: ""
};
if (!forceCheck && updateCheckInterval <= 0) {
logger.debug(`Update check is disabled.`);
return update;
}
const lastUpdateCheck = await Flashcore.get(FLASHCORE_KEYS.lastUpdateCheck) ?? 0;
const now = Date.now();
const isDue = now - lastUpdateCheck > updateCheckInterval * 1e3;
logger.debug(`Update check from ${new Date(lastUpdateCheck).toISOString()} is due:`, isDue);
if (!forceCheck && !isDue) {
return update;
}
const response = await fetch(`https://registry.npmjs.org/${packageJson2.name}/latest`);
const latestVersion = (await response.json()).version;
update.hasUpdate = packageJson2.version !== latestVersion;
update.latestVersion = latestVersion;
if (packageJson2.repository?.url) {
logger.debug(`Getting changelog URL from repository URL...`, packageJson2.repository);
let changelogUrl = packageJson2.repository?.url;
changelogUrl = changelogUrl.replace(".git", "").replace("git+", "") + "/main";
if (packageJson2.repository.directory) {
changelogUrl += `/${packageJson2.repository.directory}`;
}
if (changelogUrl.includes("github.com")) {
changelogUrl = changelogUrl.replace("github.com", "raw.githubusercontent.com");
}
changelogUrl += "/CHANGELOG.md";
const changelogResponse = await fetch(changelogUrl);
if (!changelogResponse.ok) {
logger.debug(`Changelog URL does not exist:`, changelogUrl);
} else {
update.changelogUrl = changelogUrl;
}
}
await Flashcore.set(FLASHCORE_KEYS.lastUpdateCheck, now);
return update;
}
function createNodeReadable(webReadable) {
const reader = webReadable.getReader();
return new Readable({
async read() {
const { done, value } = await reader.read();
this.push(done ? null : value);
}
});
}
async function downloadFile(url, fileName) {
const response = await fetch(url);
if (!response.ok) {
throw new Error("Network response was not ok " + response.statusText);
}
mkdirSync(path.dirname(fileName), { recursive: true });
const fileStream = createWriteStream(fileName);
const nodeReadable = createNodeReadable(response.body);
await pipelineAsync(nodeReadable, fileStream);
}
function exec(command, options) {
return new Promise((resolve, reject) => {
logger.debug(`> ${color.bold(command)}`);
const args = command.split(" ");
const childProcess = spawn(args.shift(), args, {
env: { ...process.env, FORCE_COLOR: "1" },
shell: IS_WINDOWS,
stdio: "inherit",
...options ?? {}
});
childProcess.on("error", reject);
childProcess.on("close", (code) => {
if (code === 0) {
resolve();
} else {
reject(`Command exited with code ${code}`);
}
});
});
}
function getPackageManager() {
const userAgent = process.env.npm_config_user_agent;
if (userAgent?.startsWith("bun")) {
return "bun";
} else if (userAgent?.startsWith("yarn")) {
return "yarn";
} else if (userAgent?.startsWith("pnpm")) {
return "pnpm";
} else {
return "npm";
}
}
function getPackageExecutor() {
const packageManager = getPackageManager();
if (packageManager === "yarn") {
return "yarn dlx";
} else if (packageManager === "pnpm") {
return "pnpx";
} else if (packageManager === "bun") {
return "bunx";
} else {
return "npx";
}
}
async function isRoboProject(project = process.cwd()) {
try {
const packageJsonPath = path.join(project, "package.json");
const packageJson2 = JSON.parse(await readFile(packageJsonPath, "utf-8"));
return packageJson2.dependencies["robo.js"] || packageJson2.devDependencies["robo.js"];
} catch (e) {
logger.debug(`Not a Robo project:`, e);
return false;
}
}
export { IS_WINDOWS, checkSageUpdates, checkUpdates, createNodeReadable, downloadFile, exec, getPackageExecutor, getPackageManager, isRoboProject };
//# sourceMappingURL=out.js.map
//# sourceMappingURL=utils.js.map