Skip to content

Commit

Permalink
Merge pull request #314 from vikejs/small-improvements
Browse files Browse the repository at this point in the history
Small improvements
  • Loading branch information
magne4000 authored Jul 19, 2024
2 parents 2fa7ab1 + f0ffcb4 commit 788d71c
Show file tree
Hide file tree
Showing 15 changed files with 195 additions and 52 deletions.
13 changes: 10 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ jobs:

strategy:
matrix:
node: ["18", "20"]
os: [ubuntu-latest, windows-latest, macos-latest]
os: [ubuntu-latest, macos-latest, windows-latest]
node: [20]
include:
- os: ubuntu-latest
node: 18
- os: ubuntu-latest
node: 22
fail-fast: false

steps:
Expand All @@ -46,7 +51,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
name: Install bun
with:
bun-version: "1.1.17"
bun-version: "1.1.20"

- name: Get pnpm store directory
id: pnpm-cache
Expand All @@ -66,6 +71,8 @@ jobs:
${{ runner.os }}-pnpm-store-
- uses: actions/cache@v4
# REALLY slow on windows
if: matrix.os != 'windows-latest'
name: Setup bun cache
with:
path: ~/.bun/install/cache
Expand Down
10 changes: 8 additions & 2 deletions boilerplates/shared/files/$README.md.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { loadReadme, type TransformerProps } from "@batijs/core";
import { getArgs, getVersion, loadReadme, markdown, type TransformerProps } from "@batijs/core";

export default async function getReadme(props: TransformerProps) {
const content = await loadReadme(props);
const flags = Array.from(props.meta.BATI)
.filter((f) => (f as string) !== "force")
.map((f) => `--${f}`)
.join(" ");
const v = getVersion();

//language=Markdown
const intro = `This app has been created with [Bati](https://batijs.dev) using the following flags: \`${flags}\``;
const intro = `Generated with [Bati](https://batijs.dev) ${v ? `(${markdown.link("https://www.npmjs.com/package/@batijs/create-app/v/" + v.version, "version " + v.semver.at(-1))})` : ""} using this command:
\`\`\`sh
${getArgs()} ${flags}
\`\`\`
`;

content.addIntro(intro);

Expand Down
2 changes: 1 addition & 1 deletion doc/demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ records:
- delay: 250
content: "\e[?2004h$ \b\b"
- delay: 1500
content: "$ pnpm create @batijs/app --solid --tailwindcss --telefunc --eslint\r\n\e[?2004l\r"
content: "$ pnpm create bati --solid --tailwindcss --telefunc --eslint\r\n\e[?2004l\r"
- delay: 1808
content: "\e[1m\e[32m✓\e[39m Project created at \e[36mmy-app\e[39m with:\e[22m\r\n - \e[32mVike\e[39m\r\n - \e[32mSolidJS\e[39m\r\n - \e[32mTailwindCSS\e[39m\r\n - \e[32mTelefunc\e[39m\r\n - \e[32mESLint\e[39m\r\n\r\n\e[1m\e[94m→\e[39m Next steps:\e[22m\r\n \e[90m$\e[39m cd my-app\r\n \e[90m$\e[39m pnpm install\r\n \e[90m$\e[39m pnpm run dev\r\n"
- delay: 35
Expand Down
80 changes: 68 additions & 12 deletions packages/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { existsSync } from "node:fs";
import { exec as nodeExec } from "node:child_process";
import { access, constants, lstat, readdir, readFile } from "node:fs/promises";
import { dirname, join, parse } from "node:path";
import { fileURLToPath } from "node:url";
import exec, { walk } from "@batijs/build";
import { type VikeMeta, withIcon } from "@batijs/core";
import { packageManager, type VikeMeta, which, withIcon } from "@batijs/core";
import { type CategoryLabels, cliFlags, type Feature, features, type Flags } from "@batijs/features";
import { execRules } from "@batijs/features/rules";
import { type ArgsDef, type CommandDef, defineCommand, type ParsedArgs, runMain } from "citty";
import { blueBright, bold, cyan, gray, green, red, yellow } from "colorette";
import sift from "sift";
import whichPm from "which-pm-runs";
import packageJson from "./package.json";
import { type RuleMessage, rulesMessages } from "./rules.js";
import type { BoilerplateDef, Hook } from "./types.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const isWin = process.platform === "win32";
const pm = whichPm();
const pm = packageManager();

type FeatureOrCategory = Flags | CategoryLabels;

Expand Down Expand Up @@ -109,13 +109,17 @@ const defaultDef = {
type: "positional",
description: "Project directory",
required: false,
default: "my-app",
},
force: {
type: "boolean",
description: "If true, does no check if target directory already exists",
required: false,
},
["skip-git"]: {
type: "boolean",
description: "If true, does not execute `git init`",
required: false,
},
} as const satisfies ArgsDef;

type Args = typeof defaultDef &
Expand Down Expand Up @@ -146,11 +150,31 @@ export default function yn(value: unknown, default_?: boolean) {
return default_;
}

function generateRandomFilename(size: number) {
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
let result = "";
for (let i = 0; i < size; i++) {
// Pick a random character from the string and add it to the result
const randomIndex = Math.floor(Math.random() * chars.length);
result += chars[randomIndex];
}
return result;
}

async function checkArguments(args: ParsedArgs<Args>) {
const projectChosenByUser = Boolean(args.project);
if (!args.project) {
// Try to default to `my-app`, otherwise `my-app[randomString]`
args.project = "my-app";
}

if (existsSync(args.project)) {
// is target a directory
const stat = await lstat(args.project);
if (!stat.isDirectory()) {
if (!projectChosenByUser) {
args.project = `my-app-${generateRandomFilename(5)}`;
return;
} else if (!stat.isDirectory()) {
console.error(
`${yellow("⚠")} Target ${cyan(args.project)} already exists but is not a directory. ${yellow("Aborting")}.`,
);
Expand All @@ -170,13 +194,22 @@ async function checkArguments(args: ParsedArgs<Args>) {
}

// is target an empty directory
if (!args.force && (await readdir(args.project)).length > 0) {
console.error(
`${yellow("⚠")} Target folder ${cyan(
args.project,
)} already exists and is not empty.\n Continuing might erase existing files. ${yellow("Aborting")}.`,
);
process.exit(4);
if (!args.force) {
const isFolderEmpty = (await readdir(args.project)).length === 0;

if (!isFolderEmpty) {
if (!projectChosenByUser) {
args.project = `my-app-${generateRandomFilename(5)}`;
return;
} else {
console.error(
`${yellow("⚠")} Target folder ${cyan(
args.project,
)} already exists and is not empty.\n Continuing might erase existing files. ${yellow("Aborting")}.`,
);
process.exit(4);
}
}
}
}
}
Expand Down Expand Up @@ -245,6 +278,25 @@ function testFlags(flags: string[], bl: BoilerplateDef) {
return true;
}

async function gitInit(cwd: string) {
try {
const exists = which("git");
if (!exists) return;

await new Promise((resolve, reject) => {
nodeExec("git init", { cwd }, (err) => {
if (err) {
reject(err);
} else {
resolve(undefined);
}
});
});
} catch (e) {
console.warn(`${yellow("⚠")} failed to execute \`git init\` in destination folder. Skipping.`);
}
}

async function run() {
const dir = boilerplatesDir();
const boilerplates = await parseBoilerplates(dir);
Expand Down Expand Up @@ -309,6 +361,10 @@ async function run() {
meta,
);

if (!args["skip-git"]) {
await gitInit(args.project);
}

printOK(args.project, flags);

for (const onafter of hooksMap.get("after") ?? []) {
Expand Down
4 changes: 1 addition & 3 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"@batijs/compile": "workspace:*",
"@types/node": "^18.19.14",
"@types/which": "^3.0.4",
"@types/which-pm-runs": "^1.0.2",
"citty": "^0.1.6",
"colorette": "^2.0.20",
"esbuild": "^0.23.0",
Expand All @@ -28,8 +27,7 @@
"tsup": "^8.1.0",
"typescript": "^5.5.3",
"unplugin-purge-polyfills": "^0.0.4",
"vite": "^5.3.3",
"which-pm-runs": "^1.1.0"
"vite": "^5.3.3"
},
"dependencies": {
"@batijs/core": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export * from "./which.js";
export * from "./print.js";
export * from "./markdown.js";
export * from "./random.js";
export * from "./runtime.js";
export type * from "./types.js";
44 changes: 44 additions & 0 deletions packages/core/src/runtime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export function packageManager() {
if (!process.env.npm_config_user_agent) {
return undefined;
}
return pmFromUserAgent(process.env.npm_config_user_agent);
}

function pmFromUserAgent(userAgent: string) {
const pmSpec = userAgent.split(" ")[0];
const separatorPos = pmSpec.lastIndexOf("/");
const name = pmSpec.substring(0, separatorPos);
return {
name: name === "npminstall" ? "cnpm" : name,
version: pmSpec.substring(separatorPos + 1),
};
}

export function getArgs() {
const pm = packageManager()?.name;

switch (pm) {
case "pnpm":
return "pnpm create bati";
case "yarn":
return "yarn dlx @batijs/cli";
case "bun":
return "bun create bati";
default:
return "npm create bati --";
}
}

export function getVersion() {
const v = process.env.npm_package_version;

if (v) {
return {
version: v,
semver: v.split(".") as [string, string, string],
};
}

return;
}
29 changes: 29 additions & 0 deletions packages/create-bati/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<p align="center">
<img src="https://raw.githubusercontent.com/vikejs/bati/main/website/assets/logo.svg" height="150">
</p>

<h1 align="center">
Bâti
</h1>
<p align="center">
Next-gen scaffolder. Get started with fully-functional apps, and choose any tool you want.
<p>

<h3 align="center"><a href="https://batijs.dev">Try the CLI generator</a></h3>

![Demo](doc/demo.gif)

## Features
- <img src="https://api.iconify.design/fluent-emoji-flat:shopping-cart.svg?color=%23888888" width=16 height=16></img> Choose the features you need, with the libraries you want
- <img src="https://api.iconify.design/fluent-emoji-flat:card-file-box.svg?color=%23888888" width=16 height=16></img> Configuration files are tailored for the stack you choose
- <img src="https://api.iconify.design/fluent-emoji-flat:house.svg?color=%23888888" width=16 height=16></img> Ready to start
- <img src="https://api.iconify.design/logos:vitejs.svg?color=%23888888" width=16 height=16></img> [Vite](https://vitejs.dev) ecosystem
- <img src="https://api.iconify.design/logos:typescript-icon.svg?color=%23888888" width=16 height=16></img> Typescript with strict types
- <img src="https://api.iconify.design/logos:eslint.svg?color=%23888888" width=16 height=16></img> Follows ESLint recommendations
- <img src="https://vike.dev/icons/vike-square-gradient.svg" width=16 height=16></img> Based on [Vike](https://vike.dev) for portability and customazibility
- <img src="https://wintercg.org/static/logo.svg" width=16 height=16></img> Sane and future-proof recommendations based on [WinterCG](https://wintercg.org)
- <img src="https://api.iconify.design/fluent-emoji-flat:green-circle.svg?color=%23888888" width=16 height=16></img> Always up-to-date, with automated testing

<hr>

**Not seeing your favorite tool? [Manually integrate it](https://vike.dev/integration) and/or upvote it [here](https://github.com/vikejs/bati/discussions/categories/integration-request).**
2 changes: 2 additions & 0 deletions packages/create-bati/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
import "@batijs/cli";
19 changes: 19 additions & 0 deletions packages/create-bati/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "create-bati",
"version": "0.0.226",
"type": "module",
"scripts": {},
"keywords": [],
"description": "Next-gen scaffolder. Get started with fully-functional apps, and choose any tool you want",
"author": "Joël Charles <joel.charles91@gmail.com>",
"repository": "https://github.com/vikejs/bati",
"license": "MIT",
"bin": "./index.js",
"devDependencies": {},
"dependencies": {
"@batijs/cli": "workspace:*"
},
"files": [
"index.js"
]
}
10 changes: 1 addition & 9 deletions packages/tests/src/exec-bati.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,7 @@ export async function execLocalBati(context: GlobalContext, flags: string[], mon
// as we are also testing that the generated package dependencies are properly bundled.
await exec(
"npm",
[
"--registry",
"http://localhost:4873",
"create",
"@batijs/app@local",
"--",
...flags.map((f) => `--${f}`),
digest,
],
["--registry", "http://localhost:4873", "create", "bati@local", "--", ...flags.map((f) => `--${f}`), digest],
{
timeout: 15000,
cwd: monorepo ? join(context.tmpdir, "packages") : context.tmpdir,
Expand Down
Loading

0 comments on commit 788d71c

Please sign in to comment.