@sibyllinesoft/arbiter 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.
- package/README.md +222 -0
- package/dist/cli.js +28718 -0
- package/dist/templates/plopfiles/__tests__/build-systems.test.ts +730 -0
- package/dist/templates/plopfiles/__tests__/e2e.test.ts +451 -0
- package/dist/templates/plopfiles/__tests__/generation.test.ts +384 -0
- package/dist/templates/plopfiles/__tests__/linting.test.ts +854 -0
- package/dist/templates/plopfiles/__tests__/modules.test.ts +278 -0
- package/dist/templates/plopfiles/__tests__/smoke.test.ts +619 -0
- package/dist/templates/plopfiles/__tests__/templates.test.ts +341 -0
- package/dist/templates/plopfiles/_modules/backends/go-chi/module.js +43 -0
- package/dist/templates/plopfiles/_modules/backends/go-chi/templates/.air.toml.hbs +30 -0
- package/dist/templates/plopfiles/_modules/backends/go-chi/templates/cmd/server/main.go.hbs +50 -0
- package/dist/templates/plopfiles/_modules/backends/go-chi/templates/go.mod.hbs +9 -0
- package/dist/templates/plopfiles/_modules/backends/go-chi/templates/internal/handlers/health.go.hbs +51 -0
- package/dist/templates/plopfiles/_modules/backends/kotlin-ktor/module.js +38 -0
- package/dist/templates/plopfiles/_modules/backends/kotlin-ktor/templates/build.gradle.kts.hbs +37 -0
- package/dist/templates/plopfiles/_modules/backends/kotlin-ktor/templates/settings.gradle.kts.hbs +1 -0
- package/dist/templates/plopfiles/_modules/backends/kotlin-ktor/templates/src/main/kotlin/Application.kt.hbs +44 -0
- package/dist/templates/plopfiles/_modules/backends/kotlin-ktor/templates/src/main/kotlin/routes/Health.kt.hbs +41 -0
- package/dist/templates/plopfiles/_modules/backends/kotlin-ktor/templates/src/main/resources/logback.xml.hbs +11 -0
- package/dist/templates/plopfiles/_modules/backends/node-express/module.js +54 -0
- package/dist/templates/plopfiles/_modules/backends/node-express/templates/src/index.ts.hbs +37 -0
- package/dist/templates/plopfiles/_modules/backends/node-express/templates/src/routes/health.ts.hbs +21 -0
- package/dist/templates/plopfiles/_modules/backends/node-express/templates/tsconfig.json.hbs +18 -0
- package/dist/templates/plopfiles/_modules/backends/node-hono/module.js +56 -0
- package/dist/templates/plopfiles/_modules/backends/node-hono/templates/src/index.ts.hbs +30 -0
- package/dist/templates/plopfiles/_modules/backends/node-hono/templates/src/routes/health.ts.hbs +64 -0
- package/dist/templates/plopfiles/_modules/backends/node-hono/templates/src/routes/index.ts.hbs +38 -0
- package/dist/templates/plopfiles/_modules/backends/node-hono/templates/tsconfig.json.hbs +20 -0
- package/dist/templates/plopfiles/_modules/backends/node-hono/templates/typedoc.json.hbs +25 -0
- package/dist/templates/plopfiles/_modules/backends/python-fastapi/module.js +65 -0
- package/dist/templates/plopfiles/_modules/backends/python-fastapi/templates/app/__init__.py.hbs +1 -0
- package/dist/templates/plopfiles/_modules/backends/python-fastapi/templates/app/config.py.hbs +28 -0
- package/dist/templates/plopfiles/_modules/backends/python-fastapi/templates/app/main.py.hbs +40 -0
- package/dist/templates/plopfiles/_modules/backends/python-fastapi/templates/app/routers/__init__.py.hbs +1 -0
- package/dist/templates/plopfiles/_modules/backends/python-fastapi/templates/app/routers/health.py.hbs +24 -0
- package/dist/templates/plopfiles/_modules/backends/python-fastapi/templates/pyproject.toml.hbs +40 -0
- package/dist/templates/plopfiles/_modules/backends/python-fastapi/templates/requirements.txt.hbs +6 -0
- package/dist/templates/plopfiles/_modules/backends/rust-axum/module.js +44 -0
- package/dist/templates/plopfiles/_modules/backends/rust-axum/templates/Cargo.toml.hbs +23 -0
- package/dist/templates/plopfiles/_modules/backends/rust-axum/templates/src/health.rs.hbs +41 -0
- package/dist/templates/plopfiles/_modules/backends/rust-axum/templates/src/main.rs.hbs +57 -0
- package/dist/templates/plopfiles/_modules/cloud/aws/module.js +33 -0
- package/dist/templates/plopfiles/_modules/cloud/aws/templates/aws-alb.tf.hbs +92 -0
- package/dist/templates/plopfiles/_modules/cloud/aws/templates/aws-ecs.tf.hbs +84 -0
- package/dist/templates/plopfiles/_modules/cloud/aws/templates/aws-iam.tf.hbs +60 -0
- package/dist/templates/plopfiles/_modules/cloud/aws/templates/aws-vpc.tf.hbs +106 -0
- package/dist/templates/plopfiles/_modules/cloud/aws/templates/aws.tf.hbs +56 -0
- package/dist/templates/plopfiles/_modules/cloud/azure/module.js +31 -0
- package/dist/templates/plopfiles/_modules/cloud/azure/templates/azure-container-apps.tf.hbs +99 -0
- package/dist/templates/plopfiles/_modules/cloud/azure/templates/azure.tf.hbs +54 -0
- package/dist/templates/plopfiles/_modules/cloud/cloudflare/module.js +43 -0
- package/dist/templates/plopfiles/_modules/cloud/cloudflare/templates/src/types.d.ts.hbs +6 -0
- package/dist/templates/plopfiles/_modules/cloud/cloudflare/templates/src/worker.ts.hbs +51 -0
- package/dist/templates/plopfiles/_modules/cloud/cloudflare/templates/wrangler.toml.hbs +36 -0
- package/dist/templates/plopfiles/_modules/cloud/gcp/module.js +31 -0
- package/dist/templates/plopfiles/_modules/cloud/gcp/templates/gcp-cloudrun.tf.hbs +89 -0
- package/dist/templates/plopfiles/_modules/cloud/gcp/templates/gcp.tf.hbs +62 -0
- package/dist/templates/plopfiles/_modules/cloud/supabase/module.js +51 -0
- package/dist/templates/plopfiles/_modules/cloud/supabase/templates/src/lib/supabase.ts.hbs +25 -0
- package/dist/templates/plopfiles/_modules/cloud/supabase/templates/src/types/supabase.ts.hbs +52 -0
- package/dist/templates/plopfiles/_modules/cloud/supabase/templates/supabase/config.toml.hbs +71 -0
- package/dist/templates/plopfiles/_modules/cloud/supabase/templates/supabase/functions/hello/index.ts.hbs +34 -0
- package/dist/templates/plopfiles/_modules/cloud/supabase/templates/supabase/migrations/00000000000000_init.sql.hbs +60 -0
- package/dist/templates/plopfiles/_modules/composer.js +180 -0
- package/dist/templates/plopfiles/_modules/databases/postgres-drizzle/drizzle.config.ts.hbs +10 -0
- package/dist/templates/plopfiles/_modules/databases/postgres-drizzle/module.js +53 -0
- package/dist/templates/plopfiles/_modules/databases/postgres-drizzle/templates/index.ts.hbs +15 -0
- package/dist/templates/plopfiles/_modules/databases/postgres-drizzle/templates/schema.ts.hbs +21 -0
- package/dist/templates/plopfiles/_modules/desktop/electron/module.js +51 -0
- package/dist/templates/plopfiles/_modules/desktop/electron/templates/forge.config.ts.hbs +38 -0
- package/dist/templates/plopfiles/_modules/desktop/electron/templates/package.json.hbs +22 -0
- package/dist/templates/plopfiles/_modules/desktop/electron/templates/src/main.ts.hbs +48 -0
- package/dist/templates/plopfiles/_modules/desktop/electron/templates/src/preload.ts.hbs +18 -0
- package/dist/templates/plopfiles/_modules/desktop/electron/templates/tsconfig.json.hbs +14 -0
- package/dist/templates/plopfiles/_modules/desktop/tauri/module.js +38 -0
- package/dist/templates/plopfiles/_modules/desktop/tauri/templates/src-tauri/Cargo.toml.hbs +20 -0
- package/dist/templates/plopfiles/_modules/desktop/tauri/templates/src-tauri/build.rs.hbs +3 -0
- package/dist/templates/plopfiles/_modules/desktop/tauri/templates/src-tauri/src/main.rs.hbs +30 -0
- package/dist/templates/plopfiles/_modules/desktop/tauri/templates/src-tauri/tauri.conf.json.hbs +44 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/module.js +61 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/architecture/components.md.hbs +37 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/architecture/overview.md.hbs +43 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/contributing/development.md.hbs +164 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/contributing/guidelines.md.hbs +50 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/getting-started/configuration.md.hbs +37 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/getting-started/installation.md.hbs +53 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/getting-started/quickstart.md.hbs +39 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/index.md.hbs +44 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/javascripts/extra.js.hbs +23 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/docs/stylesheets/extra.css.hbs +51 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/mkdocs.yml.hbs +141 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/requirements-docs.txt.hbs +15 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/scripts/aggregate-docs.mjs.hbs +188 -0
- package/dist/templates/plopfiles/_modules/docs/mkdocs/templates/scripts/gen_ref_pages.py.hbs +54 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/module.js +60 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/index.html.hbs +13 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/nginx.conf.hbs +31 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/postcss.config.js.hbs +6 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/src/App.tsx.hbs +12 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/src/index.css.hbs +25 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/src/lib/api.ts.hbs +52 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/src/main.tsx.hbs +18 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/src/pages/Home.tsx.hbs +31 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/tailwind.config.js.hbs +8 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/tsconfig.json.hbs +25 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/tsconfig.node.json.hbs +10 -0
- package/dist/templates/plopfiles/_modules/frontends/react-vite/templates/vite.config.ts.hbs +21 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/module.js +51 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/index.html.hbs +13 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/postcss.config.js.hbs +6 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/src/App.tsx.hbs +12 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/src/index.css.hbs +3 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/src/index.tsx.hbs +21 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/src/lib/api.ts.hbs +52 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/src/pages/Home.tsx.hbs +34 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/tailwind.config.js.hbs +8 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/tsconfig.json.hbs +24 -0
- package/dist/templates/plopfiles/_modules/frontends/solid-vite/templates/vite.config.ts.hbs +21 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/module.js +54 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/index.html.hbs +13 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/postcss.config.js.hbs +6 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/src/App.vue.hbs +9 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/src/index.css.hbs +3 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/src/lib/api.ts.hbs +52 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/src/main.ts.hbs +14 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/src/pages/Home.vue.hbs +27 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/src/router.ts.hbs +13 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/tailwind.config.js.hbs +8 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/tsconfig.json.hbs +25 -0
- package/dist/templates/plopfiles/_modules/frontends/vue-vite/templates/vite.config.ts.hbs +21 -0
- package/dist/templates/plopfiles/_modules/infra/docker-compose/module.js +52 -0
- package/dist/templates/plopfiles/_modules/infra/docker-compose/templates/Dockerfile.backend.hbs +32 -0
- package/dist/templates/plopfiles/_modules/infra/docker-compose/templates/Dockerfile.frontend.hbs +31 -0
- package/dist/templates/plopfiles/_modules/infra/docker-compose/templates/docker-compose.yml.hbs +97 -0
- package/dist/templates/plopfiles/_modules/infra/github-actions/module.js +24 -0
- package/dist/templates/plopfiles/_modules/infra/github-actions/templates/.github/workflows/ci.yml.hbs +78 -0
- package/dist/templates/plopfiles/_modules/infra/github-actions/templates/.github/workflows/deploy.yml.hbs +60 -0
- package/dist/templates/plopfiles/_modules/infra/just/module.js +26 -0
- package/dist/templates/plopfiles/_modules/infra/just/templates/justfile.hbs +205 -0
- package/dist/templates/plopfiles/_modules/infra/kubernetes/module.js +30 -0
- package/dist/templates/plopfiles/_modules/infra/kubernetes/templates/k8s/base/deployment.yaml.hbs +48 -0
- package/dist/templates/plopfiles/_modules/infra/kubernetes/templates/k8s/base/ingress.yaml.hbs +23 -0
- package/dist/templates/plopfiles/_modules/infra/kubernetes/templates/k8s/base/kustomization.yaml.hbs +11 -0
- package/dist/templates/plopfiles/_modules/infra/kubernetes/templates/k8s/base/service.yaml.hbs +15 -0
- package/dist/templates/plopfiles/_modules/infra/kubernetes/templates/k8s/overlays/dev/deployment-patch.yaml.hbs +17 -0
- package/dist/templates/plopfiles/_modules/infra/kubernetes/templates/k8s/overlays/dev/kustomization.yaml.hbs +15 -0
- package/dist/templates/plopfiles/_modules/infra/kubernetes/templates/k8s/overlays/prod/deployment-patch.yaml.hbs +17 -0
- package/dist/templates/plopfiles/_modules/infra/kubernetes/templates/k8s/overlays/prod/kustomization.yaml.hbs +15 -0
- package/dist/templates/plopfiles/_modules/infra/pulumi/module.js +30 -0
- package/dist/templates/plopfiles/_modules/infra/pulumi/templates/.gitignore.hbs +5 -0
- package/dist/templates/plopfiles/_modules/infra/pulumi/templates/Pulumi.dev.yaml.hbs +3 -0
- package/dist/templates/plopfiles/_modules/infra/pulumi/templates/Pulumi.yaml.hbs +7 -0
- package/dist/templates/plopfiles/_modules/infra/pulumi/templates/index.ts.hbs +26 -0
- package/dist/templates/plopfiles/_modules/infra/pulumi/templates/package.json.hbs +12 -0
- package/dist/templates/plopfiles/_modules/infra/pulumi/templates/tsconfig.json.hbs +16 -0
- package/dist/templates/plopfiles/_modules/infra/terraform/module.js +31 -0
- package/dist/templates/plopfiles/_modules/infra/terraform/templates/.gitignore.hbs +12 -0
- package/dist/templates/plopfiles/_modules/infra/terraform/templates/main.tf.hbs +34 -0
- package/dist/templates/plopfiles/_modules/infra/terraform/templates/outputs.tf.hbs +15 -0
- package/dist/templates/plopfiles/_modules/infra/terraform/templates/terraform.tfvars.example.hbs +6 -0
- package/dist/templates/plopfiles/_modules/infra/terraform/templates/variables.tf.hbs +30 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/module.js +38 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/build.gradle.kts.hbs +102 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/proguard-rules.pro.hbs +20 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/src/main/AndroidManifest.xml.hbs +25 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/src/main/kotlin/com/example/app/ApiClient.kt.hbs +38 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/src/main/kotlin/com/example/app/App.kt.hbs +116 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/src/main/kotlin/com/example/app/MainActivity.kt.hbs +28 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/src/main/kotlin/com/example/app/ui/theme/Color.kt.hbs +11 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/src/main/kotlin/com/example/app/ui/theme/Theme.kt.hbs +55 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/src/main/kotlin/com/example/app/ui/theme/Type.kt.hbs +31 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/src/main/res/values/strings.xml.hbs +3 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/app/src/main/res/values/themes.xml.hbs +4 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/build.gradle.kts.hbs +6 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/gradle.properties.hbs +4 -0
- package/dist/templates/plopfiles/_modules/mobile/android-kotlin/templates/settings.gradle.kts.hbs +18 -0
- package/dist/templates/plopfiles/_modules/mobile/flutter/module.js +36 -0
- package/dist/templates/plopfiles/_modules/mobile/flutter/templates/.env.hbs +1 -0
- package/dist/templates/plopfiles/_modules/mobile/flutter/templates/lib/main.dart.hbs +29 -0
- package/dist/templates/plopfiles/_modules/mobile/flutter/templates/lib/screens/home_screen.dart.hbs +88 -0
- package/dist/templates/plopfiles/_modules/mobile/flutter/templates/lib/services/api_service.dart.hbs +61 -0
- package/dist/templates/plopfiles/_modules/mobile/flutter/templates/pubspec.yaml.hbs +25 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/module.js +39 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/templates/App/App.swift.hbs +10 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/templates/App/Assets.xcassets/AccentColor.colorset/Contents.json.hbs +11 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/templates/App/Assets.xcassets/AppIcon.appiconset/Contents.json.hbs +13 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/templates/App/Assets.xcassets/Contents.json.hbs +6 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/templates/App/ContentView.swift.hbs +13 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/templates/App/Services/APIClient.swift.hbs +58 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/templates/App/Views/DetailsView.swift.hbs +22 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/templates/App/Views/HomeView.swift.hbs +62 -0
- package/dist/templates/plopfiles/_modules/mobile/ios-swift/templates/App.xcodeproj/project.pbxproj.hbs +363 -0
- package/dist/templates/plopfiles/_modules/mobile/react-native/module.js +36 -0
- package/dist/templates/plopfiles/_modules/mobile/react-native/templates/app/_layout.tsx.hbs +16 -0
- package/dist/templates/plopfiles/_modules/mobile/react-native/templates/app/index.tsx.hbs +66 -0
- package/dist/templates/plopfiles/_modules/mobile/react-native/templates/app.json.hbs +37 -0
- package/dist/templates/plopfiles/_modules/mobile/react-native/templates/package.json.hbs +29 -0
- package/dist/templates/plopfiles/_modules/mobile/react-native/templates/src/lib/api.ts.hbs +52 -0
- package/dist/templates/plopfiles/_modules/mobile/react-native/templates/tsconfig.json.hbs +11 -0
- package/dist/templates/plopfiles/_modules/quality/biome/module.js +44 -0
- package/dist/templates/plopfiles/_modules/quality/biome/templates/biome.json.hbs +126 -0
- package/dist/templates/plopfiles/_modules/quality/clippy/module.js +40 -0
- package/dist/templates/plopfiles/_modules/quality/clippy/templates/clippy.toml.hbs +29 -0
- package/dist/templates/plopfiles/_modules/quality/clippy/templates/rustfmt.toml.hbs +44 -0
- package/dist/templates/plopfiles/_modules/quality/golangci-lint/module.js +40 -0
- package/dist/templates/plopfiles/_modules/quality/golangci-lint/templates/.golangci.yml.hbs +199 -0
- package/dist/templates/plopfiles/_modules/quality/ruff/module.js +43 -0
- package/dist/templates/plopfiles/_modules/quality/ruff/templates/mypy.ini.hbs +48 -0
- package/dist/templates/plopfiles/_modules/quality/ruff/templates/ruff.toml.hbs +111 -0
- package/dist/templates/plopfiles/_modules/storybook/react-storybook/module.js +54 -0
- package/dist/templates/plopfiles/_modules/storybook/react-storybook/templates/.storybook/main.ts.hbs +44 -0
- package/dist/templates/plopfiles/_modules/storybook/react-storybook/templates/.storybook/preview.ts.hbs +68 -0
- package/dist/templates/plopfiles/_modules/storybook/react-storybook/templates/src/stories/Button.stories.tsx.hbs +158 -0
- package/dist/templates/plopfiles/_modules/types.ts +98 -0
- package/dist/templates/plopfiles/full-stack/plopfile.js +132 -0
- package/dist/templates/plopfiles/full-stack/templates/gitignore.hbs +44 -0
- package/dist/templates/plopfiles/full-stack/templates/package.json.hbs +21 -0
- package/dist/templates/plopfiles/presets/cli-go/module.js +43 -0
- package/dist/templates/plopfiles/presets/cli-go/templates/README.md.hbs +42 -0
- package/dist/templates/plopfiles/presets/cli-go/templates/config.json.hbs +9 -0
- package/dist/templates/plopfiles/presets/cli-node/module.js +45 -0
- package/dist/templates/plopfiles/presets/cli-node/templates/README.md.hbs +42 -0
- package/dist/templates/plopfiles/presets/cli-node/templates/config.json.hbs +9 -0
- package/dist/templates/plopfiles/presets/cli-python/module.js +43 -0
- package/dist/templates/plopfiles/presets/cli-python/templates/README.md.hbs +42 -0
- package/dist/templates/plopfiles/presets/cli-python/templates/config.json.hbs +9 -0
- package/dist/templates/plopfiles/presets/cli-rust/module.js +43 -0
- package/dist/templates/plopfiles/presets/cli-rust/templates/README.md.hbs +42 -0
- package/dist/templates/plopfiles/presets/cli-rust/templates/config.json.hbs +9 -0
- package/dist/templates/plopfiles/presets/loader.js +125 -0
- package/dist/templates/plopfiles/typescript-service/plopfile.js +186 -0
- package/dist/templates/plopfiles/typescript-service/templates/Dockerfile.hbs +29 -0
- package/dist/templates/plopfiles/typescript-service/templates/README.md.hbs +85 -0
- package/dist/templates/plopfiles/typescript-service/templates/config.ts.hbs +15 -0
- package/dist/templates/plopfiles/typescript-service/templates/db/index.ts.hbs +19 -0
- package/dist/templates/plopfiles/typescript-service/templates/db/schema.ts.hbs +16 -0
- package/dist/templates/plopfiles/typescript-service/templates/index.ts.hbs +89 -0
- package/dist/templates/plopfiles/typescript-service/templates/package.json.hbs +36 -0
- package/dist/templates/plopfiles/typescript-service/templates/routes/health.ts.hbs +61 -0
- package/dist/templates/plopfiles/typescript-service/templates/routes/index.ts.hbs +35 -0
- package/dist/templates/plopfiles/typescript-service/templates/tsconfig.json.hbs +24 -0
- package/dist/templates/plopfiles/typescript-service/templates/types.ts.hbs +28 -0
- package/dist/templates/typescript/component.module.css.tpl +6 -0
- package/dist/templates/typescript/component.test.tsx.tpl +9 -0
- package/dist/templates/typescript/component.tsx.tpl +17 -0
- package/dist/templates/typescript/component.types.ts.tpl +3 -0
- package/dist/templates/typescript/project/nextjs/app/globals.css.tpl +10 -0
- package/dist/templates/typescript/project/nextjs/app/layout.tsx.tpl +15 -0
- package/dist/templates/typescript/project/nextjs/app/page.tsx.tpl +8 -0
- package/dist/templates/typescript/project/nextjs/babel.config.js.tpl +8 -0
- package/dist/templates/typescript/project/nextjs/jest.config.js.tpl +10 -0
- package/dist/templates/typescript/project/nextjs/jest.setup.ts.tpl +6 -0
- package/dist/templates/typescript/project/nextjs/next-env.d.ts.tpl +5 -0
- package/dist/templates/typescript/project/nextjs/next.config.js.tpl +9 -0
- package/dist/templates/typescript/project/nextjs/package.json.tpl +1 -0
- package/dist/templates/typescript/project/nextjs/tsconfig.json.tpl +1 -0
- package/dist/templates/typescript/project/vite/App.css.tpl +8 -0
- package/dist/templates/typescript/project/vite/App.tsx.tpl +17 -0
- package/dist/templates/typescript/project/vite/index.css.tpl +8 -0
- package/dist/templates/typescript/project/vite/index.html.tpl +13 -0
- package/dist/templates/typescript/project/vite/main.tsx.tpl +10 -0
- package/dist/templates/typescript/project/vite/package.json.tpl +1 -0
- package/dist/templates/typescript/project/vite/test-setup.ts.tpl +1 -0
- package/dist/templates/typescript/project/vite/tsconfig.build.json.tpl +1 -0
- package/dist/templates/typescript/project/vite/tsconfig.json.tpl +1 -0
- package/dist/templates/typescript/project/vite/tsconfig.node.json.tpl +1 -0
- package/dist/templates/typescript/project/vite/vite.config.ts.tpl +18 -0
- package/dist/templates/typescript/service.api.ts.tpl +27 -0
- package/dist/templates/typescript/service.class.ts.tpl +28 -0
- package/dist/templates/typescript/service.handler.ts.tpl +42 -0
- package/dist/templates/typescript/service.schema.ts.tpl +16 -0
- package/package.json +95 -0
- package/templates/typescript/component.module.css.tpl +6 -0
- package/templates/typescript/component.test.tsx.tpl +9 -0
- package/templates/typescript/component.tsx.tpl +17 -0
- package/templates/typescript/component.types.ts.tpl +3 -0
- package/templates/typescript/project/nextjs/app/globals.css.tpl +10 -0
- package/templates/typescript/project/nextjs/app/layout.tsx.tpl +15 -0
- package/templates/typescript/project/nextjs/app/page.tsx.tpl +8 -0
- package/templates/typescript/project/nextjs/babel.config.js.tpl +8 -0
- package/templates/typescript/project/nextjs/jest.config.js.tpl +10 -0
- package/templates/typescript/project/nextjs/jest.setup.ts.tpl +6 -0
- package/templates/typescript/project/nextjs/next-env.d.ts.tpl +5 -0
- package/templates/typescript/project/nextjs/next.config.js.tpl +9 -0
- package/templates/typescript/project/nextjs/package.json.tpl +1 -0
- package/templates/typescript/project/nextjs/tsconfig.json.tpl +1 -0
- package/templates/typescript/project/vite/App.css.tpl +8 -0
- package/templates/typescript/project/vite/App.tsx.tpl +17 -0
- package/templates/typescript/project/vite/index.css.tpl +8 -0
- package/templates/typescript/project/vite/index.html.tpl +13 -0
- package/templates/typescript/project/vite/main.tsx.tpl +10 -0
- package/templates/typescript/project/vite/package.json.tpl +1 -0
- package/templates/typescript/project/vite/test-setup.ts.tpl +1 -0
- package/templates/typescript/project/vite/tsconfig.build.json.tpl +1 -0
- package/templates/typescript/project/vite/tsconfig.json.tpl +1 -0
- package/templates/typescript/project/vite/tsconfig.node.json.tpl +1 -0
- package/templates/typescript/project/vite/vite.config.ts.tpl +18 -0
- package/templates/typescript/service.api.ts.tpl +27 -0
- package/templates/typescript/service.class.ts.tpl +28 -0
- package/templates/typescript/service.handler.ts.tpl +42 -0
- package/templates/typescript/service.schema.ts.tpl +16 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template File Validation Tests
|
|
3
|
+
*
|
|
4
|
+
* Validates that all template files are valid Handlebars templates
|
|
5
|
+
* and don't have obvious issues.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, expect, test } from "bun:test";
|
|
9
|
+
import { dirname, join } from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
import { readFile, readdir, stat } from "fs/promises";
|
|
12
|
+
import Handlebars from "handlebars";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const MODULES_DIR = join(__dirname, "..", "_modules");
|
|
16
|
+
|
|
17
|
+
// Register common helpers used in templates
|
|
18
|
+
Handlebars.registerHelper(
|
|
19
|
+
"kebabCase",
|
|
20
|
+
(str: string) =>
|
|
21
|
+
str
|
|
22
|
+
?.toLowerCase()
|
|
23
|
+
.replace(/\s+/g, "-")
|
|
24
|
+
.replace(/[^a-z0-9-]/g, "") || "",
|
|
25
|
+
);
|
|
26
|
+
Handlebars.registerHelper(
|
|
27
|
+
"snakeCase",
|
|
28
|
+
(str: string) =>
|
|
29
|
+
str
|
|
30
|
+
?.toLowerCase()
|
|
31
|
+
.replace(/\s+/g, "_")
|
|
32
|
+
.replace(/[^a-z0-9_]/g, "") || "",
|
|
33
|
+
);
|
|
34
|
+
Handlebars.registerHelper("camelCase", (str: string) => {
|
|
35
|
+
if (!str) return "";
|
|
36
|
+
return str.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase());
|
|
37
|
+
});
|
|
38
|
+
Handlebars.registerHelper("pascalCase", (str: string) => {
|
|
39
|
+
if (!str) return "";
|
|
40
|
+
const camel = str.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase());
|
|
41
|
+
return camel.charAt(0).toUpperCase() + camel.slice(1);
|
|
42
|
+
});
|
|
43
|
+
Handlebars.registerHelper(
|
|
44
|
+
"titleCase",
|
|
45
|
+
(str: string) => str?.replace(/\b\w/g, (char) => char.toUpperCase()) || "",
|
|
46
|
+
);
|
|
47
|
+
Handlebars.registerHelper("eq", (a: unknown, b: unknown) => a === b);
|
|
48
|
+
Handlebars.registerHelper("ne", (a: unknown, b: unknown) => a !== b);
|
|
49
|
+
Handlebars.registerHelper("json", (obj: unknown) => JSON.stringify(obj, null, 2));
|
|
50
|
+
Handlebars.registerHelper(
|
|
51
|
+
"has",
|
|
52
|
+
(arr: unknown[] | undefined, value: unknown) => Array.isArray(arr) && arr.includes(value),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Recursively find all .hbs files
|
|
56
|
+
async function findTemplateFiles(dir: string): Promise<string[]> {
|
|
57
|
+
const files: string[] = [];
|
|
58
|
+
|
|
59
|
+
async function walk(currentDir: string) {
|
|
60
|
+
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
const fullPath = join(currentDir, entry.name);
|
|
63
|
+
if (entry.isDirectory()) {
|
|
64
|
+
await walk(fullPath);
|
|
65
|
+
} else if (entry.name.endsWith(".hbs")) {
|
|
66
|
+
files.push(fullPath);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
await walk(dir);
|
|
72
|
+
return files;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Test context for template rendering
|
|
76
|
+
const testContext = {
|
|
77
|
+
name: "test-app",
|
|
78
|
+
projectDir: "/tmp/test",
|
|
79
|
+
backendDir: "backend",
|
|
80
|
+
frontendDir: "frontend",
|
|
81
|
+
desktopDir: "desktop",
|
|
82
|
+
mobileDir: "mobile",
|
|
83
|
+
backend: "node-hono",
|
|
84
|
+
frontend: "react-vite",
|
|
85
|
+
database: "postgres-drizzle",
|
|
86
|
+
environment: "development",
|
|
87
|
+
infra: ["docker-compose", "kubernetes"],
|
|
88
|
+
build: ["bazel", "nx"],
|
|
89
|
+
manifest: {
|
|
90
|
+
dependencies: { test: "^1.0.0" },
|
|
91
|
+
devDependencies: { "test-dev": "^1.0.0" },
|
|
92
|
+
scripts: { test: "echo test" },
|
|
93
|
+
envVars: { TEST: "value" },
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
describe("Template Validation", () => {
|
|
98
|
+
test("all .hbs files are valid Handlebars templates", async () => {
|
|
99
|
+
const templateFiles = await findTemplateFiles(MODULES_DIR);
|
|
100
|
+
const errors: string[] = [];
|
|
101
|
+
|
|
102
|
+
for (const file of templateFiles) {
|
|
103
|
+
try {
|
|
104
|
+
const content = await readFile(file, "utf-8");
|
|
105
|
+
// Try to compile the template
|
|
106
|
+
Handlebars.compile(content);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
errors.push(`${file}: ${error}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (errors.length > 0) {
|
|
113
|
+
console.error("Template compilation errors:");
|
|
114
|
+
errors.forEach((e) => console.error(` - ${e}`));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
expect(errors).toHaveLength(0);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("all .hbs files render without errors", async () => {
|
|
121
|
+
const templateFiles = await findTemplateFiles(MODULES_DIR);
|
|
122
|
+
const errors: string[] = [];
|
|
123
|
+
|
|
124
|
+
for (const file of templateFiles) {
|
|
125
|
+
try {
|
|
126
|
+
const content = await readFile(file, "utf-8");
|
|
127
|
+
const template = Handlebars.compile(content);
|
|
128
|
+
const rendered = template(testContext);
|
|
129
|
+
|
|
130
|
+
// Check for unrendered Handlebars template syntax
|
|
131
|
+
// But exclude other template syntaxes that look similar:
|
|
132
|
+
// - Vue/Angular: {{ expression }}
|
|
133
|
+
// - GitHub Actions: ${{ expression }}
|
|
134
|
+
// - React Native/JSX: ={{ ... }}
|
|
135
|
+
// - Kotlin string templates: ${ }
|
|
136
|
+
if (rendered.includes("{{") && rendered.includes("}}")) {
|
|
137
|
+
const match = rendered.match(/\{\{[^}]+\}\}/g);
|
|
138
|
+
if (match) {
|
|
139
|
+
const unintentional = match.filter((m) => {
|
|
140
|
+
// Skip GitHub Actions syntax
|
|
141
|
+
if (m.includes("${{")) return false;
|
|
142
|
+
// Skip escaped Handlebars
|
|
143
|
+
if (m.includes("\\{{")) return false;
|
|
144
|
+
// Skip Handlebars block syntax in output
|
|
145
|
+
if (m.includes("{{#") || m.includes("{{/") || m.includes("{{>")) return false;
|
|
146
|
+
// Skip Vue/Angular template expressions (typically in .vue files)
|
|
147
|
+
if (file.endsWith(".vue.hbs")) return false;
|
|
148
|
+
// Skip JSX attribute syntax like ={{ }}
|
|
149
|
+
if (m.match(/^=\{\{/)) return false;
|
|
150
|
+
|
|
151
|
+
// Check if it looks like a JavaScript expression (Vue/Angular)
|
|
152
|
+
// These typically have spaces around content or JS operators
|
|
153
|
+
const inner = m.slice(2, -2).trim();
|
|
154
|
+
if (
|
|
155
|
+
inner.includes("JSON.") ||
|
|
156
|
+
inner.includes(".toString") ||
|
|
157
|
+
inner.match(/^\s*\w+\s*$/) || // Simple variable like {{ health }}
|
|
158
|
+
inner.includes(":") // Object literal like {{ title: "..." }}
|
|
159
|
+
) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return true;
|
|
164
|
+
});
|
|
165
|
+
if (unintentional.length > 0) {
|
|
166
|
+
errors.push(`${file}: Unrendered template syntax: ${unintentional.join(", ")}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
errors.push(`${file}: ${error}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (errors.length > 0) {
|
|
176
|
+
console.error("Template rendering errors:");
|
|
177
|
+
errors.forEach((e) => console.error(` - ${e}`));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
expect(errors).toHaveLength(0);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("JSON template files produce valid JSON", async () => {
|
|
184
|
+
const templateFiles = await findTemplateFiles(MODULES_DIR);
|
|
185
|
+
const jsonFiles = templateFiles.filter(
|
|
186
|
+
(f) => f.endsWith(".json.hbs") || f.endsWith("package.json.hbs"),
|
|
187
|
+
);
|
|
188
|
+
const errors: string[] = [];
|
|
189
|
+
|
|
190
|
+
for (const file of jsonFiles) {
|
|
191
|
+
try {
|
|
192
|
+
const content = await readFile(file, "utf-8");
|
|
193
|
+
const template = Handlebars.compile(content);
|
|
194
|
+
const rendered = template(testContext);
|
|
195
|
+
JSON.parse(rendered);
|
|
196
|
+
} catch (error) {
|
|
197
|
+
errors.push(`${file}: ${error}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (errors.length > 0) {
|
|
202
|
+
console.error("JSON validation errors:");
|
|
203
|
+
errors.forEach((e) => console.error(` - ${e}`));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
expect(errors).toHaveLength(0);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("YAML template files don't have obvious syntax errors", async () => {
|
|
210
|
+
const templateFiles = await findTemplateFiles(MODULES_DIR);
|
|
211
|
+
const yamlFiles = templateFiles.filter(
|
|
212
|
+
(f) => f.endsWith(".yaml.hbs") || f.endsWith(".yml.hbs"),
|
|
213
|
+
);
|
|
214
|
+
const errors: string[] = [];
|
|
215
|
+
|
|
216
|
+
for (const file of yamlFiles) {
|
|
217
|
+
try {
|
|
218
|
+
const content = await readFile(file, "utf-8");
|
|
219
|
+
const template = Handlebars.compile(content);
|
|
220
|
+
const rendered = template(testContext);
|
|
221
|
+
|
|
222
|
+
// Basic YAML checks
|
|
223
|
+
const lines = rendered.split("\n");
|
|
224
|
+
for (let i = 0; i < lines.length; i++) {
|
|
225
|
+
const line = lines[i];
|
|
226
|
+
// Check for tabs (YAML doesn't allow tabs for indentation)
|
|
227
|
+
if (line.match(/^\t/)) {
|
|
228
|
+
errors.push(`${file}:${i + 1}: Tab character used for indentation`);
|
|
229
|
+
}
|
|
230
|
+
// Check for obviously broken indentation
|
|
231
|
+
if (line.match(/^(\s*)(\S+):\s*$/) && i + 1 < lines.length) {
|
|
232
|
+
const currentIndent = line.match(/^(\s*)/)?.[1]?.length || 0;
|
|
233
|
+
const nextLine = lines[i + 1];
|
|
234
|
+
const nextIndent = nextLine.match(/^(\s*)/)?.[1]?.length || 0;
|
|
235
|
+
if (
|
|
236
|
+
nextLine.trim() &&
|
|
237
|
+
nextIndent <= currentIndent &&
|
|
238
|
+
!nextLine.trim().startsWith("#")
|
|
239
|
+
) {
|
|
240
|
+
// This might be intentional for empty values, so just warn
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
} catch (error) {
|
|
245
|
+
errors.push(`${file}: ${error}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (errors.length > 0) {
|
|
250
|
+
console.error("YAML validation warnings:");
|
|
251
|
+
errors.forEach((e) => console.error(` - ${e}`));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// YAML warnings shouldn't fail the test, just report
|
|
255
|
+
expect(true).toBe(true);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("TypeScript template files don't have unrendered variables", async () => {
|
|
259
|
+
const templateFiles = await findTemplateFiles(MODULES_DIR);
|
|
260
|
+
const tsFiles = templateFiles.filter((f) => f.endsWith(".ts.hbs") || f.endsWith(".tsx.hbs"));
|
|
261
|
+
const errors: string[] = [];
|
|
262
|
+
|
|
263
|
+
for (const file of tsFiles) {
|
|
264
|
+
try {
|
|
265
|
+
const content = await readFile(file, "utf-8");
|
|
266
|
+
const template = Handlebars.compile(content);
|
|
267
|
+
const rendered = template(testContext);
|
|
268
|
+
|
|
269
|
+
// Check for undefined values that slipped through template rendering
|
|
270
|
+
// But allow valid JS patterns like ternary expressions: `x ? y : undefined`
|
|
271
|
+
const lines = rendered.split("\n");
|
|
272
|
+
for (let i = 0; i < lines.length; i++) {
|
|
273
|
+
const line = lines[i];
|
|
274
|
+
// Check for assignment to undefined (likely template error)
|
|
275
|
+
if (line.match(/\w+\s*=\s*undefined\s*;?\s*$/)) {
|
|
276
|
+
errors.push(`${file}:${i + 1}: Direct assignment to undefined: ${line.trim()}`);
|
|
277
|
+
}
|
|
278
|
+
// Check for property set to undefined (likely template error)
|
|
279
|
+
if (line.match(/:\s*undefined\s*,?\s*$/) && !line.includes("?")) {
|
|
280
|
+
errors.push(`${file}:${i + 1}: Property set to undefined: ${line.trim()}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Check for unrendered Handlebars variables (shows as empty or malformed)
|
|
285
|
+
// Look for patterns that suggest template variables weren't rendered
|
|
286
|
+
if (rendered.match(/\{\{\s*\}\}/)) {
|
|
287
|
+
errors.push(`${file}: Contains empty template expression {{}}`);
|
|
288
|
+
}
|
|
289
|
+
} catch (error) {
|
|
290
|
+
errors.push(`${file}: ${error}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (errors.length > 0) {
|
|
295
|
+
console.error("TypeScript template errors:");
|
|
296
|
+
errors.forEach((e) => console.error(` - ${e}`));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
expect(errors).toHaveLength(0);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
describe("Module Structure Validation", () => {
|
|
304
|
+
const categories = ["backends", "frontends", "databases", "desktop", "mobile", "infra", "cloud"];
|
|
305
|
+
|
|
306
|
+
for (const category of categories) {
|
|
307
|
+
test(`${category} modules have required structure`, async () => {
|
|
308
|
+
const categoryPath = join(MODULES_DIR, category);
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
const entries = await readdir(categoryPath, { withFileTypes: true });
|
|
312
|
+
const modules = entries.filter((e) => e.isDirectory() && !e.name.startsWith("_"));
|
|
313
|
+
|
|
314
|
+
for (const mod of modules) {
|
|
315
|
+
const modulePath = join(categoryPath, mod.name);
|
|
316
|
+
const moduleJsPath = join(modulePath, "module.js");
|
|
317
|
+
|
|
318
|
+
// Check module.js exists
|
|
319
|
+
const moduleJsExists = await stat(moduleJsPath)
|
|
320
|
+
.then(() => true)
|
|
321
|
+
.catch(() => false);
|
|
322
|
+
expect(moduleJsExists).toBe(true);
|
|
323
|
+
|
|
324
|
+
// Check templates directory exists (optional for some modules)
|
|
325
|
+
const templatesPath = join(modulePath, "templates");
|
|
326
|
+
const templatesExist = await stat(templatesPath)
|
|
327
|
+
.then((s) => s.isDirectory())
|
|
328
|
+
.catch(() => false);
|
|
329
|
+
|
|
330
|
+
// Most modules should have templates
|
|
331
|
+
if (!templatesExist) {
|
|
332
|
+
console.warn(`Warning: ${category}/${mod.name} has no templates directory`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
} catch {
|
|
336
|
+
// Category might not exist
|
|
337
|
+
console.warn(`Warning: Category ${category} not found`);
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Go + Chi Backend Module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { dirname, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const templatesDir = resolve(__dirname, "templates");
|
|
10
|
+
|
|
11
|
+
export default function (data) {
|
|
12
|
+
const backendDir = data.backendDir || "backend";
|
|
13
|
+
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
type: "addMany",
|
|
17
|
+
destination: `{{projectDir}}/${backendDir}`,
|
|
18
|
+
base: templatesDir,
|
|
19
|
+
templateFiles: `${templatesDir}/**/*.hbs`,
|
|
20
|
+
stripExtensions: ["hbs"],
|
|
21
|
+
data,
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const description = "Go backend with Chi router";
|
|
27
|
+
|
|
28
|
+
export const scripts = {
|
|
29
|
+
"dev:backend": "cd backend && air",
|
|
30
|
+
"build:backend": "cd backend && go build -o bin/server ./cmd/server",
|
|
31
|
+
"start:backend": "cd backend && ./bin/server",
|
|
32
|
+
"test:backend": "cd backend && go test ./...",
|
|
33
|
+
"lint:backend": "cd backend && golangci-lint run",
|
|
34
|
+
"lint:backend:fix": "cd backend && golangci-lint run --fix",
|
|
35
|
+
"format:backend": "cd backend && gofmt -s -w .",
|
|
36
|
+
"docs:backend": "cd backend && godoc -http=:6060",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const envVars = {
|
|
40
|
+
PORT: "3000",
|
|
41
|
+
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/{{snakeCase name}}",
|
|
42
|
+
GO_ENV: "development",
|
|
43
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
root = "."
|
|
2
|
+
tmp_dir = "tmp"
|
|
3
|
+
|
|
4
|
+
[build]
|
|
5
|
+
cmd = "go build -o ./tmp/main ./cmd/server"
|
|
6
|
+
bin = "./tmp/main"
|
|
7
|
+
delay = 1000
|
|
8
|
+
exclude_dir = ["assets", "tmp", "vendor", "node_modules"]
|
|
9
|
+
exclude_file = []
|
|
10
|
+
exclude_regex = ["_test.go"]
|
|
11
|
+
exclude_unchanged = false
|
|
12
|
+
follow_symlink = false
|
|
13
|
+
include_ext = ["go", "tpl", "tmpl", "html"]
|
|
14
|
+
kill_delay = "0s"
|
|
15
|
+
log = "build-errors.log"
|
|
16
|
+
send_interrupt = false
|
|
17
|
+
stop_on_error = true
|
|
18
|
+
|
|
19
|
+
[color]
|
|
20
|
+
app = ""
|
|
21
|
+
build = "yellow"
|
|
22
|
+
main = "magenta"
|
|
23
|
+
runner = "green"
|
|
24
|
+
watcher = "cyan"
|
|
25
|
+
|
|
26
|
+
[log]
|
|
27
|
+
time = false
|
|
28
|
+
|
|
29
|
+
[misc]
|
|
30
|
+
clean_on_exit = false
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"log"
|
|
6
|
+
"net/http"
|
|
7
|
+
"os"
|
|
8
|
+
|
|
9
|
+
"github.com/go-chi/chi/v5"
|
|
10
|
+
"github.com/go-chi/chi/v5/middleware"
|
|
11
|
+
"github.com/go-chi/cors"
|
|
12
|
+
"github.com/joho/godotenv"
|
|
13
|
+
|
|
14
|
+
"{{kebabCase name}}/internal/handlers"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
func main() {
|
|
18
|
+
// Load .env file
|
|
19
|
+
godotenv.Load()
|
|
20
|
+
|
|
21
|
+
port := os.Getenv("PORT")
|
|
22
|
+
if port == "" {
|
|
23
|
+
port = "3000"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
r := chi.NewRouter()
|
|
27
|
+
|
|
28
|
+
// Middleware
|
|
29
|
+
r.Use(middleware.Logger)
|
|
30
|
+
r.Use(middleware.Recoverer)
|
|
31
|
+
r.Use(middleware.RequestID)
|
|
32
|
+
r.Use(cors.Handler(cors.Options{
|
|
33
|
+
AllowedOrigins: []string{"*"},
|
|
34
|
+
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
|
35
|
+
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type"},
|
|
36
|
+
AllowCredentials: true,
|
|
37
|
+
}))
|
|
38
|
+
|
|
39
|
+
// Routes
|
|
40
|
+
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
|
41
|
+
json.NewEncoder(w).Encode(map[string]string{
|
|
42
|
+
"message": "Welcome to {{titleCase name}} API",
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
r.Mount("/health", handlers.HealthRouter())
|
|
47
|
+
|
|
48
|
+
log.Printf("{{titleCase name}} listening on port %s", port)
|
|
49
|
+
http.ListenAndServe(":"+port, r)
|
|
50
|
+
}
|
package/dist/templates/plopfiles/_modules/backends/go-chi/templates/internal/handlers/health.go.hbs
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
package handlers
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"net/http"
|
|
6
|
+
"time"
|
|
7
|
+
|
|
8
|
+
"github.com/go-chi/chi/v5"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
type HealthResponse struct {
|
|
12
|
+
Status string `json:"status"`
|
|
13
|
+
Timestamp string `json:"timestamp"`
|
|
14
|
+
Service string `json:"service"`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type ReadyResponse struct {
|
|
18
|
+
Ready bool `json:"ready"`
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type LiveResponse struct {
|
|
22
|
+
Alive bool `json:"alive"`
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func HealthRouter() chi.Router {
|
|
26
|
+
r := chi.NewRouter()
|
|
27
|
+
r.Get("/", healthCheck)
|
|
28
|
+
r.Get("/ready", readinessCheck)
|
|
29
|
+
r.Get("/live", livenessCheck)
|
|
30
|
+
return r
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func healthCheck(w http.ResponseWriter, r *http.Request) {
|
|
34
|
+
w.Header().Set("Content-Type", "application/json")
|
|
35
|
+
json.NewEncoder(w).Encode(HealthResponse{
|
|
36
|
+
Status: "ok",
|
|
37
|
+
Timestamp: time.Now().UTC().Format(time.RFC3339),
|
|
38
|
+
Service: "{{kebabCase name}}-backend",
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func readinessCheck(w http.ResponseWriter, r *http.Request) {
|
|
43
|
+
w.Header().Set("Content-Type", "application/json")
|
|
44
|
+
// Add database/service checks here
|
|
45
|
+
json.NewEncoder(w).Encode(ReadyResponse{Ready: true})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
func livenessCheck(w http.ResponseWriter, r *http.Request) {
|
|
49
|
+
w.Header().Set("Content-Type", "application/json")
|
|
50
|
+
json.NewEncoder(w).Encode(LiveResponse{Alive: true})
|
|
51
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kotlin + Ktor Backend Module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { dirname, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const templatesDir = resolve(__dirname, "templates");
|
|
10
|
+
|
|
11
|
+
export default function (data) {
|
|
12
|
+
const backendDir = data.backendDir || "backend";
|
|
13
|
+
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
type: "addMany",
|
|
17
|
+
destination: `{{projectDir}}/${backendDir}`,
|
|
18
|
+
base: templatesDir,
|
|
19
|
+
templateFiles: `${templatesDir}/**/*.hbs`,
|
|
20
|
+
stripExtensions: ["hbs"],
|
|
21
|
+
data,
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const description = "Kotlin backend with Ktor framework";
|
|
27
|
+
|
|
28
|
+
export const scripts = {
|
|
29
|
+
"dev:backend": "cd backend && ./gradlew run --continuous",
|
|
30
|
+
"build:backend": "cd backend && ./gradlew build",
|
|
31
|
+
"start:backend": "cd backend && ./gradlew run",
|
|
32
|
+
"test:backend": "cd backend && ./gradlew test",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const envVars = {
|
|
36
|
+
PORT: "3000",
|
|
37
|
+
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/{{snakeCase name}}",
|
|
38
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
plugins {
|
|
2
|
+
kotlin("jvm") version "1.9.22"
|
|
3
|
+
kotlin("plugin.serialization") version "1.9.22"
|
|
4
|
+
id("io.ktor.plugin") version "2.3.7"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
group = "com.{{snakeCase name}}"
|
|
8
|
+
version = "0.1.0"
|
|
9
|
+
|
|
10
|
+
application {
|
|
11
|
+
mainClass.set("com.{{snakeCase name}}.ApplicationKt")
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
repositories {
|
|
15
|
+
mavenCentral()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
dependencies {
|
|
19
|
+
// Ktor server
|
|
20
|
+
implementation("io.ktor:ktor-server-core-jvm")
|
|
21
|
+
implementation("io.ktor:ktor-server-netty-jvm")
|
|
22
|
+
implementation("io.ktor:ktor-server-content-negotiation-jvm")
|
|
23
|
+
implementation("io.ktor:ktor-serialization-kotlinx-json-jvm")
|
|
24
|
+
implementation("io.ktor:ktor-server-cors-jvm")
|
|
25
|
+
implementation("io.ktor:ktor-server-call-logging-jvm")
|
|
26
|
+
implementation("io.ktor:ktor-server-status-pages-jvm")
|
|
27
|
+
|
|
28
|
+
// Logging
|
|
29
|
+
implementation("ch.qos.logback:logback-classic:1.4.14")
|
|
30
|
+
|
|
31
|
+
// Config
|
|
32
|
+
implementation("io.github.cdimascio:dotenv-kotlin:6.4.1")
|
|
33
|
+
|
|
34
|
+
// Testing
|
|
35
|
+
testImplementation("io.ktor:ktor-server-tests-jvm")
|
|
36
|
+
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.9.22")
|
|
37
|
+
}
|
package/dist/templates/plopfiles/_modules/backends/kotlin-ktor/templates/settings.gradle.kts.hbs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rootProject.name = "{{kebabCase name}}"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package com.{{snakeCase name}}
|
|
2
|
+
|
|
3
|
+
import io.github.cdimascio.dotenv.dotenv
|
|
4
|
+
import io.ktor.serialization.kotlinx.json.*
|
|
5
|
+
import io.ktor.server.application.*
|
|
6
|
+
import io.ktor.server.engine.*
|
|
7
|
+
import io.ktor.server.netty.*
|
|
8
|
+
import io.ktor.server.plugins.contentnegotiation.*
|
|
9
|
+
import io.ktor.server.plugins.cors.routing.*
|
|
10
|
+
import io.ktor.server.plugins.calllogging.*
|
|
11
|
+
import io.ktor.server.response.*
|
|
12
|
+
import io.ktor.server.routing.*
|
|
13
|
+
import kotlinx.serialization.Serializable
|
|
14
|
+
import com.{{snakeCase name}}.routes.healthRoutes
|
|
15
|
+
|
|
16
|
+
val dotenv = dotenv {
|
|
17
|
+
ignoreIfMissing = true
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Serializable
|
|
21
|
+
data class Message(val message: String)
|
|
22
|
+
|
|
23
|
+
fun main() {
|
|
24
|
+
val port = dotenv["PORT"]?.toIntOrNull() ?: 3000
|
|
25
|
+
|
|
26
|
+
embeddedServer(Netty, port = port) {
|
|
27
|
+
install(ContentNegotiation) {
|
|
28
|
+
json()
|
|
29
|
+
}
|
|
30
|
+
install(CORS) {
|
|
31
|
+
anyHost()
|
|
32
|
+
allowHeader("Content-Type")
|
|
33
|
+
allowHeader("Authorization")
|
|
34
|
+
}
|
|
35
|
+
install(CallLogging)
|
|
36
|
+
|
|
37
|
+
routing {
|
|
38
|
+
get("/") {
|
|
39
|
+
call.respond(Message("Welcome to {{titleCase name}} API"))
|
|
40
|
+
}
|
|
41
|
+
healthRoutes()
|
|
42
|
+
}
|
|
43
|
+
}.start(wait = true)
|
|
44
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package com.{{snakeCase name}}.routes
|
|
2
|
+
|
|
3
|
+
import io.ktor.server.application.*
|
|
4
|
+
import io.ktor.server.response.*
|
|
5
|
+
import io.ktor.server.routing.*
|
|
6
|
+
import kotlinx.serialization.Serializable
|
|
7
|
+
import java.time.Instant
|
|
8
|
+
|
|
9
|
+
@Serializable
|
|
10
|
+
data class HealthResponse(
|
|
11
|
+
val status: String,
|
|
12
|
+
val timestamp: String,
|
|
13
|
+
val service: String
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
@Serializable
|
|
17
|
+
data class ReadyResponse(val ready: Boolean)
|
|
18
|
+
|
|
19
|
+
@Serializable
|
|
20
|
+
data class LiveResponse(val alive: Boolean)
|
|
21
|
+
|
|
22
|
+
fun Route.healthRoutes() {
|
|
23
|
+
route("/health") {
|
|
24
|
+
get {
|
|
25
|
+
call.respond(HealthResponse(
|
|
26
|
+
status = "ok",
|
|
27
|
+
timestamp = Instant.now().toString(),
|
|
28
|
+
service = "{{kebabCase name}}-backend"
|
|
29
|
+
))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get("/ready") {
|
|
33
|
+
// Add database/service checks here
|
|
34
|
+
call.respond(ReadyResponse(ready = true))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get("/live") {
|
|
38
|
+
call.respond(LiveResponse(alive = true))
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|