Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on Keep a Changelog and the project follows Semantic Version

## [Unreleased]

### Bug Fixes

- **create-rezi/cli**: Fixed `npm create rezi` / `bun create rezi` no-op scaffolding by making CLI main-entry detection symlink-safe.

## [0.1.0-alpha.58] - 2026-03-06
### Breaking Changes

Expand Down
38 changes: 38 additions & 0 deletions packages/create-rezi/src/__tests__/mainEntry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { mkdtemp, symlink, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { assert, test } from "@rezi-ui/testkit";
import { isMainModuleEntry } from "../mainEntry.js";

test("isMainModuleEntry returns true for direct script execution", async () => {
const root = await mkdtemp(join(tmpdir(), "rezi-main-entry-"));
const scriptPath = join(root, "create-rezi.mjs");
await writeFile(scriptPath, "export {};\n", "utf8");

const moduleUrl = pathToFileURL(scriptPath).href;
assert.equal(isMainModuleEntry(scriptPath, moduleUrl), true);
});

test("isMainModuleEntry resolves symlinked launchers", async () => {
const root = await mkdtemp(join(tmpdir(), "rezi-main-entry-"));
const scriptPath = join(root, "dist-index.mjs");
const launcherPath = join(root, "launcher.mjs");
await writeFile(scriptPath, "export {};\n", "utf8");
await symlink(scriptPath, launcherPath);

const moduleUrl = pathToFileURL(scriptPath).href;
assert.equal(isMainModuleEntry(launcherPath, moduleUrl), true);
});

test("isMainModuleEntry rejects non-matching entry paths", async () => {
const root = await mkdtemp(join(tmpdir(), "rezi-main-entry-"));
const scriptPath = join(root, "dist-index.mjs");
const otherPath = join(root, "other.mjs");
await writeFile(scriptPath, "export {};\n", "utf8");
await writeFile(otherPath, "export {};\n", "utf8");

const moduleUrl = pathToFileURL(scriptPath).href;
assert.equal(isMainModuleEntry(otherPath, moduleUrl), false);
assert.equal(isMainModuleEntry(undefined, moduleUrl), false);
});
4 changes: 2 additions & 2 deletions packages/create-rezi/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { spawnSync } from "node:child_process";
import { relative, resolve } from "node:path";
import { cwd, exit, stdin, stdout } from "node:process";
import { createInterface } from "node:readline/promises";
import { fileURLToPath } from "node:url";
import { isMainModuleEntry } from "./mainEntry.js";
import {
TEMPLATE_DEFINITIONS,
createProject,
Expand Down Expand Up @@ -276,7 +276,7 @@ async function main(): Promise<void> {
}
}

const isMain = process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1]);
const isMain = isMainModuleEntry(process.argv[1], import.meta.url);
if (isMain) {
main().catch((err) => {
stdout.write(`\ncreate-rezi error: ${err instanceof Error ? err.message : String(err)}\n`);
Expand Down
20 changes: 20 additions & 0 deletions packages/create-rezi/src/mainEntry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { realpathSync } from "node:fs";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";

function resolveCanonicalPath(pathValue: string): string {
try {
return realpathSync(pathValue);
} catch {
return pathValue;
}
}

export function isMainModuleEntry(argvPath: string | undefined, moduleUrl: string): boolean {
if (!argvPath) {
return false;
}
const modulePath = resolveCanonicalPath(fileURLToPath(moduleUrl));
const entryPath = resolveCanonicalPath(resolve(argvPath));
return modulePath === entryPath;
}
Loading