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
68 changes: 68 additions & 0 deletions .github/workflows/tests-entry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ jobs:
- solid--daisyui--eslint--biome--oxlint
- react--daisyui--eslint--biome--oxlint
- vue--daisyui--eslint--biome--oxlint
- react--h3--auth0--cloudflare--eslint--biome--oxlint
- react--hono--auth0--cloudflare--eslint--biome--oxlint
- solid--express--authjs--eslint--biome--oxlint
- react--express--authjs--eslint--biome--oxlint
- vue--express--authjs--eslint--biome--oxlint
Expand All @@ -106,6 +108,18 @@ jobs:
- solid--fastify--authjs--eslint--biome--oxlint
- react--fastify--authjs--eslint--biome--oxlint
- vue--fastify--authjs--eslint--biome--oxlint
- solid--express--auth0--eslint--biome--oxlint
- react--express--auth0--eslint--biome--oxlint
- vue--express--auth0--eslint--biome--oxlint
- solid--h3--auth0--eslint--biome--oxlint
- react--h3--auth0--eslint--biome--oxlint
- vue--h3--auth0--eslint--biome--oxlint
- solid--hono--auth0--eslint--biome--oxlint
- react--hono--auth0--eslint--biome--oxlint
- vue--hono--auth0--eslint--biome--oxlint
- solid--fastify--auth0--eslint--biome--oxlint
- react--fastify--auth0--eslint--biome--oxlint
- vue--fastify--auth0--eslint--biome--oxlint
- solid--h3--trpc--drizzle--cloudflare--eslint--biome--oxlint
- solid--hono--trpc--drizzle--cloudflare--eslint--biome--oxlint
- solid--h3--telefunc--drizzle--cloudflare--eslint--biome--oxlint
Expand Down Expand Up @@ -223,6 +237,9 @@ jobs:
- sentry--solid--eslint--biome--oxlint
- sentry--react--eslint--biome--oxlint
- sentry--vue--eslint--biome--oxlint
- solid--storybook--eslint
- react--storybook--eslint
- vue--storybook--eslint
- react--vercel--hono--eslint--biome--oxlint
- react--vercel--h3--eslint--biome--oxlint
- react--vercel--express--eslint--biome--oxlint
Expand Down Expand Up @@ -280,6 +297,12 @@ jobs:
- destination: vue--daisyui--eslint--biome--oxlint
flags: --vue --daisyui --eslint --biome --oxlint
test-files: FRAMEWORK+CSS.spec.ts
- destination: react--h3--auth0--cloudflare--eslint--biome--oxlint
flags: --react --h3 --auth0 --cloudflare --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: react--hono--auth0--cloudflare--eslint--biome--oxlint
flags: --react --hono --auth0 --cloudflare --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: solid--express--authjs--eslint--biome--oxlint
flags: --solid --express --authjs --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
Expand Down Expand Up @@ -316,6 +339,42 @@ jobs:
- destination: vue--fastify--authjs--eslint--biome--oxlint
flags: --vue --fastify --authjs --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: solid--express--auth0--eslint--biome--oxlint
flags: --solid --express --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: react--express--auth0--eslint--biome--oxlint
flags: --react --express --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: vue--express--auth0--eslint--biome--oxlint
flags: --vue --express --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: solid--h3--auth0--eslint--biome--oxlint
flags: --solid --h3 --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: react--h3--auth0--eslint--biome--oxlint
flags: --react --h3 --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: vue--h3--auth0--eslint--biome--oxlint
flags: --vue --h3 --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: solid--hono--auth0--eslint--biome--oxlint
flags: --solid --hono --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: react--hono--auth0--eslint--biome--oxlint
flags: --react --hono --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: vue--hono--auth0--eslint--biome--oxlint
flags: --vue --hono --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: solid--fastify--auth0--eslint--biome--oxlint
flags: --solid --fastify --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: react--fastify--auth0--eslint--biome--oxlint
flags: --react --fastify --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: vue--fastify--auth0--eslint--biome--oxlint
flags: --vue --fastify --auth0 --eslint --biome --oxlint
test-files: FRAMEWORK+SERVER+AUTH.spec.ts
- destination: solid--h3--trpc--drizzle--cloudflare--eslint--biome--oxlint
flags: --solid --h3 --trpc --drizzle --cloudflare --eslint --biome
--oxlint
Expand Down Expand Up @@ -683,6 +742,15 @@ jobs:
- destination: sentry--vue--eslint--biome--oxlint
flags: --sentry --vue --eslint --biome --oxlint
test-files: FRAMEWORK+sentry.spec.ts
- destination: solid--storybook--eslint
flags: --solid --storybook --eslint
test-files: FRAMEWORK+storybook.spec.ts
- destination: react--storybook--eslint
flags: --react --storybook --eslint
test-files: FRAMEWORK+storybook.spec.ts
- destination: vue--storybook--eslint
flags: --vue --storybook --eslint
test-files: FRAMEWORK+storybook.spec.ts
- destination: react--vercel--hono--eslint--biome--oxlint
flags: --react --vercel --hono --eslint --biome --oxlint
test-files: FRAMEWORK+vercel.spec.ts
Expand Down
13 changes: 8 additions & 5 deletions boilerplates/drizzle/files/database/drizzle/queries/todos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ export function insertTodo(
return db.insert(todoTable).values({ text });
}

export function getAllTodos(
db: BATI.If<{
"!BATI.hasD1": ReturnType<typeof dbSqlite>;
_: ReturnType<typeof dbD1>;
}>,
export async function getAllTodos(
db: BATI.If<
{
"!BATI.hasD1": ReturnType<typeof dbSqlite>;
_: ReturnType<typeof dbD1>;
},
"union"
>,
) {
return db.select().from(todoTable).all();
}
2 changes: 2 additions & 0 deletions boilerplates/eslint/files/eslint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export default tseslint.config(
"cdk.out/*",
//# BATI.has("cloudflare")
"worker-configuration.d.ts",
//# BATI.has("storybook")
"stories/*",
// JS files at the root of the project
"*.js",
"*.cjs",
Expand Down
2 changes: 1 addition & 1 deletion boilerplates/shared-todo/files/pages/todo/+data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type Data = Awaited<ReturnType<typeof data>>;

export async function data(_pageContext: PageContextServer) {
if (BATI.has("drizzle")) {
const todoItemsInitial = drizzleQueries.getAllTodos(_pageContext.db);
const todoItemsInitial = await drizzleQueries.getAllTodos(_pageContext.db);

return { todoItemsInitial };
} else if (BATI.has("sqlite") && !BATI.hasD1) {
Expand Down
18 changes: 18 additions & 0 deletions boilerplates/storybook/bati.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineConfig } from "@batijs/core/config";

export default defineConfig({
if(meta) {
return meta.BATI.has("storybook");
},
nextSteps(_meta, packageManager) {
return [
{
type: "command",
step: `${packageManager} storybook`,
},
];
},
knip: {
ignoreDependencies: ["playwright", "@vitest/coverage-v8"],
},
});
27 changes: 27 additions & 0 deletions boilerplates/storybook/hooks/after.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { execSync } from "node:child_process";
import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import type { VikeMeta } from "@batijs/core";
import { packageManager } from "@batijs/core";

export default async function onafter(cwd: string, meta: VikeMeta) {
const isInteractive = !meta.BATI_IS_CI && !meta.BATI_TEST;
const pm = packageManager();
const command = `${pm.exec} storybook@latest init --skip-install --no-dev${isInteractive ? "" : " --yes"}`;
execSync(command, { cwd, stdio: "inherit" });

if (!isInteractive && meta.BATI.has("solid")) {
// SolidJS typings are not correct
await replaceInFile(
join(cwd, "stories/Page.stories.ts"),
"type Story = StoryObj<typeof meta>;",
"type Story = StoryObj<Omit<typeof meta, 'component'>>;",
);
}
}

async function replaceInFile(path: string, searchValue: string, replaceValue: string) {
let content = await readFile(path, "utf8");
content = content.replace(searchValue, replaceValue);
await writeFile(path, content, "utf8");
}
24 changes: 24 additions & 0 deletions boilerplates/storybook/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@batijs/storybook",
"private": true,
"version": "0.0.1",
"description": "",
"type": "module",
"scripts": {
"check-types": "tsc --noEmit",
"build": "bati-compile-boilerplate"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@batijs/compile": "workspace:*",
"@types/node": "^20.19.37"
},
"dependencies": {
"@batijs/core": "workspace:*"
},
"files": [
"dist/"
]
}
8 changes: 8 additions & 0 deletions boilerplates/storybook/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": ["../tsconfig.base.json"],
"compilerOptions": {
"types": ["@types/node", "@batijs/core/types"],
"lib": ["DOM", "DOM.Iterable", "ES2022"],
"baseUrl": "."
}
}
15 changes: 11 additions & 4 deletions packages/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,16 @@ function checkRules(flags: string[]) {
}
}

async function retrieveHooks(hooks: string[]): Promise<Map<"after", Hook[]>> {
async function retrieveHooks(hooks: Map<BoilerplateDefWithConfig, string>): Promise<Map<"after", Hook[]>> {
const map = new Map<"after", Hook[]>();
for (const hook of hooks) {
const sortedHooks = Array.from(hooks.entries()).sort(([b1], [b2]) => {
if (b1.config.enforce === "pre") return 1;
if (b1.config.enforce === "post") return -1;
if (b2.config.enforce === "pre") return -1;
if (b2.config.enforce === "post") return 1;
return 0;
});
for (const [, hook] of sortedHooks) {
for await (const file of walk(hook)) {
const parsed = parse(file);
const importFile = isWin ? `file://${file}` : file;
Expand Down Expand Up @@ -512,7 +519,7 @@ async function run() {
const args = await checkArguments(commandContext.args);

const sources: string[] = [];
const hooks: string[] = [];
const hooks = new Map<BoilerplateDefWithConfig, string>();
const flags = [
...new Set(
Object.entries(args)
Expand Down Expand Up @@ -556,7 +563,7 @@ async function run() {
sources.push(join(dir, bl.folder, "files"));
}
if (bl.subfolders.includes("hooks")) {
hooks.push(join(dir, bl.folder, "hooks"));
hooks.set(bl, join(dir, bl.folder, "hooks"));
}
}

Expand Down
3 changes: 3 additions & 0 deletions packages/cli/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,7 @@ Choose one of them or remove selected Server`,
`${inverse(bold("shadcn/ui"))} integration is tied to ${inverse(bold("TailwindCSS"))}. Using another CSS library with it may have unpredictable behaviour.`,
),
[RulesMessage.INFO_STACKBLITZ_COMPAT]: null,
[RulesMessage.ERROR_STORYBOOK_R_UI_FRAMEWORK]: error(
`${inverse(bold("Storybook"))} is only supported with ${inverse(bold("React"))}, ${inverse(bold("Vue"))}, or ${inverse(bold("Solid"))}`,
),
} satisfies Record<RulesMessage, RuleMessage | null>;
1 change: 1 addition & 0 deletions packages/cli/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@batijs/solid#build",
"@batijs/solid-sentry#build",
"@batijs/sqlite#build",
"@batijs/storybook#build",
"@batijs/tailwindcss#build",
"@batijs/telefunc#build",
"@batijs/trpc#build",
Expand Down
5 changes: 5 additions & 0 deletions packages/features/src/categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ tailored for Vike.`,
group: categoriesGroups.Utilities,
description: `Coming soon: Error Tracking solution for frontend and backend`,
},
{
label: "Tooling",
group: categoriesGroups.Utilities,
description: `Additional tooling to improve your developer experience.`,
},
] as const satisfies ReadonlyArray<Category>;

export type CategoryLabels = (typeof categories)[number]["label"];
18 changes: 18 additions & 0 deletions packages/features/src/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,24 @@ export const features = [
url: "https://logrocket.com",
disabled: true,
},

// Tooling
{
category: "Tooling",
label: "Storybook",
flag: "storybook",
image:
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDY0IDY0Ij48dGl0bGU+aWNvbi1zdG9yeWJvb2stc3F1YXJlPC90aXRsZT48ZGVmcz48cGF0aCBpZD0icGF0aC0xIiBkPSJNMS45NDY0OTk1NSw1Ny4xMzA5NDcyIEwwLjAwMjI1OTczMTE2LDUuOTU0NzY2NjMgQy0wLjA2MTk1MDg4MzMsNC4yNjQ2MTgxNCAxLjI0OTkyMjg4LDIuODMyMjM2OTcgMi45NTg3MTUxOSwyLjcyNjczNDE4IEw0Ny4wMjI2NTM4LDAuMDA2MTc2Mjg0OTEgQzQ4Ljc2MjAwMDUsLTAuMTAxMjEyOTYgNTAuMjYwMTQ1OCwxLjIwNDYyOTggNTAuMzY4ODU1LDIuOTIyODU3NzEgQzUwLjM3Mjk1MDUsMi45ODc1OTM5MSA1MC4zNzUsMy4wNTI0NDA2MyA1MC4zNzUsMy4xMTczMDMxNSBMNTAuMzc1LDU4Ljg4MjgwMjggQzUwLjM3NSw2MC42MDQzODMxIDQ4Ljk2MjIyOTYsNjIgNDcuMjE5NDg5NCw2MiBDNDcuMTcyMjc3Niw2MiA0Ny4xMjUwNzIxLDYxLjk5ODk1MzQgNDcuMDc3OTA4LDYxLjk5Njg2MDYgTDQuOTU4MjA5MDQsNjAuMTI4MDk5NyBDMy4zMTc4MTMzMyw2MC4wNTUzMTg5IDIuMDA4MDgyMDMsNTguNzUxOTE4IDEuOTQ2NDk5NTUsNTcuMTMwOTQ3MiBaIi8+PC9kZWZzPjxnIGlkPSJpY29uLXN0b3J5Ym9vay1zcXVhcmUiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiPjxnIGlkPSJpY29uIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg3LjAwMDAwMCwgMS4wMDAwMDApIj48cGF0aCBpZD0iQ29tYmluZWQtU2hhcGUiIGZpbGw9IiNGRjQ3ODUiIGZpbGwtcnVsZT0ibm9uemVybyIgZD0iTTUwLjM2ODg1NSwyLjkyMjg1NzcxIEM1MC4zNzI5NTA1LDIuOTg3NTkzOTEgNTAuMzc1LDMuMDUyNDQwNjMgNTAuMzc1LDMuMTE3MzAzMTUgTDUwLjM3NSw1OC44ODI4MDI4IEM1MC4zNzUsNjAuNjA0MzgzMSA0OC45NjIyMjk2LDYyIDQ3LjIxOTQ4OTQsNjIgQzQ3LjE3MjI3NzYsNjIgNDcuMTI1MDcyMSw2MS45OTg5NTM0IDQ3LjA3NzkwOCw2MS45OTY4NjA2IEw0Ljk1ODIwOTA0LDYwLjEyODA5OTcgQzMuMzE3ODEzMzMsNjAuMDU1MzE4OSAyLjAwODA4MjAzLDU4Ljc1MTkxOCAxLjk0NjQ5OTU1LDU3LjEzMDk0NzIgTDAuMDAyMjU5NzMxMTYsNS45NTQ3NjY2MyBDLTAuMDYxOTUwODgzMyw0LjI2NDYxODE0IDEuMjQ5OTIyODgsMi44MzIyMzY5NyAyLjk1ODcxNTE5LDIuNzI2NzM0MTggTDM3LjQ5OSwwLjU5NCBMMzcuMTk4MTMyNCw3LjYyMDc4NzY2IEMzNy4xOTQ3MjI3LDcuNzAxNzk2NjQgMzcuMjEyODIyNCw3Ljc4MTc4NzMxIDM3LjI0OTk4NjksNy44NTMwNTUyNSBMMzcuMjkzNDE1OCw3LjkyMTEzMDI2IEMzNy40NTA1Mjk2LDguMTI1NzM2MzcgMzcuNzQ1ODAwMiw4LjE2NTc4Mjg4IDM3Ljk1MjkyMDksOC4wMTA1NzY3IEwzNy45NTI5MjA5LDguMDEwNTc2NyBMNDAuNzE1ODE5NSw1Ljk0MDE5Njc4IEw0My4wNDkzOTY1LDcuNzU2MTg1MzcgQzQzLjEzNjgzODgsNy44MjQyMzI3OSA0My4yNDU4NjM0LDcuODU5NDY1ODQgNDMuMzU3MTEwNiw3Ljg1NTYyODEzIEM0My42MTY5MjEzLDcuODQ2NjY1NTMgNDMuODIwMTg0NCw3LjYzMTMzOTEgNDMuODExMTExNSw3LjM3NDY4MzE2IEw0My44MTExMTE1LDcuMzc0NjgzMTYgTDQzLjU1LDAuMjIgTDQ3LjAyMjY1MzgsMC4wMDYxNzYyODQ5MSBDNDguNzYyMDAwNSwtMC4xMDEyMTI5NiA1MC4yNjAxNDU4LDEuMjA0NjI5OCA1MC4zNjg4NTUsMi45MjI4NTc3MSBaIi8+PG1hc2sgaWQ9Im1hc2stMiIgZmlsbD0iI2ZmZiI+PHVzZSB4bGluazpocmVmPSIjcGF0aC0xIi8+PC9tYXNrPjxwYXRoIGlkPSJTIiBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik0yOC45MzM4Mzc0LDIzLjQ4MTQzMzEgQzI4LjkzMzgzNzQsMjQuNjk0ODAyOCAzNy4xMzAwNTExLDI0LjExMzI2NjQgMzguMjMwMzIwNiwyMy4yNjA5NTc4IEMzOC4yMzAzMjA2LDE0Ljk5ODE5OTUgMzMuNzg0MTc2NCwxMC42NTYyNSAyNS42NDI1MzU5LDEwLjY1NjI1IEMxNy41MDA4OTUyLDEwLjY1NjI1IDEyLjkzOTI2NjgsMTUuMDY1NzU0MiAxMi45MzkyNjY4LDIxLjY4MDAxNCBDMTIuOTM5MjY2OCwzMy4xOTk4NDk5IDI4LjUyOTY0MjQsMzMuNDIwMzI1MSAyOC41Mjk2NDI0LDM5LjcwMzg3MiBDMjguNTI5NjQyNCw0MS40Njc2NzQ1IDI3LjY2MzUxMDUsNDIuNTE0OTMyMyAyNS43NTgwMjAxLDQyLjUxNDkzMjMgQzIzLjI3NTEwODQsNDIuNTE0OTMyMyAyMi4yOTM0OTIyLDQxLjI1MDQ2OTIgMjIuNDA4OTc2NSwzNi45NTEyMDA0IEMyMi40MDg5NzY1LDM2LjAxODUzMDQgMTIuOTM5MjY2OCwzNS43Mjc3NjIxIDEyLjY1MDU1NjEsMzYuOTUxMjAwNCBDMTEuOTE1MzgxMiw0Ny4zNjk4NTkxIDE4LjQyNDc2OTMsNTAuMzc1IDI1Ljg3MzUwNDQsNTAuMzc1IEMzMy4wOTEyNzA5LDUwLjM3NSAzOC43NSw0Ni41Mzg2MDY5IDM4Ljc1LDM5LjU5MzYzNDEgQzM4Ljc1LDI3LjI0NzAxNTkgMjIuOTI4NjU1NiwyNy41Nzc3Mjg5IDIyLjkyODY1NTYsMjEuNDU5NTM4NyBDMjIuOTI4NjU1NiwxOC45NzkxOTEyIDI0Ljc3NjQwMzksMTguNjQ4NDc4MyAyNS44NzM1MDQ0LDE4LjY0ODQ3ODMgQzI3LjAyODM0NywxOC42NDg0NzgzIDI5LjEwNzA2MzgsMTguODUxNDUxMyAyOC45MzM4Mzc0LDIzLjQ4MTQzMzEgWiIgbWFzaz0idXJsKCNtYXNrLTIpIi8+PHBhdGggaWQ9ImJvb2ttYXJrIiBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9Im5vbnplcm8iIGQ9Ik0zNi44MTI5MTY5LDcuMjc0MDYxMDYgTDM3LjEyMTUyMzMsMC4zNjY4MTQ5NzQgTDQzLjMyNjE1MDMsMCBMNDMuNTkzNDUwMyw3LjAzMjIyNjUzIEM0My42MDI3NTMxLDcuMjg0NDI5NDMgNDMuMzk0MzM5OSw3LjQ5NjAxOTkxIDQzLjEyNzk0NjQsNy41MDQ4MjcgQzQzLjAxMzg4MDQsNy41MDg1OTgxMiA0Mi45MDIwOTM1LDcuNDczOTc2MzcgNDIuODEyNDM1Niw3LjQwNzEwOTU5IEw0MC40MTk3MzIzLDUuNjIyNjI4ODEgTDM3LjU4NjgyOTYsNy42NTcwODcxOCBDMzcuMzc0NDYxMSw3LjgwOTYwMDUgMzcuMDcxNzA5Miw3Ljc3MDI0ODggMzYuOTEwNjE0Niw3LjU2OTE5MjY2IEMzNi44NDI4MDE4LDcuNDg0NTU4MDQgMzYuODA4MjU1NSw3LjM4MDE5OSAzNi44MTI5MTY5LDcuMjc0MDYxMDYgWiIgbWFzaz0idXJsKCNtYXNrLTIpIi8+PC9nPjwvZz48L3N2Zz4=",
url: "https://storybook.js.org",
tagline: "Build, test & document components",
repo: "storybookjs/storybook",
links: [
{
label: "Docs",
href: "https://storybook.js.org/docs",
},
],
},
] as const satisfies ReadonlyArray<Feature<CategoryLabels>>;

export const flags = features.map((f) => f.flag);
Expand Down
2 changes: 2 additions & 0 deletions packages/features/src/rules/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ export enum RulesMessage {
// --- INFO
// Some tools do not work on Stackblitz
INFO_STACKBLITZ_COMPAT,
// Storybook requires a supported UI framework (React, Vue, or Solid)
ERROR_STORYBOOK_R_UI_FRAMEWORK,
}
6 changes: 6 additions & 0 deletions packages/features/src/rules/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,10 @@ export default [
filter(RulesMessage.INFO_STACKBLITZ_COMPAT, (fts) => {
return fts.has("drizzle") || fts.has("sqlite") || fts.has("kysely") || fts.has("cloudflare");
}),
filter(RulesMessage.ERROR_STORYBOOK_R_UI_FRAMEWORK, (fts) => {
if (fts.has("storybook")) {
return !fts.has("react") && !fts.has("vue") && !fts.has("solid");
}
return false;
}),
] satisfies Rule[];
5 changes: 4 additions & 1 deletion packages/tests/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ export async function updatePackageJson(
pkgjson.scripts["lint:oxlint"] =
"oxlint --max-warnings 0 --type-aware --ignore-pattern '*.spec.ts' --ignore-path .gitignore .";
}
pkgjson.scripts.typecheck = "tsc --noEmit";
// Storybook create .ts files that imports .vue files, and tsc complains about that
if (!flags.includes("storybook") || !flags.includes("vue")) {
pkgjson.scripts.typecheck = "tsc --noEmit";
}
pkgjson.devDependencies ??= {};
pkgjson.devDependencies.vitest = packageJson.devDependencies.vitest;
pkgjson.devDependencies.knip = packageJson.devDependencies.knip;
Expand Down
41 changes: 41 additions & 0 deletions packages/tests/tests/FRAMEWORK+storybook.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { describeBati } from "@batijs/tests-utils";

export const matrix = [["solid", "react", "vue"], "storybook", "eslint"];

await describeBati(({ test, expect }) => {
test("storybook config files", async () => {
const fs = await import("node:fs/promises");
const path = await import("node:path");

const storybookDir = process.cwd();

const configExtensions = ["ts", "js", "mjs", "cjs"];
let configFileExists = false;

for (const ext of configExtensions) {
const configPath = path.join(storybookDir, ".storybook", `main.${ext}`);
try {
await fs.access(configPath);
configFileExists = true;
break;
} catch {
// Continue to next extension
}
}

expect(configFileExists).toBe(true);
});

test("storybook scripts", async () => {
const fs = await import("node:fs/promises");
const path = await import("node:path");

const cwd = process.cwd();

const packageJsonPath = path.join(cwd, "package.json");
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));

expect(packageJson.scripts.storybook).toBeTruthy();
expect(packageJson.scripts["build-storybook"]).toBeTruthy();
});
});
Loading
Loading