@buenojs/bueno 0.8.4 → 0.8.6
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 +264 -17
- package/dist/cli/{index.js → bin.js} +413 -332
- package/dist/container/index.js +273 -0
- package/dist/context/index.js +219 -0
- package/dist/database/index.js +493 -0
- package/dist/frontend/index.js +7697 -0
- package/dist/graphql/index.js +2156 -0
- package/dist/health/index.js +364 -0
- package/dist/i18n/index.js +345 -0
- package/dist/index.js +9694 -5047
- package/dist/jobs/index.js +819 -0
- package/dist/lock/index.js +367 -0
- package/dist/logger/index.js +281 -0
- package/dist/metrics/index.js +289 -0
- package/dist/middleware/index.js +77 -0
- package/dist/migrations/index.js +571 -0
- package/dist/modules/index.js +3411 -0
- package/dist/notification/index.js +484 -0
- package/dist/observability/index.js +331 -0
- package/dist/openapi/index.js +795 -0
- package/dist/orm/index.js +1356 -0
- package/dist/router/index.js +886 -0
- package/dist/rpc/index.js +691 -0
- package/dist/schema/index.js +400 -0
- package/dist/telemetry/index.js +595 -0
- package/dist/template/index.js +640 -0
- package/dist/templates/index.js +640 -0
- package/dist/testing/index.js +1111 -0
- package/dist/types/index.js +60 -0
- package/llms.txt +231 -0
- package/package.json +125 -27
- package/src/cache/index.ts +2 -1
- package/src/cli/ARCHITECTURE.md +3 -3
- package/src/cli/bin.ts +2 -2
- package/src/cli/commands/build.ts +183 -165
- package/src/cli/commands/dev.ts +96 -89
- package/src/cli/commands/generate.ts +142 -111
- package/src/cli/commands/help.ts +20 -16
- package/src/cli/commands/index.ts +3 -6
- package/src/cli/commands/migration.ts +124 -105
- package/src/cli/commands/new.ts +294 -232
- package/src/cli/commands/start.ts +81 -79
- package/src/cli/core/args.ts +68 -50
- package/src/cli/core/console.ts +89 -95
- package/src/cli/core/index.ts +4 -4
- package/src/cli/core/prompt.ts +65 -62
- package/src/cli/core/spinner.ts +23 -20
- package/src/cli/index.ts +46 -38
- package/src/cli/templates/database/index.ts +37 -18
- package/src/cli/templates/database/mysql.ts +3 -3
- package/src/cli/templates/database/none.ts +2 -2
- package/src/cli/templates/database/postgresql.ts +3 -3
- package/src/cli/templates/database/sqlite.ts +3 -3
- package/src/cli/templates/deploy.ts +29 -26
- package/src/cli/templates/docker.ts +41 -30
- package/src/cli/templates/frontend/index.ts +33 -15
- package/src/cli/templates/frontend/none.ts +2 -2
- package/src/cli/templates/frontend/react.ts +18 -18
- package/src/cli/templates/frontend/solid.ts +15 -15
- package/src/cli/templates/frontend/svelte.ts +17 -17
- package/src/cli/templates/frontend/vue.ts +15 -15
- package/src/cli/templates/generators/index.ts +29 -29
- package/src/cli/templates/generators/types.ts +21 -21
- package/src/cli/templates/index.ts +6 -6
- package/src/cli/templates/project/api.ts +37 -36
- package/src/cli/templates/project/default.ts +25 -25
- package/src/cli/templates/project/fullstack.ts +28 -26
- package/src/cli/templates/project/index.ts +55 -16
- package/src/cli/templates/project/minimal.ts +17 -12
- package/src/cli/templates/project/types.ts +10 -5
- package/src/cli/templates/project/website.ts +15 -15
- package/src/cli/utils/fs.ts +55 -41
- package/src/cli/utils/index.ts +3 -3
- package/src/cli/utils/strings.ts +47 -33
- package/src/cli/utils/version.ts +14 -8
- package/src/config/env-validation.ts +100 -0
- package/src/config/env.ts +169 -41
- package/src/config/index.ts +28 -20
- package/src/config/loader.ts +25 -16
- package/src/config/merge.ts +21 -10
- package/src/config/types.ts +566 -25
- package/src/config/validation.ts +215 -7
- package/src/container/forward-ref.ts +22 -22
- package/src/container/index.ts +34 -12
- package/src/context/index.ts +11 -1
- package/src/database/index.ts +7 -190
- package/src/database/orm/builder.ts +457 -0
- package/src/database/orm/casts/index.ts +130 -0
- package/src/database/orm/casts/types.ts +25 -0
- package/src/database/orm/compiler.ts +304 -0
- package/src/database/orm/hooks/index.ts +114 -0
- package/src/database/orm/index.ts +61 -0
- package/src/database/orm/model-registry.ts +59 -0
- package/src/database/orm/model.ts +821 -0
- package/src/database/orm/relationships/base.ts +146 -0
- package/src/database/orm/relationships/belongs-to-many.ts +179 -0
- package/src/database/orm/relationships/belongs-to.ts +56 -0
- package/src/database/orm/relationships/has-many.ts +45 -0
- package/src/database/orm/relationships/has-one.ts +41 -0
- package/src/database/orm/relationships/index.ts +11 -0
- package/src/database/orm/scopes/index.ts +55 -0
- package/src/events/__tests__/event-system.test.ts +235 -0
- package/src/events/config.ts +238 -0
- package/src/events/example-usage.ts +185 -0
- package/src/events/index.ts +278 -0
- package/src/events/manager.ts +385 -0
- package/src/events/registry.ts +182 -0
- package/src/events/types.ts +124 -0
- package/src/frontend/api-routes.ts +65 -23
- package/src/frontend/bundler.ts +76 -34
- package/src/frontend/console-client.ts +2 -2
- package/src/frontend/console-stream.ts +94 -38
- package/src/frontend/dev-server.ts +94 -46
- package/src/frontend/file-router.ts +61 -19
- package/src/frontend/frameworks/index.ts +37 -10
- package/src/frontend/frameworks/react.ts +10 -8
- package/src/frontend/frameworks/solid.ts +11 -9
- package/src/frontend/frameworks/svelte.ts +15 -9
- package/src/frontend/frameworks/vue.ts +13 -11
- package/src/frontend/hmr-client.ts +12 -10
- package/src/frontend/hmr.ts +146 -103
- package/src/frontend/index.ts +14 -5
- package/src/frontend/islands.ts +41 -22
- package/src/frontend/isr.ts +59 -37
- package/src/frontend/layout.ts +36 -21
- package/src/frontend/ssr/react.ts +74 -27
- package/src/frontend/ssr/solid.ts +54 -20
- package/src/frontend/ssr/svelte.ts +48 -14
- package/src/frontend/ssr/vue.ts +50 -18
- package/src/frontend/ssr.ts +83 -39
- package/src/frontend/types.ts +91 -56
- package/src/graphql/built-in-engine.ts +598 -0
- package/src/graphql/context-builder.ts +110 -0
- package/src/graphql/decorators.ts +358 -0
- package/src/graphql/execution-pipeline.ts +227 -0
- package/src/graphql/graphql-module.ts +563 -0
- package/src/graphql/index.ts +101 -0
- package/src/graphql/metadata.ts +237 -0
- package/src/graphql/schema-builder.ts +319 -0
- package/src/graphql/subscription-handler.ts +283 -0
- package/src/graphql/types.ts +324 -0
- package/src/health/index.ts +21 -9
- package/src/i18n/engine.ts +305 -0
- package/src/i18n/index.ts +38 -0
- package/src/i18n/loader.ts +218 -0
- package/src/i18n/middleware.ts +164 -0
- package/src/i18n/negotiator.ts +162 -0
- package/src/i18n/types.ts +158 -0
- package/src/index.ts +182 -27
- package/src/jobs/drivers/memory.ts +315 -0
- package/src/jobs/drivers/redis.ts +459 -0
- package/src/jobs/index.ts +30 -0
- package/src/jobs/queue.ts +281 -0
- package/src/jobs/types.ts +295 -0
- package/src/jobs/worker.ts +380 -0
- package/src/logger/index.ts +1 -3
- package/src/logger/transports/index.ts +62 -22
- package/src/metrics/index.ts +25 -16
- package/src/migrations/index.ts +9 -0
- package/src/modules/filters.ts +13 -17
- package/src/modules/guards.ts +49 -26
- package/src/modules/index.ts +457 -299
- package/src/modules/interceptors.ts +58 -20
- package/src/modules/lazy.ts +11 -19
- package/src/modules/lifecycle.ts +15 -7
- package/src/modules/metadata.ts +15 -5
- package/src/modules/pipes.ts +94 -72
- package/src/notification/channels/base.ts +68 -0
- package/src/notification/channels/email.ts +105 -0
- package/src/notification/channels/push.ts +104 -0
- package/src/notification/channels/sms.ts +105 -0
- package/src/notification/channels/whatsapp.ts +104 -0
- package/src/notification/index.ts +48 -0
- package/src/notification/service.ts +354 -0
- package/src/notification/types.ts +344 -0
- package/src/observability/__tests__/observability.test.ts +483 -0
- package/src/observability/breadcrumbs.ts +114 -0
- package/src/observability/index.ts +136 -0
- package/src/observability/interceptor.ts +85 -0
- package/src/observability/service.ts +303 -0
- package/src/observability/trace.ts +37 -0
- package/src/observability/types.ts +196 -0
- package/src/openapi/__tests__/decorators.test.ts +335 -0
- package/src/openapi/__tests__/document-builder.test.ts +285 -0
- package/src/openapi/__tests__/route-scanner.test.ts +334 -0
- package/src/openapi/__tests__/schema-generator.test.ts +275 -0
- package/src/openapi/decorators.ts +328 -0
- package/src/openapi/document-builder.ts +274 -0
- package/src/openapi/index.ts +112 -0
- package/src/openapi/metadata.ts +112 -0
- package/src/openapi/route-scanner.ts +289 -0
- package/src/openapi/schema-generator.ts +256 -0
- package/src/openapi/swagger-module.ts +166 -0
- package/src/openapi/types.ts +398 -0
- package/src/orm/index.ts +10 -0
- package/src/rpc/index.ts +3 -1
- package/src/schema/index.ts +9 -0
- package/src/security/index.ts +15 -6
- package/src/ssg/index.ts +9 -8
- package/src/telemetry/index.ts +76 -22
- package/src/template/index.ts +7 -0
- package/src/templates/engine.ts +224 -0
- package/src/templates/index.ts +9 -0
- package/src/templates/loader.ts +331 -0
- package/src/templates/renderers/markdown.ts +212 -0
- package/src/templates/renderers/simple.ts +269 -0
- package/src/templates/types.ts +154 -0
- package/src/testing/index.ts +100 -27
- package/src/types/optional-deps.d.ts +347 -187
- package/src/validation/index.ts +92 -2
- package/src/validation/schemas.ts +536 -0
- package/tests/integration/cli.test.ts +19 -19
- package/tests/integration/fullstack.test.ts +4 -4
- package/tests/unit/cli.test.ts +1 -1
- package/tests/unit/database.test.ts +2 -72
- package/tests/unit/env-validation.test.ts +166 -0
- package/tests/unit/events.test.ts +910 -0
- package/tests/unit/graphql.test.ts +991 -0
- package/tests/unit/i18n.test.ts +455 -0
- package/tests/unit/jobs.test.ts +493 -0
- package/tests/unit/notification.test.ts +988 -0
- package/tests/unit/observability.test.ts +453 -0
- package/tests/unit/orm/builder.test.ts +323 -0
- package/tests/unit/orm/casts.test.ts +179 -0
- package/tests/unit/orm/compiler.test.ts +220 -0
- package/tests/unit/orm/eager-loading.test.ts +285 -0
- package/tests/unit/orm/hooks.test.ts +191 -0
- package/tests/unit/orm/model.test.ts +373 -0
- package/tests/unit/orm/relationships.test.ts +303 -0
- package/tests/unit/orm/scopes.test.ts +74 -0
- package/tests/unit/templates-simple.test.ts +53 -0
- package/tests/unit/templates.test.ts +454 -0
- package/tests/unit/validation.test.ts +18 -24
- package/tsconfig.json +11 -3
|
@@ -13,19 +13,26 @@ export type {
|
|
|
13
13
|
DatabaseDriver,
|
|
14
14
|
TemplateFile,
|
|
15
15
|
SelectOption,
|
|
16
|
-
} from
|
|
16
|
+
} from "./types";
|
|
17
17
|
|
|
18
|
-
import
|
|
19
|
-
import { defaultTemplate } from
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
|
|
18
|
+
import { apiTemplate } from "./api";
|
|
19
|
+
import { defaultTemplate } from "./default";
|
|
20
|
+
import { fullstackTemplate } from "./fullstack";
|
|
21
|
+
import { minimalTemplate } from "./minimal";
|
|
22
|
+
import type {
|
|
23
|
+
ProjectConfig,
|
|
24
|
+
ProjectTemplate,
|
|
25
|
+
ProjectTemplateResult,
|
|
26
|
+
} from "./types";
|
|
27
|
+
import { websiteTemplate } from "./website";
|
|
24
28
|
|
|
25
29
|
/**
|
|
26
30
|
* Project template registry
|
|
27
31
|
*/
|
|
28
|
-
const projectTemplates: Record<
|
|
32
|
+
const projectTemplates: Record<
|
|
33
|
+
ProjectTemplate,
|
|
34
|
+
(config: ProjectConfig) => ProjectTemplateResult
|
|
35
|
+
> = {
|
|
29
36
|
default: defaultTemplate,
|
|
30
37
|
minimal: minimalTemplate,
|
|
31
38
|
fullstack: fullstackTemplate,
|
|
@@ -36,21 +43,53 @@ const projectTemplates: Record<ProjectTemplate, (config: ProjectConfig) => Proje
|
|
|
36
43
|
/**
|
|
37
44
|
* Get project template based on template type
|
|
38
45
|
*/
|
|
39
|
-
export function getProjectTemplate(
|
|
46
|
+
export function getProjectTemplate(
|
|
47
|
+
template: ProjectTemplate,
|
|
48
|
+
): (config: ProjectConfig) => ProjectTemplateResult {
|
|
40
49
|
return projectTemplates[template];
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
/**
|
|
44
53
|
* Get template selection options for prompts
|
|
45
54
|
*/
|
|
46
|
-
export function getTemplateOptions(): {
|
|
55
|
+
export function getTemplateOptions(): {
|
|
56
|
+
value: ProjectTemplate;
|
|
57
|
+
name: string;
|
|
58
|
+
description: string;
|
|
59
|
+
}[] {
|
|
47
60
|
return [
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
{
|
|
62
|
+
value: "default",
|
|
63
|
+
name: "Default",
|
|
64
|
+
description: "Standard project with modules and database",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
value: "minimal",
|
|
68
|
+
name: "Minimal",
|
|
69
|
+
description: "Bare minimum project structure",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
value: "fullstack",
|
|
73
|
+
name: "Fullstack",
|
|
74
|
+
description: "Full-stack project with SSR and frontend",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
value: "api",
|
|
78
|
+
name: "API",
|
|
79
|
+
description: "API-only project without frontend",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
value: "website",
|
|
83
|
+
name: "Website",
|
|
84
|
+
description: "Static website with SSG",
|
|
85
|
+
},
|
|
53
86
|
];
|
|
54
87
|
}
|
|
55
88
|
|
|
56
|
-
export {
|
|
89
|
+
export {
|
|
90
|
+
defaultTemplate,
|
|
91
|
+
minimalTemplate,
|
|
92
|
+
fullstackTemplate,
|
|
93
|
+
apiTemplate,
|
|
94
|
+
websiteTemplate,
|
|
95
|
+
};
|
|
@@ -2,39 +2,44 @@
|
|
|
2
2
|
* Minimal Project Template
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
5
|
+
import { getBuenoDependency } from "../../utils/version";
|
|
6
|
+
import type { ProjectConfig, ProjectTemplateResult } from "./types";
|
|
7
7
|
|
|
8
8
|
export function minimalTemplate(config: ProjectConfig): ProjectTemplateResult {
|
|
9
9
|
return {
|
|
10
10
|
files: [
|
|
11
11
|
{
|
|
12
|
-
path:
|
|
12
|
+
path: "server/main.ts",
|
|
13
13
|
content: `import { createServer } from '@buenojs/bueno';
|
|
14
14
|
|
|
15
15
|
const app = createServer();
|
|
16
16
|
|
|
17
17
|
app.router.get('/', () => {
|
|
18
|
-
|
|
18
|
+
return Response.json({ message: 'Hello, Bueno!' });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
app.router.get('/health', () => {
|
|
22
|
+
return Response.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
19
23
|
});
|
|
20
24
|
|
|
21
25
|
await app.listen(3000);
|
|
26
|
+
console.log('🚀 Server running at http://localhost:3000');
|
|
22
27
|
`,
|
|
23
28
|
},
|
|
24
29
|
],
|
|
25
|
-
directories: [
|
|
30
|
+
directories: ["server", "tests"],
|
|
26
31
|
dependencies: {
|
|
27
32
|
...getBuenoDependency(),
|
|
28
33
|
},
|
|
29
34
|
devDependencies: {
|
|
30
|
-
|
|
31
|
-
typescript:
|
|
35
|
+
"@types/bun": "latest",
|
|
36
|
+
typescript: "^5.3.0",
|
|
32
37
|
},
|
|
33
38
|
scripts: {
|
|
34
|
-
dev:
|
|
35
|
-
build:
|
|
36
|
-
start:
|
|
37
|
-
test:
|
|
39
|
+
dev: "bun run --watch server/main.ts",
|
|
40
|
+
build: "bun build ./server/main.ts --outdir ./dist --target bun",
|
|
41
|
+
start: "bun run dist/main.js",
|
|
42
|
+
test: "bun test",
|
|
38
43
|
},
|
|
39
44
|
};
|
|
40
|
-
}
|
|
45
|
+
}
|
|
@@ -7,22 +7,27 @@
|
|
|
7
7
|
/**
|
|
8
8
|
* Project templates
|
|
9
9
|
*/
|
|
10
|
-
export type ProjectTemplate =
|
|
10
|
+
export type ProjectTemplate =
|
|
11
|
+
| "default"
|
|
12
|
+
| "minimal"
|
|
13
|
+
| "fullstack"
|
|
14
|
+
| "api"
|
|
15
|
+
| "website";
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Frontend frameworks
|
|
14
19
|
*/
|
|
15
|
-
export type FrontendFramework =
|
|
20
|
+
export type FrontendFramework = "react" | "vue" | "svelte" | "solid" | "none";
|
|
16
21
|
|
|
17
22
|
/**
|
|
18
23
|
* Database drivers
|
|
19
24
|
*/
|
|
20
|
-
export type DatabaseDriver =
|
|
25
|
+
export type DatabaseDriver = "sqlite" | "postgresql" | "mysql" | "none";
|
|
21
26
|
|
|
22
27
|
/**
|
|
23
28
|
* Deploy platforms
|
|
24
29
|
*/
|
|
25
|
-
export type DeployPlatform =
|
|
30
|
+
export type DeployPlatform = "render" | "fly" | "railway";
|
|
26
31
|
|
|
27
32
|
/**
|
|
28
33
|
* Project configuration interface
|
|
@@ -86,4 +91,4 @@ export interface SelectOption<T> {
|
|
|
86
91
|
value: T;
|
|
87
92
|
name: string;
|
|
88
93
|
description?: string;
|
|
89
|
-
}
|
|
94
|
+
}
|
|
@@ -4,21 +4,21 @@
|
|
|
4
4
|
* Static website template using SSG (Static Site Generation)
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
7
|
+
import { getBuenoDependency } from "../../utils/version";
|
|
8
|
+
import type { ProjectConfig, ProjectTemplateResult } from "./types";
|
|
9
9
|
|
|
10
10
|
export function websiteTemplate(config: ProjectConfig): ProjectTemplateResult {
|
|
11
11
|
return {
|
|
12
12
|
files: [
|
|
13
13
|
{
|
|
14
|
-
path:
|
|
14
|
+
path: "src/build.ts",
|
|
15
15
|
content: `/**
|
|
16
16
|
* Build script for ${config.name}
|
|
17
17
|
*
|
|
18
18
|
* Uses Bueno's SSG module to generate static HTML from markdown content
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { SSG, createSSG, type SiteConfig, type LayoutContext } from 'bueno';
|
|
21
|
+
import { SSG, createSSG, type SiteConfig, type LayoutContext } from '@buenojs/bueno';
|
|
22
22
|
|
|
23
23
|
// Site configuration
|
|
24
24
|
const siteConfig: Partial<SiteConfig> = {
|
|
@@ -80,7 +80,7 @@ function renderDefaultLayout(ctx: LayoutContext): string {
|
|
|
80
80
|
`,
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
|
-
path:
|
|
83
|
+
path: "src/serve.ts",
|
|
84
84
|
content: `/**
|
|
85
85
|
* Development server for serving the built website
|
|
86
86
|
*/
|
|
@@ -131,7 +131,7 @@ serve();
|
|
|
131
131
|
`,
|
|
132
132
|
},
|
|
133
133
|
{
|
|
134
|
-
path:
|
|
134
|
+
path: "content/index.md",
|
|
135
135
|
content: `---
|
|
136
136
|
title: Welcome
|
|
137
137
|
description: Welcome to my website
|
|
@@ -150,7 +150,7 @@ This is a static website built with [Bueno Framework](https://buenojs.dev).
|
|
|
150
150
|
`,
|
|
151
151
|
},
|
|
152
152
|
{
|
|
153
|
-
path:
|
|
153
|
+
path: "public/styles/main.css",
|
|
154
154
|
content: `/* Main styles for the website */
|
|
155
155
|
* {
|
|
156
156
|
box-sizing: border-box;
|
|
@@ -234,7 +234,7 @@ pre {
|
|
|
234
234
|
`,
|
|
235
235
|
},
|
|
236
236
|
{
|
|
237
|
-
path:
|
|
237
|
+
path: ".env.example",
|
|
238
238
|
content: `# ${config.name} Environment Variables
|
|
239
239
|
# Copy this file to .env and customize as needed
|
|
240
240
|
|
|
@@ -246,18 +246,18 @@ NODE_ENV=development
|
|
|
246
246
|
`,
|
|
247
247
|
},
|
|
248
248
|
],
|
|
249
|
-
directories: [
|
|
249
|
+
directories: ["src", "content", "public/styles", "layouts"],
|
|
250
250
|
dependencies: {
|
|
251
251
|
...getBuenoDependency(),
|
|
252
252
|
},
|
|
253
253
|
devDependencies: {
|
|
254
|
-
|
|
255
|
-
typescript:
|
|
254
|
+
"@types/bun": "latest",
|
|
255
|
+
typescript: "^5.3.0",
|
|
256
256
|
},
|
|
257
257
|
scripts: {
|
|
258
|
-
dev:
|
|
259
|
-
build:
|
|
260
|
-
serve:
|
|
258
|
+
dev: "bun run --watch src/build.ts --dev",
|
|
259
|
+
build: "bun run src/build.ts",
|
|
260
|
+
serve: "bun run src/serve.ts",
|
|
261
261
|
},
|
|
262
262
|
};
|
|
263
|
-
}
|
|
263
|
+
}
|
package/src/cli/utils/fs.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Provides file system operations using Bun's native APIs
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import * as fs from
|
|
8
|
-
import * as path from
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Check if a file exists
|
|
@@ -73,7 +73,7 @@ export async function readFile(filePath: string): Promise<string> {
|
|
|
73
73
|
* Read a file as string (sync)
|
|
74
74
|
*/
|
|
75
75
|
export function readFileSync(filePath: string): string {
|
|
76
|
-
return fs.readFileSync(filePath,
|
|
76
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
@@ -98,7 +98,7 @@ export function writeFileSync(filePath: string, content: string): void {
|
|
|
98
98
|
const dir = path.dirname(filePath);
|
|
99
99
|
createDirectorySync(dir);
|
|
100
100
|
|
|
101
|
-
fs.writeFileSync(filePath, content,
|
|
101
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
/**
|
|
@@ -132,10 +132,7 @@ export function deleteDirectorySync(dirPath: string): void {
|
|
|
132
132
|
/**
|
|
133
133
|
* Copy a file
|
|
134
134
|
*/
|
|
135
|
-
export async function copyFile(
|
|
136
|
-
src: string,
|
|
137
|
-
dest: string,
|
|
138
|
-
): Promise<void> {
|
|
135
|
+
export async function copyFile(src: string, dest: string): Promise<void> {
|
|
139
136
|
// Ensure destination directory exists
|
|
140
137
|
const dir = path.dirname(dest);
|
|
141
138
|
await createDirectory(dir);
|
|
@@ -211,9 +208,9 @@ export async function findFileUp(
|
|
|
211
208
|
options: { stopAt?: string } = {},
|
|
212
209
|
): Promise<string | null> {
|
|
213
210
|
let currentDir = startDir;
|
|
214
|
-
const stopAt = options.stopAt ??
|
|
211
|
+
const stopAt = options.stopAt ?? "/";
|
|
215
212
|
|
|
216
|
-
while (currentDir !== stopAt && currentDir !==
|
|
213
|
+
while (currentDir !== stopAt && currentDir !== "/") {
|
|
217
214
|
const filePath = path.join(currentDir, fileName);
|
|
218
215
|
if (await fileExists(filePath)) {
|
|
219
216
|
return filePath;
|
|
@@ -231,7 +228,7 @@ export async function getProjectRoot(
|
|
|
231
228
|
startDir: string = process.cwd(),
|
|
232
229
|
): Promise<string | null> {
|
|
233
230
|
// Look for package.json as indicator
|
|
234
|
-
const packageJsonPath = await findFileUp(startDir,
|
|
231
|
+
const packageJsonPath = await findFileUp(startDir, "package.json");
|
|
235
232
|
if (packageJsonPath) {
|
|
236
233
|
return path.dirname(packageJsonPath);
|
|
237
234
|
}
|
|
@@ -248,10 +245,10 @@ export async function isBuenoProject(
|
|
|
248
245
|
if (!root) return false;
|
|
249
246
|
|
|
250
247
|
// Check for bueno.config.ts or package.json with bueno dependency
|
|
251
|
-
const configPath = path.join(root,
|
|
248
|
+
const configPath = path.join(root, "bueno.config.ts");
|
|
252
249
|
if (await fileExists(configPath)) return true;
|
|
253
250
|
|
|
254
|
-
const packageJsonPath = path.join(root,
|
|
251
|
+
const packageJsonPath = path.join(root, "package.json");
|
|
255
252
|
if (await fileExists(packageJsonPath)) {
|
|
256
253
|
const content = await readFile(packageJsonPath);
|
|
257
254
|
try {
|
|
@@ -281,9 +278,10 @@ export async function writeJson(
|
|
|
281
278
|
data: unknown,
|
|
282
279
|
options: { pretty?: boolean } = {},
|
|
283
280
|
): Promise<void> {
|
|
284
|
-
const content =
|
|
285
|
-
|
|
286
|
-
|
|
281
|
+
const content =
|
|
282
|
+
options.pretty !== false
|
|
283
|
+
? JSON.stringify(data, null, 2)
|
|
284
|
+
: JSON.stringify(data);
|
|
287
285
|
await writeFile(filePath, content);
|
|
288
286
|
}
|
|
289
287
|
|
|
@@ -326,7 +324,7 @@ export function getExtName(filePath: string): string {
|
|
|
326
324
|
* Normalize path separators
|
|
327
325
|
*/
|
|
328
326
|
export function normalizePath(filePath: string): string {
|
|
329
|
-
return filePath.replace(/\\/g,
|
|
327
|
+
return filePath.replace(/\\/g, "/");
|
|
330
328
|
}
|
|
331
329
|
|
|
332
330
|
/**
|
|
@@ -339,10 +337,7 @@ export interface TemplateData {
|
|
|
339
337
|
/**
|
|
340
338
|
* Process a template string
|
|
341
339
|
*/
|
|
342
|
-
export function processTemplate(
|
|
343
|
-
template: string,
|
|
344
|
-
data: TemplateData,
|
|
345
|
-
): string {
|
|
340
|
+
export function processTemplate(template: string, data: TemplateData): string {
|
|
346
341
|
let result = template;
|
|
347
342
|
|
|
348
343
|
// Process conditionals: {{#if key}}...{{/if}}
|
|
@@ -350,7 +345,7 @@ export function processTemplate(
|
|
|
350
345
|
/\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g,
|
|
351
346
|
(_, key: string, content: string) => {
|
|
352
347
|
const value = data[key];
|
|
353
|
-
return value ? content :
|
|
348
|
+
return value ? content : "";
|
|
354
349
|
},
|
|
355
350
|
);
|
|
356
351
|
|
|
@@ -359,55 +354,74 @@ export function processTemplate(
|
|
|
359
354
|
/\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g,
|
|
360
355
|
(_, key: string, content: string) => {
|
|
361
356
|
const items = data[key];
|
|
362
|
-
if (!Array.isArray(items)) return
|
|
357
|
+
if (!Array.isArray(items)) return "";
|
|
363
358
|
|
|
364
359
|
return items
|
|
365
360
|
.map((item) => {
|
|
366
361
|
let itemContent = content;
|
|
367
|
-
if (typeof item ===
|
|
362
|
+
if (typeof item === "object" && item !== null) {
|
|
368
363
|
// Replace nested properties
|
|
369
364
|
for (const [k, v] of Object.entries(item)) {
|
|
370
365
|
itemContent = itemContent.replace(
|
|
371
|
-
new RegExp(`\\{\\{${k}\\}\\}`,
|
|
366
|
+
new RegExp(`\\{\\{${k}\\}\\}`, "g"),
|
|
372
367
|
String(v),
|
|
373
368
|
);
|
|
374
369
|
}
|
|
375
370
|
}
|
|
376
371
|
return itemContent;
|
|
377
372
|
})
|
|
378
|
-
.join(
|
|
373
|
+
.join("");
|
|
379
374
|
},
|
|
380
375
|
);
|
|
381
376
|
|
|
382
377
|
// Process simple variables with helpers: {{helperName key}}
|
|
383
378
|
const helpers: Record<string, (v: string) => string> = {
|
|
384
379
|
camelCase: (v) =>
|
|
385
|
-
v
|
|
380
|
+
v
|
|
381
|
+
.replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ""))
|
|
382
|
+
.replace(/^(.)/, (c) => c.toLowerCase()),
|
|
386
383
|
pascalCase: (v) =>
|
|
387
|
-
v
|
|
384
|
+
v
|
|
385
|
+
.replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ""))
|
|
386
|
+
.replace(/^(.)/, (c) => c.toUpperCase()),
|
|
388
387
|
kebabCase: (v) =>
|
|
389
|
-
v
|
|
388
|
+
v
|
|
389
|
+
.replace(/([a-z])([A-Z])/g, "$1-$2")
|
|
390
|
+
.replace(/[-_\s]+/g, "-")
|
|
391
|
+
.toLowerCase(),
|
|
390
392
|
snakeCase: (v) =>
|
|
391
|
-
v
|
|
393
|
+
v
|
|
394
|
+
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
395
|
+
.replace(/[-\s]+/g, "_")
|
|
396
|
+
.toLowerCase(),
|
|
392
397
|
upperCase: (v) => v.toUpperCase(),
|
|
393
398
|
lowerCase: (v) => v.toLowerCase(),
|
|
394
399
|
capitalize: (v) => v.charAt(0).toUpperCase() + v.slice(1),
|
|
395
400
|
pluralize: (v) => {
|
|
396
|
-
if (
|
|
397
|
-
|
|
401
|
+
if (
|
|
402
|
+
v.endsWith("y") &&
|
|
403
|
+
!["ay", "ey", "iy", "oy", "uy"].some((e) => v.endsWith(e))
|
|
404
|
+
) {
|
|
405
|
+
return v.slice(0, -1) + "ies";
|
|
398
406
|
}
|
|
399
|
-
if (
|
|
400
|
-
|
|
407
|
+
if (
|
|
408
|
+
v.endsWith("s") ||
|
|
409
|
+
v.endsWith("x") ||
|
|
410
|
+
v.endsWith("z") ||
|
|
411
|
+
v.endsWith("ch") ||
|
|
412
|
+
v.endsWith("sh")
|
|
413
|
+
) {
|
|
414
|
+
return v + "es";
|
|
401
415
|
}
|
|
402
|
-
return v +
|
|
416
|
+
return v + "s";
|
|
403
417
|
},
|
|
404
418
|
};
|
|
405
419
|
|
|
406
420
|
for (const [helperName, helperFn] of Object.entries(helpers)) {
|
|
407
|
-
const regex = new RegExp(`\\{\\{${helperName}\\s+(\\w+)\\}\\}`,
|
|
421
|
+
const regex = new RegExp(`\\{\\{${helperName}\\s+(\\w+)\\}\\}`, "g");
|
|
408
422
|
result = result.replace(regex, (_, key: string) => {
|
|
409
423
|
const value = data[key];
|
|
410
|
-
if (typeof value ===
|
|
424
|
+
if (typeof value === "string") {
|
|
411
425
|
return helperFn(value);
|
|
412
426
|
}
|
|
413
427
|
return String(value);
|
|
@@ -416,13 +430,13 @@ export function processTemplate(
|
|
|
416
430
|
|
|
417
431
|
// Process simple variables: {{key}}
|
|
418
432
|
for (const [key, value] of Object.entries(data)) {
|
|
419
|
-
const regex = new RegExp(`\\{\\{${key}\\}\\}`,
|
|
433
|
+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
|
|
420
434
|
result = result.replace(regex, String(value));
|
|
421
435
|
}
|
|
422
436
|
|
|
423
437
|
// Clean up empty lines left by conditionals
|
|
424
|
-
result = result.replace(/^\s*\n/gm,
|
|
425
|
-
result = result.replace(/\n{3,}/g,
|
|
438
|
+
result = result.replace(/^\s*\n/gm, "\n");
|
|
439
|
+
result = result.replace(/\n{3,}/g, "\n\n");
|
|
426
440
|
|
|
427
441
|
return result.trim();
|
|
428
|
-
}
|
|
442
|
+
}
|
package/src/cli/utils/index.ts
CHANGED