mirror of
https://github.com/hanzoai/shadcn.git
synced 2026-10-30 18:22:59 +00:00
* refactor: decouple @hanzo/ui from hanzogui Make @hanzo/ui shadcn-only — no hanzogui/Tamagui coupling. - remove primitives/bases (gui/admin/svelte/vue) re-exports - drop @hanzogui peerDependencies + peerDependenciesMeta entries - add check-no-hanzogui guard, wired into build - fix latent NodeJS.Timeout types to keep the build green * refactor: remove duplicate @hanzo/brand from the monorepo @hanzo/brand is owned by the standalone hanzoai/brand (the npm-canonical source); this monorepo's copy was unused and had drifted. - delete pkg/brand - add check-no-brand-pkg guard (wired into `check`) so it can't reappear * refactor(ui): stop importing from the app; use own cn util pkg/ui pulled `cn` from @/lib/utils (../../app) — an inverted dependency on the consuming app. Point the animation components at pkg/ui's own cn and drop the @/app, @/registry, @/lib tsconfig path aliases. * fix(ui): type errors; stop tracking the root lockfile - ModelCard: lucide-react dropped the Github icon → use Code - drawer: annotate DrawerTrigger/DrawerClose (radix type portability) - untrack root pnpm-lock.yaml; CI → --no-frozen-lockfile * release: bump @hanzo/ui to 5.7.0 * refactor: rename pkg/ → pkgs/, merge packages/ into it standardize on 'pkgs/': move pkg/* and packages/* into pkgs/. Update workspace globs, CI, scripts, and config references accordingly.
228 lines
7.0 KiB
JavaScript
228 lines
7.0 KiB
JavaScript
const { execSync } = require("node:child_process");
|
|
const crypto = require("node:crypto");
|
|
const fs = require("node:fs/promises");
|
|
const path = require("node:path");
|
|
|
|
const toml = require("@iarna/toml");
|
|
const PackageJson = require("@npmcli/package-json");
|
|
const semver = require("semver");
|
|
|
|
const cleanupCypressFiles = ({ fileEntries, packageManager }) =>
|
|
fileEntries.flatMap(([filePath, content]) => {
|
|
const newContent = content.replace(
|
|
new RegExp("npx ts-node", "g"),
|
|
packageManager.name === "bun" ? "bun" : `${packageManager.exec} ts-node`,
|
|
);
|
|
|
|
return [fs.writeFile(filePath, newContent)];
|
|
});
|
|
|
|
const escapeRegExp = (string) =>
|
|
// $& means the whole matched string
|
|
string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
|
|
const getPackageManagerCommand = (packageManager) =>
|
|
// Inspired by https://github.com/nrwl/nx/blob/bd9b33eaef0393d01f747ea9a2ac5d2ca1fb87c6/packages/nx/src/utils/package-manager.ts#L38-L103
|
|
({
|
|
bun: () => ({
|
|
exec: "bunx",
|
|
lockfile: "bun.lockb",
|
|
name: "bun",
|
|
run: (script, args) => `bun run ${script} ${args || ""}`,
|
|
}),
|
|
npm: () => ({
|
|
exec: "npx",
|
|
lockfile: "package-lock.json",
|
|
name: "npm",
|
|
run: (script, args) => `npm run ${script} ${args ? `-- ${args}` : ""}`,
|
|
}),
|
|
pnpm: () => {
|
|
const pnpmVersion = getPackageManagerVersion("pnpm");
|
|
const includeDoubleDashBeforeArgs = semver.lt(pnpmVersion, "7.0.0");
|
|
const useExec = semver.gte(pnpmVersion, "6.13.0");
|
|
|
|
return {
|
|
exec: useExec ? "pnpm exec" : "pnpx",
|
|
lockfile: "pnpm-lock.yaml",
|
|
name: "pnpm",
|
|
run: (script, args) =>
|
|
includeDoubleDashBeforeArgs
|
|
? `pnpm run ${script} ${args ? `-- ${args}` : ""}`
|
|
: `pnpm run ${script} ${args || ""}`,
|
|
};
|
|
},
|
|
yarn: () => ({
|
|
exec: "yarn",
|
|
lockfile: "yarn.lock",
|
|
name: "yarn",
|
|
run: (script, args) => `yarn ${script} ${args || ""}`,
|
|
}),
|
|
})[packageManager]();
|
|
|
|
const getPackageManagerVersion = (packageManager) =>
|
|
// Copied over from https://github.com/nrwl/nx/blob/bd9b33eaef0393d01f747ea9a2ac5d2ca1fb87c6/packages/nx/src/utils/package-manager.ts#L105-L114
|
|
execSync(`${packageManager} --version`).toString("utf-8").trim();
|
|
|
|
const getRandomString = (length) => crypto.randomBytes(length).toString("hex");
|
|
|
|
const removeUnusedDependencies = (dependencies, unusedDependencies) =>
|
|
Object.fromEntries(
|
|
Object.entries(dependencies).filter(
|
|
([key]) => !unusedDependencies.includes(key),
|
|
),
|
|
);
|
|
|
|
const updatePackageJson = ({ APP_NAME, packageJson, packageManager }) => {
|
|
const {
|
|
devDependencies,
|
|
prisma: { seed: prismaSeed, ...prisma },
|
|
scripts: {
|
|
// eslint-disable-next-line no-unused-vars
|
|
"format:repo": _repoFormatScript,
|
|
...scripts
|
|
},
|
|
} = packageJson.content;
|
|
|
|
packageJson.update({
|
|
name: APP_NAME,
|
|
devDependencies:
|
|
packageManager.name === "bun"
|
|
? removeUnusedDependencies(devDependencies, ["ts-node"])
|
|
: devDependencies,
|
|
prisma: {
|
|
...prisma,
|
|
seed:
|
|
packageManager.name === "bun"
|
|
? prismaSeed.replace("ts-node", "bun")
|
|
: prismaSeed,
|
|
},
|
|
scripts,
|
|
});
|
|
};
|
|
|
|
const main = async ({ packageManager, rootDirectory }) => {
|
|
const pm = getPackageManagerCommand(packageManager);
|
|
|
|
const README_PATH = path.join(rootDirectory, "README.md");
|
|
const FLY_TOML_PATH = path.join(rootDirectory, "fly.toml");
|
|
const EXAMPLE_ENV_PATH = path.join(rootDirectory, ".env.example");
|
|
const ENV_PATH = path.join(rootDirectory, ".env");
|
|
const DOCKERFILE_PATH = path.join(rootDirectory, "Dockerfile");
|
|
const CYPRESS_SUPPORT_PATH = path.join(rootDirectory, "cypress", "support");
|
|
const CYPRESS_COMMANDS_PATH = path.join(CYPRESS_SUPPORT_PATH, "commands.ts");
|
|
const CREATE_USER_COMMAND_PATH = path.join(
|
|
CYPRESS_SUPPORT_PATH,
|
|
"create-user.ts",
|
|
);
|
|
const DELETE_USER_COMMAND_PATH = path.join(
|
|
CYPRESS_SUPPORT_PATH,
|
|
"delete-user.ts",
|
|
);
|
|
|
|
const REPLACER = "indie-stack-template";
|
|
|
|
const DIR_NAME = path.basename(rootDirectory);
|
|
const SUFFIX = getRandomString(2);
|
|
|
|
const APP_NAME = (DIR_NAME + "-" + SUFFIX)
|
|
// get rid of anything that's not allowed in an app name
|
|
.replace(/[^a-zA-Z0-9-_]/g, "-");
|
|
|
|
const [
|
|
prodContent,
|
|
readme,
|
|
env,
|
|
dockerfile,
|
|
cypressCommands,
|
|
createUserCommand,
|
|
deleteUserCommand,
|
|
packageJson,
|
|
] = await Promise.all([
|
|
fs.readFile(FLY_TOML_PATH, "utf-8"),
|
|
fs.readFile(README_PATH, "utf-8"),
|
|
fs.readFile(EXAMPLE_ENV_PATH, "utf-8"),
|
|
fs.readFile(DOCKERFILE_PATH, "utf-8"),
|
|
fs.readFile(CYPRESS_COMMANDS_PATH, "utf-8"),
|
|
fs.readFile(CREATE_USER_COMMAND_PATH, "utf-8"),
|
|
fs.readFile(DELETE_USER_COMMAND_PATH, "utf-8"),
|
|
PackageJson.load(rootDirectory),
|
|
]);
|
|
|
|
const newEnv = env.replace(
|
|
/^SESSION_SECRET=.*$/m,
|
|
`SESSION_SECRET="${getRandomString(16)}"`,
|
|
);
|
|
|
|
const prodToml = toml.parse(prodContent);
|
|
prodToml.app = prodToml.app.replace(REPLACER, APP_NAME);
|
|
|
|
const initInstructions = `
|
|
- First run this stack's \`remix.init\` script and commit the changes it makes to your project.
|
|
|
|
\`\`\`sh
|
|
npx remix init
|
|
git init # if you haven't already
|
|
git add .
|
|
git commit -m "Initialize project"
|
|
\`\`\`
|
|
`;
|
|
|
|
const newReadme = readme
|
|
.replace(new RegExp(escapeRegExp(REPLACER), "g"), APP_NAME)
|
|
.replace(initInstructions, "");
|
|
|
|
const newDockerfile = pm.lockfile
|
|
? dockerfile.replace(
|
|
new RegExp(escapeRegExp("ADD package.json"), "g"),
|
|
`ADD package.json ${pm.lockfile}`,
|
|
)
|
|
: dockerfile;
|
|
|
|
updatePackageJson({ APP_NAME, packageJson, packageManager: pm });
|
|
|
|
await Promise.all([
|
|
fs.writeFile(FLY_TOML_PATH, toml.stringify(prodToml)),
|
|
fs.writeFile(README_PATH, newReadme),
|
|
fs.writeFile(ENV_PATH, newEnv),
|
|
fs.writeFile(DOCKERFILE_PATH, newDockerfile),
|
|
...cleanupCypressFiles({
|
|
fileEntries: [
|
|
[CYPRESS_COMMANDS_PATH, cypressCommands],
|
|
[CREATE_USER_COMMAND_PATH, createUserCommand],
|
|
[DELETE_USER_COMMAND_PATH, deleteUserCommand],
|
|
],
|
|
packageManager: pm,
|
|
}),
|
|
packageJson.save(),
|
|
fs.copyFile(
|
|
path.join(rootDirectory, "remix.init", "gitignore"),
|
|
path.join(rootDirectory, ".gitignore"),
|
|
),
|
|
fs.rm(path.join(rootDirectory, ".github", "ISSUE_TEMPLATE"), {
|
|
recursive: true,
|
|
}),
|
|
fs.rm(path.join(rootDirectory, ".github", "workflows", "format-repo.yml")),
|
|
fs.rm(path.join(rootDirectory, ".github", "workflows", "lint-repo.yml")),
|
|
fs.rm(path.join(rootDirectory, ".github", "workflows", "no-response.yml")),
|
|
fs.rm(path.join(rootDirectory, ".github", "dependabot.yml")),
|
|
fs.rm(path.join(rootDirectory, ".github", "PULL_REQUEST_TEMPLATE.md")),
|
|
fs.rm(path.join(rootDirectory, "LICENSE.md")),
|
|
]);
|
|
|
|
execSync(pm.run("setup"), { cwd: rootDirectory, stdio: "inherit" });
|
|
|
|
execSync(pm.run("format", "--log-level warn"), {
|
|
cwd: rootDirectory,
|
|
stdio: "inherit",
|
|
});
|
|
|
|
console.log(
|
|
`Setup is complete. You're now ready to rock and roll 🤘
|
|
|
|
Start development with \`${pm.run("dev")}\`
|
|
`.trim(),
|
|
);
|
|
};
|
|
|
|
module.exports = main;
|