@igniter-js/cli 0.1.0

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.
Files changed (35) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +358 -0
  3. package/dist/templates/components.json.hbs +21 -0
  4. package/dist/templates/copilot.instructions.hbs +117 -0
  5. package/dist/templates/docker-compose.hbs +15 -0
  6. package/dist/templates/env.hbs +33 -0
  7. package/dist/templates/eslintrc.hbs +3 -0
  8. package/dist/templates/feature.controller.hbs +83 -0
  9. package/dist/templates/feature.index.hbs +5 -0
  10. package/dist/templates/feature.interface.hbs +71 -0
  11. package/dist/templates/feature.procedure.hbs +76 -0
  12. package/dist/templates/globals.hbs +198 -0
  13. package/dist/templates/igniter.client.hbs +21 -0
  14. package/dist/templates/igniter.context.hbs +23 -0
  15. package/dist/templates/igniter.hbs +8 -0
  16. package/dist/templates/igniter.router.hbs +29 -0
  17. package/dist/templates/layout.hbs +54 -0
  18. package/dist/templates/page.hbs +313 -0
  19. package/dist/templates/prisma.hbs +9 -0
  20. package/dist/templates/readme.hbs +136 -0
  21. package/dist/templates/vitest.config.hbs +11 -0
  22. package/dist/utils/analyze.d.ts +17 -0
  23. package/dist/utils/analyze.js +187 -0
  24. package/dist/utils/consts.d.ts +26 -0
  25. package/dist/utils/consts.js +34 -0
  26. package/dist/utils/handlebars-helpers.d.ts +1 -0
  27. package/dist/utils/handlebars-helpers.js +43 -0
  28. package/dist/utils/helpers.d.ts +12 -0
  29. package/dist/utils/helpers.js +102 -0
  30. package/dist/utils/prisma-schema-parser.d.ts +59 -0
  31. package/dist/utils/prisma-schema-parser.js +197 -0
  32. package/dist/utils/template-handler.d.ts +6 -0
  33. package/dist/utils/template-handler.js +33 -0
  34. package/package.json +73 -0
  35. package/readme.md +143 -0
@@ -0,0 +1,313 @@
1
+ import { Badge } from "@/core/design-system/badge"
2
+ import { Button } from "@/core/design-system/button"
3
+ import { Card, CardContent, CardFooter } from "@/core/design-system/card"
4
+ import { ArrowRight, Code2, Github, SparkleIcon, Twitter, Youtube } from "lucide-react"
5
+ import { FileText } from "lucide-react"
6
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@radix-ui/react-tabs"
7
+
8
+ export default async function Home() {
9
+ return (
10
+ <div className="min-h-screen flex flex-col pt-12 space-y-12">
11
+ <header className="max-w-2xl w-full space-y-8 mx-auto my-auto">
12
+ <div className="space-y-6 text-center">
13
+ <Badge variant="outline" className="mx-auto rounded-full px-3 py-1 text-sm font-medium bg-cyan-500/10 text-cyan-500 border-cyan-300/10/20" aria-label="Beta version">
14
+ BETA
15
+ </Badge>
16
+
17
+ <h1 className="text-4xl sm:text-5xl font-bold tracking-tight bg-gradient-to-r from-primary to-primary/60 bg-clip-text text-transparent">
18
+ Welcome to <br />Igniter Framework
19
+ </h1>
20
+ <p className="text-base sm:text-lg text-muted-foreground max-w-md mx-auto leading-relaxed">
21
+ A modern framework optimized for AI-powered development, featuring built-in best practices and type safety for rapid web applications
22
+ </p>
23
+
24
+ <div className="flex items-center justify-center gap-4">
25
+ <Button variant="outline" size="icon" asChild>
26
+ <a href="https://github.com/feldbarcelospro/igniter-js" target="_blank" rel="noopener noreferrer">
27
+ <Github className="h-4 w-4" />
28
+ <span className="sr-only">GitHub Repository</span>
29
+ </a>
30
+ </Button>
31
+ <Button variant="outline" size="icon" asChild>
32
+ <a href="https://twitter.com/feldbarcelospro" target="_blank" rel="noopener noreferrer">
33
+ <Twitter className="h-4 w-4" />
34
+ <span className="sr-only">X (Twitter) Profile</span>
35
+ </a>
36
+ </Button>
37
+ <Button variant="outline" size="icon" asChild>
38
+ <a href="https://youtube.com/@feldbarcelospro" target="_blank" rel="noopener noreferrer">
39
+ <Youtube className="h-4 w-4" />
40
+ <span className="sr-only">YouTube Channel</span>
41
+ </a>
42
+ </Button>
43
+ </div>
44
+ </div>
45
+ <section aria-labelledby="getting-started-title" className="relative">
46
+ <div className="absolute inset-0 bg-gradient-to-b from-transparent to-background/10 pointer-events-none" aria-hidden="true" />
47
+ <Card className="rounded-3xl shadow-lg backdrop-blur-sm border bg-card/50 overflow-hidden">
48
+ <CardContent className="p-6 sm:p-8">
49
+ <Tabs defaultValue="getting-started" className="space-y-6 flex flex-col items-center">
50
+ <TabsList className="inline-flex h-12 items-center justify-center rounded-full bg-muted p-1 text-muted-foreground">
51
+ <TabsTrigger
52
+ value="getting-started"
53
+ className="inline-flex w-fit items-center justify-center whitespace-nowrap rounded-full px-6 py-2.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm"
54
+ >
55
+ <Code2 className="mr-2 h-4 w-4" />
56
+ Getting Started
57
+ </TabsTrigger>
58
+ <TabsTrigger
59
+ value="first-feature"
60
+ className="inline-flex items-center justify-center whitespace-nowrap rounded-full px-6 py-2.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm"
61
+ >
62
+ <FileText className="mr-2 h-4 w-4" />
63
+ First Feature
64
+ </TabsTrigger>
65
+ <TabsTrigger
66
+ value="extensions"
67
+ className="inline-flex items-center justify-center whitespace-nowrap rounded-full px-6 py-2.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm"
68
+ >
69
+ <SparkleIcon className="mr-2 h-4 w-4" />
70
+ Add your first Spark (Comming Soon)
71
+ </TabsTrigger>
72
+ </TabsList>
73
+
74
+ <TabsContent value="getting-started" className="space-y-6 w-full">
75
+ <div className="space-y-2 text-center flex flex-col items-center justify-center">
76
+ <h2 className="text-2xl font-bold tracking-tight">Getting Started</h2>
77
+ <p className="text-muted-foreground">Follow these steps to set up your development environment.</p>
78
+ </div>
79
+
80
+ <div className="space-y-4">
81
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
82
+ <p className="font-medium text-foreground mb-2">1. Install dependencies</p>
83
+ <code className="relative rounded-xl bg-muted border px-4 py-3 font-mono text-sm block group-hover:border-accent transition-colors">
84
+ npm install
85
+ </code>
86
+ </div>
87
+
88
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
89
+ <p className="font-medium text-foreground mb-2">2. Start development server</p>
90
+ <code className="relative rounded-xl bg-muted border px-4 py-3 font-mono text-sm block group-hover:border-accent transition-colors">
91
+ npm run dev
92
+ </code>
93
+ </div>
94
+
95
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
96
+ <p className="font-medium text-foreground mb-2">3. View your application</p>
97
+ <div className="flex items-center gap-2">
98
+ <span className="h-2 w-2 rounded-full bg-green-500 animate-pulse"></span>
99
+ <code className="text-primary">http://localhost:3000</code>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ </TabsContent>
104
+
105
+ <TabsContent value="first-feature" className="space-y-6 w-full">
106
+ <div className="space-y-2 text-center flex flex-col items-center justify-center">
107
+ <h2 className="text-2xl font-bold tracking-tight">Create Your First Feature</h2>
108
+ <p className="text-muted-foreground">Follow these steps to create and configure a new feature.</p>
109
+ </div>
110
+
111
+ <div className="space-y-4">
112
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
113
+ <p className="font-medium text-foreground mb-2">1. Add your entity on schema.prisma</p>
114
+ <code className="relative rounded-xl bg-muted border px-4 py-3 font-mono text-sm block group-hover:border-accent transition-colors">
115
+ {`// Example:
116
+ model Post {
117
+ id Int @id @default(autoincrement())
118
+ title String
119
+ content String?
120
+ createdAt DateTime @default(now())
121
+ updatedAt DateTime @updatedAt
122
+ }`}
123
+ </code>
124
+ </div>
125
+
126
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
127
+ <p className="font-medium text-foreground mb-2">2. Run CLI and select features to generate</p>
128
+ <code className="relative rounded-xl bg-muted border px-4 py-3 font-mono text-sm block group-hover:border-accent transition-colors">
129
+ igniter generate feature
130
+ </code>
131
+ </div>
132
+
133
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
134
+ <p className="font-medium text-foreground mb-2">4. Add to /src/igniter.router.ts</p>
135
+ <code className="relative rounded-xl bg-muted border px-4 py-3 font-mono text-sm block group-hover:border-accent transition-colors">
136
+ {`// Example:
137
+ import { PostFeature } from '@/features/post'
138
+
139
+ export const router = new IgniterRouter()
140
+ .use(postFeature.controller)
141
+ `}
142
+ </code>
143
+ </div>
144
+
145
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
146
+ <p className="font-medium text-foreground mb-2">5. Use in your application</p>
147
+ <p className="text-sm text-muted-foreground">
148
+ {`// Server Component Example:
149
+ import { PostFeature } from '@/features/post'
150
+
151
+ export default async function Page() {
152
+ const getPosts = router.bind('post', 'get')
153
+ const posts = await getPosts()
154
+
155
+ return <pre>{JSON.stringify(posts, null, 2)}</pre>
156
+ }
157
+
158
+ // Client Component Example:
159
+ 'use client'
160
+
161
+ import { PostFeature } from '@/features/post'
162
+ import { useAction } from '@igniter/hooks'
163
+
164
+ export default function Page() {
165
+ const { data, execute } = useAction({
166
+ action: router.bind('post', 'get')
167
+ })
168
+
169
+ return (
170
+ <>
171
+ <button onClick={execute}>Load Posts</button>
172
+ <pre>{JSON.stringify(data, null, 2)}</pre>
173
+ </>
174
+ )
175
+ }
176
+ `}
177
+ </p >
178
+ </div>
179
+ </div>
180
+ </TabsContent>
181
+
182
+ <TabsContent value="extensions" className="space-y-6 w-full">
183
+ <div className="space-y-2 text-center flex flex-col items-center justify-center">
184
+ <h2 className="text-2xl font-bold tracking-tight">Ignite Sparks</h2>
185
+ <p className="text-muted-foreground">Add powerful features that ignite your application.</p>
186
+ </div>
187
+
188
+ <div className="space-y-4">
189
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
190
+ <p className="font-medium text-foreground mb-2">1. Discover available Sparks</p>
191
+ <code className="relative rounded-xl bg-muted border px-4 py-3 font-mono text-sm block group-hover:border-accent transition-colors">
192
+ npm run igniter spark:list
193
+ </code>
194
+ </div>
195
+
196
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
197
+ <p className="font-medium text-foreground mb-2">2. Ignite a single Spark</p>
198
+ <code className="relative rounded-xl bg-muted border px-4 py-3 font-mono text-sm block group-hover:border-accent transition-colors">
199
+ npm run igniter spark:add auth
200
+ </code>
201
+ </div>
202
+
203
+ <div className="group rounded-2xl border p-4 transition-colors hover:bg-accent">
204
+ <p className="font-medium text-foreground mb-2">3. Ignite multiple Sparks</p>
205
+ <code className="relative rounded-xl bg-muted border px-4 py-3 font-mono text-sm block group-hover:border-accent transition-colors">
206
+ npm run igniter spark:add email storage payment
207
+ </code>
208
+ </div>
209
+ </div>
210
+ </TabsContent>
211
+ </Tabs>
212
+ </CardContent>
213
+ <CardFooter className="flex flex-col items-center justify-center border-t pt-8">
214
+ <Button variant="outline" size="lg" className="w-full rounded-xl">
215
+ Read Docs
216
+ <ArrowRight className="w-4 h-4 ml-auto" aria-hidden="true" />
217
+ </Button>
218
+ </CardFooter>
219
+ </Card>
220
+ </section>
221
+
222
+ <section className="grid gap-4 sm:grid-cols-2" aria-label="Resources">
223
+ <article>
224
+ <Card className="rounded-2xl shadow-sm hover:shadow-md transition-shadow bg-card">
225
+ <CardContent className="p-4 sm:p-6 space-y-2">
226
+ <span className="h-10 w-10 rounded-lg border border-cyan-300/10 bg-cyan-500/10 flex items-center justify-center mb-4">
227
+ <FileText className="w-5 h-5 text-cyan-500" aria-hidden="true" />
228
+ </span>
229
+ <div className="flex items-center gap-2">
230
+ <h3 className="font-semibold">Documentation</h3>
231
+ </div>
232
+ <p className="text-sm text-muted-foreground">
233
+ Learn more about Igniter Framework features and API.
234
+ </p>
235
+ <Button variant="outline" className="w-full !mt-8 rounded-xl">
236
+ Read Docs
237
+ <ArrowRight className="w-4 h-4 ml-auto" aria-hidden="true" />
238
+ </Button>
239
+ </CardContent>
240
+ </Card>
241
+ </article>
242
+
243
+ <article>
244
+ <Card className="rounded-2xl shadow-sm hover:shadow-md transition-shadow bg-card">
245
+ <CardContent className="p-4 sm:p-6 space-y-2">
246
+ <span className="h-10 w-10 rounded-lg border border-cyan-300/10 bg-cyan-500/10 flex items-center justify-center mb-4">
247
+ <Code2 className="w-5 h-5 text-cyan-500" aria-hidden="true" />
248
+ </span>
249
+ <div className="flex items-center gap-2">
250
+ <h3 className="font-semibold">Examples</h3>
251
+ </div>
252
+ <p className="text-sm text-muted-foreground">
253
+ Discover and deploy example Igniter Framework projects.
254
+ </p>
255
+ <Button variant="outline" className="w-full !mt-8 rounded-xl">
256
+ View Examples
257
+ <ArrowRight className="w-4 h-4 ml-auto" aria-hidden="true" />
258
+ </Button>
259
+ </CardContent>
260
+ </Card>
261
+ </article>
262
+ </section>
263
+ </header>
264
+
265
+ <footer className="border-t pt-6 text-center w-full text-sm text-muted-foreground h-16">
266
+ <nav aria-label="Footer Links">
267
+ <p>
268
+ Built with{" "}
269
+ <a
270
+ href="https://ui.shadcn.com"
271
+ target="_blank"
272
+ rel="noopener noreferrer"
273
+ className="font-medium underline underline-offset-4 hover:text-primary transition-colors"
274
+ aria-label="Visit shadcn/ui website"
275
+ >
276
+ shadcn/ui
277
+ </a>
278
+ {", "}
279
+ <a
280
+ href="https://nextjs.org"
281
+ target="_blank"
282
+ rel="noopener noreferrer"
283
+ className="font-medium underline underline-offset-4 hover:text-primary transition-colors"
284
+ aria-label="Visit Next.js website"
285
+ >
286
+ Next.js 15
287
+ </a>
288
+ {", "}
289
+ <a
290
+ href="https://www.prisma.io"
291
+ target="_blank"
292
+ rel="noopener noreferrer"
293
+ className="font-medium underline underline-offset-4 hover:text-primary transition-colors"
294
+ aria-label="Visit Prisma website"
295
+ >
296
+ Prisma
297
+ </a>
298
+ {", and "}
299
+ <a
300
+ href="https://zod.dev"
301
+ target="_blank"
302
+ rel="noopener noreferrer"
303
+ className="font-medium underline underline-offset-4 hover:text-primary transition-colors"
304
+ aria-label="Visit Zod website"
305
+ >
306
+ Zod
307
+ </a>
308
+ </p>
309
+ </nav>
310
+ </footer>
311
+ </div>
312
+ )
313
+ }
@@ -0,0 +1,9 @@
1
+ import { PrismaClient } from '@prisma/client'
2
+
3
+ const globalForPrisma = globalThis as unknown as {
4
+ prisma: PrismaClient | undefined
5
+ }
6
+
7
+ export const prisma = globalForPrisma.prisma ?? new PrismaClient()
8
+
9
+ if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
@@ -0,0 +1,136 @@
1
+ # {{name}}
2
+
3
+ A modern web application built with [Igniter Framework](https://github.com/felipebarcelospro/igniter-js) - A feature-first framework for Next.js projects.
4
+
5
+ ## 🚀 Quick Start
6
+
7
+ 1. **Install Dependencies**
8
+ ```bash
9
+ npm install
10
+ # or
11
+ yarn install
12
+ ```
13
+
14
+ 2. **Setup Database**
15
+ ```bash
16
+ # Start Docker containers
17
+ npm run docker:up
18
+
19
+ # Generate Prisma Client
20
+ npm run db:generate
21
+
22
+ # Push database schema
23
+ npm run db:push
24
+ ```
25
+
26
+ 3. **Start Development Server**
27
+ ```bash
28
+ npm run dev
29
+ # or
30
+ yarn dev
31
+ ```
32
+
33
+ Open [http://localhost:3000](http://localhost:3000) to view your application.
34
+
35
+ ## 📖 Project Structure
36
+
37
+ ```
38
+ ├── src/
39
+ │ ├── app/ # Next.js app directory
40
+ │ ├── core/ # Core framework modules
41
+ │ │ ├── design-system/ # UI components (shadcn/ui)
42
+ │ │ ├── factories/ # Base factories for features
43
+ │ │ ├── providers/ # Context providers
44
+ │ │ └── utils/ # Shared utilities
45
+ │ ├── features/ # Feature modules
46
+ │ │ └── [feature]/ # Feature-specific code
47
+ │ │ ├── index.ts # Feature entry point
48
+ │ │ ├── controllers/ # HTTP request handlers
49
+ │ │ │ └── [feature].controller.ts
50
+ │ │ ├── services/ # Business logic
51
+ │ │ │ └── [feature].service.ts
52
+ │ │ ├── repositories/ # Data access
53
+ │ │ │ └── [feature].repository.ts
54
+ │ │ ├── validators/ # Data validation schemas
55
+ │ │ │ └── [feature].validator.ts
56
+ │ │ ├── [feature].types.ts # Feature types
57
+ │ │ └── [feature].feature.ts # Feature configuration
58
+ │ └── configs/ # Configuration files
59
+ ├── public/ # Static files
60
+ ├── docs/ # Documentation
61
+ ├── scripts/ # Utility scripts
62
+ └── .github/ # GitHub configuration
63
+ ```
64
+
65
+ ## 🛠 Available Scripts
66
+
67
+ - `npm run dev` - Start development server
68
+ - `npm run build` - Build for production
69
+ - `npm run start` - Start production server
70
+ - `npm run lint` - Run ESLint
71
+ - `npm run test` - Run tests with Vitest
72
+
73
+ ### Database Scripts
74
+ - `npm run docker:up` - Start Docker containers
75
+ - `npm run docker:down` - Stop Docker containers
76
+ - `npm run db:studio` - Open Prisma Studio
77
+ - `npm run db:push` - Push database schema changes
78
+ - `npm run db:generate` - Generate Prisma Client
79
+
80
+ ### Igniter CLI Commands
81
+ - `npm run igniter:generate feature [name]` - Generate a new feature
82
+
83
+ ## 🏗 Feature Generation
84
+ Generate a new feature using the Igniter CLI:
85
+
86
+ ```bash
87
+ npm run igniter generate feature
88
+ ```
89
+
90
+ This will create a new feature with the following structure:
91
+ ```
92
+ src/features/users/
93
+ ├── index.ts # Feature exports
94
+ ├── controller.ts # HTTP request handling
95
+ ├── service.ts # Business logic
96
+ ├── repository.ts # Data access
97
+ ├── factory.ts # Object creation
98
+ └── schema.ts # Data validation
99
+ ```
100
+
101
+ ## 🧩 Tech Stack
102
+
103
+ - **Framework**: Igniter.js (Next.js 15)
104
+ - **Language**: TypeScript
105
+ - **Styling**: Tailwind CSS
106
+ - **UI Components**: shadcn/ui
107
+ - **Database**: Prisma
108
+ - **Testing**: Vitest
109
+ - **State Management**: React Context
110
+ - **API Layer**: Feature-based controllers
111
+ - **Validation**: Zod
112
+ - **Development**: Docker
113
+
114
+ ## 📚 Documentation
115
+
116
+ For more detailed documentation:
117
+
118
+ - [Igniter Framework Documentation](https://github.com/felipebarcelospro/igniter-js)
119
+ - [Next.js Documentation](https://nextjs.org/docs)
120
+ - [Prisma Documentation](https://www.prisma.io/docs)
121
+ - [shadcn/ui Documentation](https://ui.shadcn.com)
122
+ - [Tailwind CSS Documentation](https://tailwindcss.com/docs)
123
+ - [Vitest Documentation](https://vitest.dev/docs)
124
+ - [Zod Documentation](https://zod.dev)
125
+
126
+ ## 🤝 Contributing
127
+
128
+ 1. Fork the repository
129
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
130
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
131
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
132
+ 5. Open a Pull Request
133
+
134
+ ## 📝 License
135
+
136
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,11 @@
1
+ /// <reference types="vitest" />
2
+ import { defineConfig } from 'vitest/config'
3
+ import react from '@vitejs/plugin-react'
4
+ import tsconfigPaths from 'vite-tsconfig-paths'
5
+
6
+ export default defineConfig({
7
+ plugins: [tsconfigPaths(), react()],
8
+ test: {
9
+ environment: 'jsdom',
10
+ },
11
+ })
@@ -0,0 +1,17 @@
1
+ import { CLIHelper } from './helpers';
2
+ export declare class AnalyzeCommand extends CLIHelper {
3
+ private readonly schemaParser;
4
+ private report;
5
+ private spinner;
6
+ constructor(basePath?: string);
7
+ private initializeReport;
8
+ analyze(): Promise<void>;
9
+ private analyzeSchema;
10
+ private analyzeFeatures;
11
+ private analyzeDependencies;
12
+ private analyzePerformance;
13
+ private getAllFiles;
14
+ private countApiEndpoints;
15
+ private calculateBundleSize;
16
+ private displayReport;
17
+ }
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AnalyzeCommand = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const child_process_1 = require("child_process");
11
+ const util_1 = require("util");
12
+ const prisma_schema_parser_1 = require("../utils/prisma-schema-parser");
13
+ const helpers_1 = require("./helpers");
14
+ const ora_1 = __importDefault(require("ora"));
15
+ const execAsync = (0, util_1.promisify)(child_process_1.exec);
16
+ class AnalyzeCommand extends helpers_1.CLIHelper {
17
+ constructor(basePath = process.cwd()) {
18
+ super();
19
+ this.schemaParser = new prisma_schema_parser_1.PrismaSchemaParser(basePath);
20
+ this.report = this.initializeReport();
21
+ this.spinner = (0, ora_1.default)();
22
+ }
23
+ initializeReport() {
24
+ return {
25
+ schema: { models: 0, relations: 0, complexModels: [] },
26
+ features: { count: 0, unused: [], incomplete: [], complexity: {} },
27
+ dependencies: { unused: [], outdated: [], security: [] },
28
+ performance: { bundleSize: '0KB', apiEndpoints: 0, slowQueries: [] }
29
+ };
30
+ }
31
+ async analyze() {
32
+ console.clear();
33
+ this.spinner.start('Analyzing project structure');
34
+ try {
35
+ await this.analyzeSchema();
36
+ await this.analyzeFeatures();
37
+ await this.analyzeDependencies();
38
+ await this.analyzePerformance();
39
+ this.spinner.succeed('Analysis completed');
40
+ this.displayReport();
41
+ }
42
+ catch (error) {
43
+ this.spinner.fail('Analysis failed');
44
+ console.error(chalk_1.default.red(error));
45
+ process.exit(1);
46
+ }
47
+ }
48
+ async analyzeSchema() {
49
+ var _a;
50
+ this.spinner.start('Analyzing Prisma schema');
51
+ const content = this.schemaParser.getSchemaContent();
52
+ const modelMatches = content.match(/model\s+\w+\s*{[^}]*}/g) || [];
53
+ this.report.schema.models = modelMatches.length;
54
+ // Analyze relations and complex models
55
+ for (const model of modelMatches) {
56
+ const relations = (model.match(/@relation/g) || []).length;
57
+ this.report.schema.relations += relations;
58
+ const modelName = ((_a = model.match(/model\s+(\w+)/)) === null || _a === void 0 ? void 0 : _a[1]) || '';
59
+ if (relations > 3) {
60
+ this.report.schema.complexModels.push(modelName);
61
+ }
62
+ }
63
+ this.spinner.succeed('Schema analysis completed');
64
+ }
65
+ async analyzeFeatures() {
66
+ this.spinner.start('Analyzing features');
67
+ const featuresPath = path_1.default.join(process.cwd(), 'src/features');
68
+ if (!fs_1.default.existsSync(featuresPath)) {
69
+ this.spinner.info('No features directory found');
70
+ return;
71
+ }
72
+ const features = fs_1.default.readdirSync(featuresPath);
73
+ this.report.features.count = features.length;
74
+ for (const feature of features) {
75
+ const featurePath = path_1.default.join(featuresPath, feature);
76
+ const requiredDirs = ['controllers', 'services', 'repositories', 'schemas'];
77
+ if (!requiredDirs.every(dir => fs_1.default.existsSync(path_1.default.join(featurePath, dir)))) {
78
+ this.report.features.incomplete.push(feature);
79
+ }
80
+ // Analyze complexity based on file count and size
81
+ let complexity = 0;
82
+ const files = this.getAllFiles(featurePath);
83
+ for (const file of files) {
84
+ const content = fs_1.default.readFileSync(file, 'utf-8');
85
+ complexity += content.split('\n').length;
86
+ }
87
+ this.report.features.complexity[feature] = complexity;
88
+ }
89
+ this.spinner.succeed('Features analysis completed');
90
+ }
91
+ async analyzeDependencies() {
92
+ this.spinner.start('Analyzing dependencies');
93
+ try {
94
+ const { stdout: npmOutdated } = await execAsync('npm outdated --json');
95
+ this.report.dependencies.outdated = Object.keys(JSON.parse(npmOutdated));
96
+ }
97
+ catch (error) {
98
+ // npm outdated returns error if dependencies are outdated
99
+ if (error instanceof Error && 'stdout' in error) {
100
+ const stdout = error.stdout;
101
+ this.report.dependencies.outdated = Object.keys(JSON.parse(stdout));
102
+ }
103
+ }
104
+ this.spinner.succeed('Dependencies analysis completed');
105
+ }
106
+ async analyzePerformance() {
107
+ this.spinner.start('Analyzing performance');
108
+ // Analyze API endpoints
109
+ const apiPath = path_1.default.join(process.cwd(), 'src/app/api');
110
+ if (fs_1.default.existsSync(apiPath)) {
111
+ this.report.performance.apiEndpoints = this.countApiEndpoints(apiPath);
112
+ }
113
+ // Calculate bundle size
114
+ const buildPath = path_1.default.join(process.cwd(), '.next/static');
115
+ if (fs_1.default.existsSync(buildPath)) {
116
+ this.report.performance.bundleSize = this.calculateBundleSize(buildPath);
117
+ }
118
+ this.spinner.succeed('Performance analysis completed');
119
+ }
120
+ getAllFiles(dir) {
121
+ const files = [];
122
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
123
+ for (const entry of entries) {
124
+ const fullPath = path_1.default.join(dir, entry.name);
125
+ if (entry.isDirectory()) {
126
+ files.push(...this.getAllFiles(fullPath));
127
+ }
128
+ else {
129
+ files.push(fullPath);
130
+ }
131
+ }
132
+ return files;
133
+ }
134
+ countApiEndpoints(dir) {
135
+ const files = this.getAllFiles(dir);
136
+ return files.filter(file => file.endsWith('route.ts')).length;
137
+ }
138
+ calculateBundleSize(dir) {
139
+ let totalSize = 0;
140
+ const files = this.getAllFiles(dir);
141
+ for (const file of files) {
142
+ const stats = fs_1.default.statSync(file);
143
+ totalSize += stats.size;
144
+ }
145
+ return `${Math.round(totalSize / 1024)}KB`;
146
+ }
147
+ displayReport() {
148
+ this.spinner.start('Generating analysis report');
149
+ const report = [
150
+ // Schema Section
151
+ chalk_1.default.cyan.bold('Schema Analysis'),
152
+ chalk_1.default.gray(`├─ Models: ${this.report.schema.models}`),
153
+ chalk_1.default.gray(`├─ Relations: ${this.report.schema.relations}`),
154
+ this.report.schema.complexModels.length > 0
155
+ ? chalk_1.default.gray(`└─ Complex Models: ${this.report.schema.complexModels.join(', ')}`)
156
+ : chalk_1.default.gray('└─ No complex models found'),
157
+ '', // Empty line for spacing
158
+ // Features Section
159
+ chalk_1.default.cyan.bold('Features Analysis'),
160
+ chalk_1.default.gray(`├─ Total Features: ${this.report.features.count}`),
161
+ this.report.features.incomplete.length > 0
162
+ ? chalk_1.default.gray(`└─ Incomplete Features: ${this.report.features.incomplete.join(', ')}`)
163
+ : chalk_1.default.gray('└─ All features are complete'),
164
+ '', // Empty line for spacing
165
+ // Dependencies Section
166
+ chalk_1.default.cyan.bold('Dependencies Analysis'),
167
+ this.report.dependencies.outdated.length > 0
168
+ ? chalk_1.default.gray(`└─ Outdated: ${this.report.dependencies.outdated.join(', ')}`)
169
+ : chalk_1.default.gray('└─ All dependencies are up to date'),
170
+ '', // Empty line for spacing
171
+ // Performance Section
172
+ chalk_1.default.cyan.bold('Performance Analysis'),
173
+ chalk_1.default.gray(`├─ API Endpoints: ${this.report.performance.apiEndpoints}`),
174
+ chalk_1.default.gray(`└─ Bundle Size: ${this.report.performance.bundleSize}`)
175
+ ].join('\n');
176
+ this.spinner.succeed('Analysis report generated');
177
+ // Display the report
178
+ console.log('\n' + report + '\n');
179
+ // Show recommendations if needed
180
+ if (this.report.schema.complexModels.length > 0 ||
181
+ this.report.features.incomplete.length > 0 ||
182
+ this.report.dependencies.outdated.length > 0) {
183
+ this.spinner.info(chalk_1.default.yellow('Recommendations found. Run `igniter analyze --fix` for detailed suggestions.'));
184
+ }
185
+ }
186
+ }
187
+ exports.AnalyzeCommand = AnalyzeCommand;