create-lumen 2.0.0-beta.2 → 2.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -22
- package/bin/cli.js +1 -6
- package/package.json +2 -2
- package/schema/fixtures/v2/valid/next-app-router-feature-based.json +1 -1
- package/schema/fixtures/v2/valid/next-app-router-none.json +1 -1
- package/schema/fixtures/v2/valid/next-pages-router-feature-based.json +1 -1
- package/schema/fixtures/v2/valid/next-pages-router-none.json +1 -1
- package/schema/lumen.config.v2.json +2 -3
- package/src/cleanup.js +20 -5
- package/src/cli-args.js +53 -2
- package/src/configure.js +36 -8
- package/src/css.js +3 -4
- package/src/dependencies.js +2 -2
- package/src/engine/capabilities.js +2 -2
- package/src/engine/composition.js +44 -10
- package/src/env.js +149 -12
- package/src/format.js +14 -6
- package/src/injector.js +66 -14
- package/src/main.js +57 -12
- package/src/manifest/emit.js +23 -7
- package/src/manifest/paths.js +1 -25
- package/src/manifest/schema.js +3 -3
- package/src/prompts.js +25 -8
- package/src/readme.js +0 -16
- package/src/utils/dev-server.js +6 -1
- package/templates/.env.example +1 -1
- package/templates/architectures/feature-based/scripts/create-feature.mjs +2 -2
- package/templates/conditional/linting/biome/biome.json +17 -11
- package/templates/conditional/linting/eslint/next/eslint.config.mjs +2 -11
- package/templates/conditional/testing/vitest/next/vitest.config.js +1 -1
- package/templates/conditional/testing/vitest/next/vitest.config.ts +1 -1
- package/templates/css/tailwind/postcss.config.mjs +3 -1
- package/schema/fixtures/v2/valid/next-app-router-hybrid.json +0 -35
- package/schema/fixtures/v2/valid/next-pages-router-hybrid.json +0 -35
- package/templates/architectures/hybrid/main.jsx +0 -10
- package/templates/architectures/hybrid/main.tsx +0 -10
- package/templates/architectures/hybrid/src/App.jsx +0 -20
- package/templates/architectures/hybrid/src/App.tsx +0 -20
- package/templates/architectures/hybrid/src/features/.gitkeep +0 -1
- package/templates/architectures/hybrid/src/shared/components/ui/Button.jsx +0 -31
- package/templates/architectures/hybrid/src/shared/components/ui/Button.tsx +0 -36
- package/templates/architectures/hybrid/src/shared/components/ui/index.js +0 -1
- package/templates/architectures/hybrid/src/shared/components/ui/index.ts +0 -1
- package/templates/architectures/hybrid/src/shared/hooks/useLocalStorage.jsx +0 -28
- package/templates/architectures/hybrid/src/shared/hooks/useLocalStorage.ts +0 -28
- package/templates/architectures/hybrid/src/shared/layouts/.gitkeep +0 -0
- package/templates/architectures/hybrid/src/shared/stores/.gitkeep +0 -0
- package/templates/architectures/hybrid/src/shared/styles/.gitkeep +0 -0
- package/templates/architectures/hybrid/src/shared/types/index.js +0 -20
- package/templates/architectures/hybrid/src/shared/types/index.ts +0 -16
- package/templates/architectures/hybrid/src/shared/utils/cn.jsx +0 -3
- package/templates/architectures/hybrid/src/shared/utils/cn.ts +0 -5
- package/templates/conditional/testing/jest/hybrid/src/__tests__/App.test.jsx +0 -11
- package/templates/conditional/testing/jest/hybrid/src/__tests__/App.test.tsx +0 -11
- package/templates/conditional/testing/vitest/hybrid/src/__tests__/App.test.jsx +0 -10
- package/templates/conditional/testing/vitest/hybrid/src/__tests__/App.test.tsx +0 -10
package/src/prompts.js
CHANGED
|
@@ -24,8 +24,6 @@ export function formatConfig(responses) {
|
|
|
24
24
|
? "Feature-based"
|
|
25
25
|
: responses.architecture === "type-based" || responses.architecture === "component-based"
|
|
26
26
|
? "Type-based"
|
|
27
|
-
: responses.architecture === "hybrid"
|
|
28
|
-
? "Hybrid (shared + features)"
|
|
29
27
|
: responses.architecture === "none"
|
|
30
28
|
? "None (flat src)"
|
|
31
29
|
: responses.architecture;
|
|
@@ -72,7 +70,8 @@ export function formatConfig(responses) {
|
|
|
72
70
|
lines.push(`• ${chalk.bold("Adapter:")} ${chalk.cyan(responses.adapter)}`);
|
|
73
71
|
}
|
|
74
72
|
if (responses.database && responses.database !== "none") {
|
|
75
|
-
|
|
73
|
+
const providerLabel = responses.databaseProvider === "supabase" ? " (Supabase)" : " (PostgreSQL)";
|
|
74
|
+
lines.push(`• ${chalk.bold("Database:")} ${chalk.cyan(responses.database === "prisma" ? `Prisma ORM${providerLabel}` : responses.database)}`);
|
|
76
75
|
}
|
|
77
76
|
if (responses.reactCompiler !== undefined) {
|
|
78
77
|
lines.push(`• ${chalk.bold("React Compiler:")} ${responses.reactCompiler ? chalk.green("Yes") : chalk.red("No")}`);
|
|
@@ -360,11 +359,6 @@ export async function getUserInputs(
|
|
|
360
359
|
value: "type-based",
|
|
361
360
|
hint: "Small apps / component libraries — code grouped by UI type",
|
|
362
361
|
},
|
|
363
|
-
{
|
|
364
|
-
label: "Hybrid",
|
|
365
|
-
value: "hybrid",
|
|
366
|
-
hint: "Next.js: features + shared code",
|
|
367
|
-
},
|
|
368
362
|
{
|
|
369
363
|
label: "None",
|
|
370
364
|
value: "none",
|
|
@@ -491,6 +485,27 @@ export async function getUserInputs(
|
|
|
491
485
|
]),
|
|
492
486
|
defaultInitial: "none",
|
|
493
487
|
},
|
|
488
|
+
{
|
|
489
|
+
id: "databaseProvider",
|
|
490
|
+
skip: (ans) => !isPromptVisible(framework, "database") || ans.database !== "prisma",
|
|
491
|
+
onSkip: (ans) => {
|
|
492
|
+
ans.databaseProvider = ans.database === "prisma" ? (ans.databaseProvider || "postgresql") : undefined;
|
|
493
|
+
},
|
|
494
|
+
message: "Which database provider do you want to configure?",
|
|
495
|
+
getOptions: () => [
|
|
496
|
+
{
|
|
497
|
+
label: "PostgreSQL",
|
|
498
|
+
value: "postgresql",
|
|
499
|
+
hint: "Standard PostgreSQL / Docker compose",
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
label: "Supabase",
|
|
503
|
+
value: "supabase",
|
|
504
|
+
hint: "PostgreSQL with connection pooling & direct migration URL",
|
|
505
|
+
},
|
|
506
|
+
],
|
|
507
|
+
defaultInitial: "postgresql",
|
|
508
|
+
},
|
|
494
509
|
{
|
|
495
510
|
id: "reactCompiler",
|
|
496
511
|
skip: () => !isPromptVisible(framework, "reactCompiler"),
|
|
@@ -682,6 +697,7 @@ export async function getUserInputs(
|
|
|
682
697
|
bundler,
|
|
683
698
|
adapter,
|
|
684
699
|
database,
|
|
700
|
+
databaseProvider,
|
|
685
701
|
reactCompiler,
|
|
686
702
|
routeGroups,
|
|
687
703
|
agentDocs,
|
|
@@ -704,6 +720,7 @@ export async function getUserInputs(
|
|
|
704
720
|
}
|
|
705
721
|
if (database !== undefined && database !== "none") {
|
|
706
722
|
finalResponses.database = database;
|
|
723
|
+
finalResponses.databaseProvider = databaseProvider || "postgresql";
|
|
707
724
|
}
|
|
708
725
|
if (reactCompiler !== undefined) {
|
|
709
726
|
finalResponses.reactCompiler = reactCompiler;
|
package/src/readme.js
CHANGED
|
@@ -117,22 +117,6 @@ ${nestedTree(appChildren)}
|
|
|
117
117
|
${nestedTree(shared)}`;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
if (responses.architecture === "hybrid") {
|
|
121
|
-
const shared = [
|
|
122
|
-
"components/ # Shared UI components",
|
|
123
|
-
"hooks/ # Shared custom hooks",
|
|
124
|
-
"layouts/ # High-level layout wrappers",
|
|
125
|
-
"stores/ # Global state stores",
|
|
126
|
-
`styles/ # ${responses.cssFramework === "none" ? "main.css (reset) + themes.css (CSS variables)" : "globals.css (framework directives) + themes.css"}`,
|
|
127
|
-
"types/ # Global type definitions",
|
|
128
|
-
"utils/ # Pure utility functions",
|
|
129
|
-
];
|
|
130
|
-
return `src/
|
|
131
|
-
├── features/ # Feature modules (domain boundaries)
|
|
132
|
-
└── shared/ # Reusable, business-agnostic resources
|
|
133
|
-
${nestedTree(shared)}`;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
120
|
if (responses.architecture === "none") {
|
|
137
121
|
return `src/
|
|
138
122
|
├── App.${responses.language === "ts" ? "tsx" : "jsx"} # Root application component
|
package/src/utils/dev-server.js
CHANGED
|
@@ -2,7 +2,12 @@ import { isCancel, select } from "@clack/prompts";
|
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { execa } from "execa";
|
|
4
4
|
|
|
5
|
-
export async function handleDevServer(pkg, projectName) {
|
|
5
|
+
export async function handleDevServer(pkg, projectName, { isNonInteractive = false } = {}) {
|
|
6
|
+
if (isNonInteractive || process.env.CI || !process.stdin.isTTY) {
|
|
7
|
+
printNextSteps(projectName, pkg);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
const startDev = await select({
|
|
7
12
|
message: "Start the development server?",
|
|
8
13
|
options: [
|
package/templates/.env.example
CHANGED
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://biomejs.dev/schemas/
|
|
3
|
-
"vcs": {
|
|
4
|
-
"enabled": false,
|
|
5
|
-
"clientKind": "git",
|
|
6
|
-
"useIgnoreFile": true
|
|
7
|
-
},
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.6.3/schema.json",
|
|
8
3
|
"files": {
|
|
9
4
|
"ignoreUnknown": false,
|
|
10
|
-
"
|
|
5
|
+
"includes": ["**", "!**/.next", "!**/dist", "!**/node_modules"]
|
|
11
6
|
},
|
|
12
7
|
"formatter": {
|
|
13
8
|
"enabled": true,
|
|
14
9
|
"indentStyle": "space",
|
|
15
10
|
"indentWidth": 2
|
|
16
11
|
},
|
|
17
|
-
"organizeImports": {
|
|
18
|
-
"enabled": true
|
|
19
|
-
},
|
|
20
12
|
"linter": {
|
|
21
13
|
"enabled": true,
|
|
22
14
|
"rules": {
|
|
23
|
-
"
|
|
15
|
+
"preset": "recommended"
|
|
24
16
|
}
|
|
25
17
|
},
|
|
26
18
|
"javascript": {
|
|
27
19
|
"formatter": {
|
|
28
20
|
"quoteStyle": "double"
|
|
29
21
|
}
|
|
22
|
+
},
|
|
23
|
+
"css": {
|
|
24
|
+
"parser": {
|
|
25
|
+
"tailwindDirectives": true
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"assist": {
|
|
29
|
+
"enabled": true,
|
|
30
|
+
"actions": {
|
|
31
|
+
"source": {
|
|
32
|
+
"organizeImports": "on"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
30
35
|
}
|
|
31
36
|
}
|
|
37
|
+
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { fileURLToPath } from "url";
|
|
3
|
-
import { FlatCompat } from "@eslint/eslintrc";
|
|
4
|
-
|
|
5
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
-
const __dirname = dirname(__filename);
|
|
7
|
-
|
|
8
|
-
const compat = new FlatCompat({
|
|
9
|
-
baseDirectory: __dirname,
|
|
10
|
-
});
|
|
1
|
+
import nextConfig from "eslint-config-next";
|
|
11
2
|
|
|
12
3
|
const eslintConfig = [
|
|
13
|
-
...
|
|
4
|
+
...nextConfig,
|
|
14
5
|
];
|
|
15
6
|
|
|
16
7
|
export default eslintConfig;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://lumen-sh.github.io/create-lumen/schema/lumen.config.v2.json",
|
|
3
|
-
"manifestVersion": 2,
|
|
4
|
-
"framework": {
|
|
5
|
-
"name": "next",
|
|
6
|
-
"variant": "app-router",
|
|
7
|
-
"bundler": "turbopack",
|
|
8
|
-
"adapter": "node"
|
|
9
|
-
},
|
|
10
|
-
"styling": {
|
|
11
|
-
"engine": "tailwind"
|
|
12
|
-
},
|
|
13
|
-
"architecture": {
|
|
14
|
-
"type": "hybrid"
|
|
15
|
-
},
|
|
16
|
-
"ui": {
|
|
17
|
-
"kit": "none"
|
|
18
|
-
},
|
|
19
|
-
"docs": {
|
|
20
|
-
"language": "en"
|
|
21
|
-
},
|
|
22
|
-
"paths": {
|
|
23
|
-
"features": "src/features",
|
|
24
|
-
"components": "src/shared/components",
|
|
25
|
-
"services": "src/shared/services",
|
|
26
|
-
"hooks": "src/shared/hooks",
|
|
27
|
-
"pages": "app",
|
|
28
|
-
"ui": "src/shared/components/ui"
|
|
29
|
-
},
|
|
30
|
-
"tooling": {
|
|
31
|
-
"language": "ts",
|
|
32
|
-
"linter": "eslint",
|
|
33
|
-
"formatter": "prettier"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://lumen-sh.github.io/create-lumen/schema/lumen.config.v2.json",
|
|
3
|
-
"manifestVersion": 2,
|
|
4
|
-
"framework": {
|
|
5
|
-
"name": "next",
|
|
6
|
-
"variant": "pages-router",
|
|
7
|
-
"bundler": "turbopack",
|
|
8
|
-
"adapter": "static"
|
|
9
|
-
},
|
|
10
|
-
"styling": {
|
|
11
|
-
"engine": "tailwind"
|
|
12
|
-
},
|
|
13
|
-
"architecture": {
|
|
14
|
-
"type": "hybrid"
|
|
15
|
-
},
|
|
16
|
-
"ui": {
|
|
17
|
-
"kit": "none"
|
|
18
|
-
},
|
|
19
|
-
"docs": {
|
|
20
|
-
"language": "es"
|
|
21
|
-
},
|
|
22
|
-
"paths": {
|
|
23
|
-
"features": "src/features",
|
|
24
|
-
"components": "src/shared/components",
|
|
25
|
-
"services": "src/shared/services",
|
|
26
|
-
"hooks": "src/shared/hooks",
|
|
27
|
-
"pages": "pages",
|
|
28
|
-
"ui": "src/shared/components/ui"
|
|
29
|
-
},
|
|
30
|
-
"tooling": {
|
|
31
|
-
"language": "js",
|
|
32
|
-
"linter": "eslint",
|
|
33
|
-
"formatter": "prettier"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import ReactDOM from "react-dom/client";
|
|
3
|
-
import App from "./App";
|
|
4
|
-
import "./shared/styles/globals.css";
|
|
5
|
-
|
|
6
|
-
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
7
|
-
<React.StrictMode>
|
|
8
|
-
<App />
|
|
9
|
-
</React.StrictMode>
|
|
10
|
-
);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Button } from "@/shared/components/ui/Button";
|
|
2
|
-
|
|
3
|
-
export default function App() {
|
|
4
|
-
return (
|
|
5
|
-
<div
|
|
6
|
-
style={{
|
|
7
|
-
minHeight: "100vh",
|
|
8
|
-
display: "flex",
|
|
9
|
-
flexDirection: "column",
|
|
10
|
-
alignItems: "center",
|
|
11
|
-
justifyContent: "center",
|
|
12
|
-
backgroundColor: "var(--color-bg, #ffffff)",
|
|
13
|
-
}}
|
|
14
|
-
>
|
|
15
|
-
<h1>Welcome to Lumen</h1>
|
|
16
|
-
<p>Hybrid architecture (src/features + src/shared).</p>
|
|
17
|
-
<Button>Click me</Button>
|
|
18
|
-
</div>
|
|
19
|
-
);
|
|
20
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Button } from "@/shared/components/ui/Button";
|
|
2
|
-
|
|
3
|
-
export default function App() {
|
|
4
|
-
return (
|
|
5
|
-
<div
|
|
6
|
-
style={{
|
|
7
|
-
minHeight: "100vh",
|
|
8
|
-
display: "flex",
|
|
9
|
-
flexDirection: "column",
|
|
10
|
-
alignItems: "center",
|
|
11
|
-
justifyContent: "center",
|
|
12
|
-
backgroundColor: "var(--color-bg, #ffffff)",
|
|
13
|
-
}}
|
|
14
|
-
>
|
|
15
|
-
<h1>Welcome to Lumen</h1>
|
|
16
|
-
<p>Hybrid architecture (src/features + src/shared).</p>
|
|
17
|
-
<Button>Click me</Button>
|
|
18
|
-
</div>
|
|
19
|
-
);
|
|
20
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export function Button({
|
|
2
|
-
variant = "primary",
|
|
3
|
-
children,
|
|
4
|
-
className,
|
|
5
|
-
...props
|
|
6
|
-
}) {
|
|
7
|
-
const styles = {
|
|
8
|
-
primary: { backgroundColor: "var(--color-primary)", color: "white" },
|
|
9
|
-
secondary: {
|
|
10
|
-
backgroundColor: "var(--color-border)",
|
|
11
|
-
color: "var(--color-fg)",
|
|
12
|
-
},
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<button
|
|
17
|
-
style={{
|
|
18
|
-
padding: "8px 16px",
|
|
19
|
-
borderRadius: "8px",
|
|
20
|
-
fontWeight: 500,
|
|
21
|
-
border: "none",
|
|
22
|
-
cursor: "pointer",
|
|
23
|
-
...styles[variant],
|
|
24
|
-
}}
|
|
25
|
-
className={className}
|
|
26
|
-
{...props}
|
|
27
|
-
>
|
|
28
|
-
{children}
|
|
29
|
-
</button>
|
|
30
|
-
);
|
|
31
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
2
|
-
variant?: "primary" | "secondary";
|
|
3
|
-
children: React.ReactNode;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export function Button({
|
|
7
|
-
variant = "primary",
|
|
8
|
-
children,
|
|
9
|
-
className,
|
|
10
|
-
...props
|
|
11
|
-
}: ButtonProps) {
|
|
12
|
-
const styles = {
|
|
13
|
-
primary: { backgroundColor: "var(--color-primary)", color: "white" },
|
|
14
|
-
secondary: {
|
|
15
|
-
backgroundColor: "var(--color-border)",
|
|
16
|
-
color: "var(--color-fg)",
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<button
|
|
22
|
-
style={{
|
|
23
|
-
padding: "8px 16px",
|
|
24
|
-
borderRadius: "8px",
|
|
25
|
-
fontWeight: 500,
|
|
26
|
-
border: "none",
|
|
27
|
-
cursor: "pointer",
|
|
28
|
-
...styles[variant],
|
|
29
|
-
}}
|
|
30
|
-
className={className}
|
|
31
|
-
{...props}
|
|
32
|
-
>
|
|
33
|
-
{children}
|
|
34
|
-
</button>
|
|
35
|
-
);
|
|
36
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { Button } from "./Button";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { Button } from "./Button";
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback } from "react";
|
|
2
|
-
|
|
3
|
-
export function useLocalStorage(key, initialValue) {
|
|
4
|
-
const [storedValue, setStoredValue] = useState(() => {
|
|
5
|
-
try {
|
|
6
|
-
const item = window.localStorage.getItem(key);
|
|
7
|
-
return item ? JSON.parse(item) : initialValue;
|
|
8
|
-
} catch {
|
|
9
|
-
return initialValue;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const setValue = useCallback(
|
|
14
|
-
(value) => {
|
|
15
|
-
try {
|
|
16
|
-
const valueToStore =
|
|
17
|
-
value instanceof Function ? value(storedValue) : value;
|
|
18
|
-
setStoredValue(valueToStore);
|
|
19
|
-
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
20
|
-
} catch (error) {
|
|
21
|
-
console.error(error);
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
[key, storedValue]
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
return [storedValue, setValue];
|
|
28
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback } from "react";
|
|
2
|
-
|
|
3
|
-
export function useLocalStorage<T>(key: string, initialValue: T) {
|
|
4
|
-
const [storedValue, setStoredValue] = useState<T>(() => {
|
|
5
|
-
try {
|
|
6
|
-
const item = window.localStorage.getItem(key);
|
|
7
|
-
return item ? (JSON.parse(item) as T) : initialValue;
|
|
8
|
-
} catch {
|
|
9
|
-
return initialValue;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const setValue = useCallback(
|
|
14
|
-
(value: T | ((prev: T) => T)) => {
|
|
15
|
-
try {
|
|
16
|
-
const valueToStore =
|
|
17
|
-
value instanceof Function ? value(storedValue) : value;
|
|
18
|
-
setStoredValue(valueToStore);
|
|
19
|
-
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
20
|
-
} catch (error) {
|
|
21
|
-
console.error(error);
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
[key, storedValue]
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
return [storedValue, setValue] as const;
|
|
28
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {Object} User
|
|
3
|
-
* @property {string} id
|
|
4
|
-
* @property {string} email
|
|
5
|
-
* @property {string} name
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @typedef {Object} ApiResponse
|
|
10
|
-
* @property {*} data
|
|
11
|
-
* @property {string} message
|
|
12
|
-
* @property {boolean} success
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @typedef {Object} CreateUserPayload
|
|
17
|
-
* @property {string} email
|
|
18
|
-
* @property {string} name
|
|
19
|
-
*/
|
|
20
|
-
export {};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export interface User {
|
|
2
|
-
id: string;
|
|
3
|
-
email: string;
|
|
4
|
-
name: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface ApiResponse<T> {
|
|
8
|
-
data: T;
|
|
9
|
-
message: string;
|
|
10
|
-
success: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface CreateUserPayload {
|
|
14
|
-
email: string;
|
|
15
|
-
name: string;
|
|
16
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "@jest/globals";
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
3
|
-
import "@testing-library/jest-dom/jest-globals";
|
|
4
|
-
import App from "@/App";
|
|
5
|
-
|
|
6
|
-
describe("App", () => {
|
|
7
|
-
it("renders without crashing", () => {
|
|
8
|
-
render(<App />);
|
|
9
|
-
expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
|
|
10
|
-
});
|
|
11
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "@jest/globals";
|
|
2
|
-
import { render, screen } from "@testing-library/react";
|
|
3
|
-
import "@testing-library/jest-dom/jest-globals";
|
|
4
|
-
import App from "@/App";
|
|
5
|
-
|
|
6
|
-
describe("App", () => {
|
|
7
|
-
it("renders without crashing", () => {
|
|
8
|
-
render(<App />);
|
|
9
|
-
expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
|
|
10
|
-
});
|
|
11
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { render, screen } from "@testing-library/react";
|
|
2
|
-
import { describe, it, expect } from "vitest";
|
|
3
|
-
import App from "@/App";
|
|
4
|
-
|
|
5
|
-
describe("App", () => {
|
|
6
|
-
it("renders without crashing", () => {
|
|
7
|
-
render(<App />);
|
|
8
|
-
expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
|
|
9
|
-
});
|
|
10
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { render, screen } from "@testing-library/react";
|
|
2
|
-
import { describe, it, expect } from "vitest";
|
|
3
|
-
import App from "@/App";
|
|
4
|
-
|
|
5
|
-
describe("App", () => {
|
|
6
|
-
it("renders without crashing", () => {
|
|
7
|
-
render(<App />);
|
|
8
|
-
expect(screen.getByText(/Welcome/i)).toBeInTheDocument();
|
|
9
|
-
});
|
|
10
|
-
});
|