create-win-project 1.3.0 → 2.0.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/LICENSE +1 -1
- package/README.md +58 -160
- package/checks/check-compatibility.js +95 -0
- package/{scripts/verify-generated.mjs → checks/check-generated-project.js} +28 -4
- package/{scripts/validate-content.mjs → checks/check-library.js} +17 -7
- package/checks/check-package.js +15 -0
- package/checks/classify-changes.js +29 -0
- package/checks/run-compatibility-shard.js +21 -0
- package/docs/README.md +20 -0
- package/docs/capabilities.md +13 -0
- package/docs/compatibility.md +13 -0
- package/docs/generated-project.md +12 -0
- package/docs/getting-started.md +26 -0
- package/docs/maintainers/architecture.md +161 -0
- package/docs/maintainers/ci-strategy.md +46 -0
- package/docs/{CONTENT_MODEL.md → maintainers/content-model.md} +3 -3
- package/docs/maintainers/contributing.md +154 -0
- package/docs/{DEPENDENCY_MAINTENANCE.md → maintainers/dependencies.md} +1 -1
- package/docs/migration-v2.md +13 -0
- package/docs/production-contract.md +24 -0
- package/index.js +2 -429
- package/{playbooks → library}/INDEX.md +5 -5
- package/library/compatibility-impact.json +14 -0
- package/{playbooks/capabilities/ci/github-actions.manifest.json → library/development-tools/ci/definition.json} +1 -0
- package/library/development-tools/devops/makefile/commands.md +11 -0
- package/library/development-tools/devops/makefile/definition.json +11 -0
- package/library/development-tools/devops/makefile/docker.md +9 -0
- package/library/development-tools/devops/makefile/validation.md +5 -0
- package/{playbooks/devops/pr-template.manifest.json → library/development-tools/devops/pr-template/definition.json} +1 -0
- package/library/features/sqlalchemy-alembic.md +17 -0
- package/library/optional-features/concerns/zod/errors.md +5 -0
- package/library/optional-features/concerns/zod/testing.md +5 -0
- package/library/optional-features/concerns/zod/validation.md +21 -0
- package/library/optional-features/styling/css-modules/definition.json +12 -0
- package/library/optional-features/styling/css-modules/responsive.md +5 -0
- package/library/optional-features/styling/css-modules/theme.md +7 -0
- package/{playbooks/platform/mobile.manifest.json → library/platforms/mobile/definition.json} +1 -0
- package/{playbooks/platform/web.manifest.json → library/platforms/web/definition.json} +1 -0
- package/{playbooks/stack/react-native.manifest.json → library/stacks/expo/definition.json} +2 -2
- package/library/stacks/fastapi/architecture.md +40 -0
- package/library/stacks/fastapi/definition.json +39 -0
- package/library/stacks/fastapi/runtime.md +25 -0
- package/library/stacks/fastapi/security.md +26 -0
- package/library/stacks/fastapi/structure.md +27 -0
- package/library/stacks/fastapi/testing.md +23 -0
- package/{playbooks/stack/nextjs.manifest.json → library/stacks/nextjs/definition.json} +2 -2
- package/{playbooks/stack/no-frontend.manifest.json → library/stacks/no-frontend/definition.json} +1 -1
- package/{playbooks/stack/react-vite.manifest.json → library/stacks/react-vite/definition.json} +2 -2
- package/{compatibility/profiles.json → library/tested-versions.json} +46 -2
- package/{playbooks/universal/accessibility.manifest.json → library/universal/accessibility/definition.json} +1 -1
- package/library/universal/coding-rules/definition.json +13 -0
- package/library/universal/coding-rules/hygiene.md +9 -0
- package/library/universal/coding-rules/naming.md +17 -0
- package/{playbooks/universal/error-handling.manifest.json → library/universal/error-handling/definition.json} +1 -0
- package/library/universal/git-conventions/branches.md +5 -0
- package/library/universal/git-conventions/commits.md +7 -0
- package/library/universal/git-conventions/definition.json +13 -0
- package/library/universal/git-conventions/workflow.md +5 -0
- package/{playbooks/universal/observability.manifest.json → library/universal/observability/definition.json} +1 -0
- package/{playbooks/universal/security.manifest.json → library/universal/security/definition.json} +1 -0
- package/library/universal/typescript/boundaries.md +13 -0
- package/library/universal/typescript/definition.json +12 -0
- package/library/universal/typescript/errors.md +5 -0
- package/library/universal/typescript/patterns.md +7 -0
- package/package.json +14 -15
- package/public/logo.svg +19 -0
- package/src/cli/arguments.js +63 -0
- package/src/cli/display.js +220 -0
- package/src/cli/main.js +203 -0
- package/src/cli/navigation.js +156 -0
- package/src/cli/questions.js +188 -0
- package/src/cli/system-check.js +158 -0
- package/src/engine/create-project.js +10 -0
- package/src/engine/install-dependencies.js +13 -0
- package/{lib/catalog.js → src/engine/load-library.js} +8 -8
- package/{lib/files.js → src/engine/project-files.js} +10 -1
- package/{lib/playbooks.js → src/engine/project-guidance.js} +26 -3
- package/{lib/application-shapes.js → src/engine/project-shapes.js} +4 -4
- package/{lib/template.js → src/engine/render-templates.js} +11 -0
- package/{lib/compatibility.js → src/engine/tested-versions.js} +21 -2
- package/src/engine/upgrade-report.js +20 -0
- package/src/engine/write-files.js +34 -0
- package/{lib/stacks/registry.js → src/stacks/available-stacks.js} +25 -1
- package/src/stacks/backends/README.md +5 -0
- package/src/stacks/backends/fastapi/ci.js +3 -0
- package/src/stacks/backends/fastapi/create-files.js +874 -0
- package/src/stacks/backends/fastapi/docker.js +75 -0
- package/src/stacks/backends/fastapi/environment.js +3 -0
- package/src/stacks/backends/fastapi/index.js +32 -0
- package/{lib/stacks → src/stacks/backends}/laravel/architecture.js +1 -0
- package/{lib/stacks → src/stacks/backends}/laravel/auth/oidc.js +1 -0
- package/{lib/stacks → src/stacks/backends}/laravel/auth/public.js +1 -0
- package/{lib/stacks → src/stacks/backends}/laravel/auth/sanctum.js +1 -0
- package/{lib/stacks → src/stacks/backends}/laravel/auth/session.js +1 -0
- package/src/stacks/backends/laravel/ci.js +3 -0
- package/{lib/stacks → src/stacks/backends}/laravel/composer.js +1 -1
- package/{lib/stacks/laravel/generate.js → src/stacks/backends/laravel/create-files.js} +1 -0
- package/src/stacks/backends/laravel/docker.js +14 -0
- package/src/stacks/backends/laravel/environment.js +5 -0
- package/{lib/stacks → src/stacks/backends}/laravel/index.js +11 -3
- package/{lib/stacks → src/stacks/backends}/laravel/ui/blade.js +1 -0
- package/{lib/stacks → src/stacks/backends}/laravel/ui/index.js +1 -0
- package/{lib/stacks → src/stacks/backends}/laravel/ui/inertia-react.js +4 -2
- package/{lib/stacks → src/stacks/backends}/laravel/ui/livewire.js +1 -0
- package/{lib/stacks → src/stacks/backends}/laravel/ui/shared.js +1 -0
- package/src/stacks/backends/none/index.js +23 -0
- package/src/stacks/backends/postgres/ci.js +3 -0
- package/src/stacks/backends/postgres/create-files.js +21 -0
- package/src/stacks/backends/postgres/docker.js +3 -0
- package/src/stacks/backends/postgres/environment.js +3 -0
- package/src/stacks/backends/postgres/index.js +30 -0
- package/src/stacks/backends/springboot/ci.js +3 -0
- package/src/stacks/backends/springboot/create-files.js +91 -0
- package/src/stacks/backends/springboot/docker.js +3 -0
- package/src/stacks/backends/springboot/environment.js +3 -0
- package/src/stacks/backends/springboot/index.js +31 -0
- package/src/stacks/backends/supabase/ci.js +3 -0
- package/src/stacks/backends/supabase/create-files.js +52 -0
- package/src/stacks/backends/supabase/docker.js +3 -0
- package/src/stacks/backends/supabase/environment.js +3 -0
- package/src/stacks/backends/supabase/index.js +31 -0
- package/src/stacks/backends/supabase/native.js +14 -0
- package/src/stacks/compose-files.js +259 -0
- package/{lib/generator.js → src/stacks/create-project.js} +206 -57
- package/src/stacks/frontends/README.md +4 -0
- package/src/stacks/frontends/nextjs/ci.js +3 -0
- package/src/stacks/frontends/nextjs/create-files.js +46 -0
- package/src/stacks/frontends/nextjs/dependencies.js +5 -0
- package/src/stacks/frontends/nextjs/docker.js +3 -0
- package/src/stacks/frontends/nextjs/environment.js +7 -0
- package/src/stacks/frontends/nextjs/index.js +35 -0
- package/src/stacks/frontends/react-native/ci.js +3 -0
- package/src/stacks/frontends/react-native/create-files.js +28 -0
- package/src/stacks/frontends/react-native/dependencies.js +5 -0
- package/src/stacks/frontends/react-native/docker.js +5 -0
- package/src/stacks/frontends/react-native/environment.js +7 -0
- package/src/stacks/frontends/react-native/index.js +30 -0
- package/src/stacks/frontends/react-vite/ci.js +3 -0
- package/src/stacks/frontends/react-vite/create-files.js +27 -0
- package/src/stacks/frontends/react-vite/dependencies.js +5 -0
- package/src/stacks/frontends/react-vite/docker.js +3 -0
- package/src/stacks/frontends/react-vite/environment.js +8 -0
- package/src/stacks/frontends/react-vite/index.js +32 -0
- package/src/stacks/shared/capability-packs.js +31 -0
- package/{lib → src}/stacks/shared/contributions.js +1 -1
- package/src/stacks/shared/environment.js +38 -0
- package/src/stacks/shared/javascript-package.js +117 -0
- package/src/stacks/shared/testing-files.js +16 -0
- package/templates/ci/fastapi.yml +62 -0
- package/templates/docker/compose/postgres.yml +1 -1
- package/templates/docker/compose/springboot.yml +3 -3
- package/templates/docker/compose/supabase.yml +1 -1
- package/templates/docker/compose-prod/fastapi.yml +52 -0
- package/templates/docker/compose-prod/springboot.yml +20 -2
- package/templates/docker/dockerfile/fastapi.dev.dockerfile +9 -0
- package/templates/docker/dockerfile/fastapi.prod.dockerfile +11 -0
- package/templates/docker/dockerfile/nextjs.prod.dockerfile +1 -0
- package/templates/docker/dockerfile/springboot.prod.dockerfile +4 -1
- package/templates/docker/dockerfile/vite.prod.dockerfile +2 -1
- package/templates/makefile/fastapi.mk +97 -0
- package/docs/ARCHITECTURE.md +0 -118
- package/lib/banner.js +0 -45
- package/lib/constants.js +0 -3
- package/lib/doctor.js +0 -45
- package/lib/interview.js +0 -77
- package/lib/laravel-scaffold.js +0 -3
- package/lib/scaffold.js +0 -467
- package/lib/stacks/index.js +0 -8
- package/playbooks/concerns/zod.md +0 -174
- package/playbooks/devops/makefile.manifest.json +0 -10
- package/playbooks/devops/makefile.md +0 -556
- package/playbooks/styling/css-modules-extensions.md +0 -267
- package/playbooks/styling/css-modules.manifest.json +0 -11
- package/playbooks/universal/coding-rules.manifest.json +0 -12
- package/playbooks/universal/coding-rules.md +0 -281
- package/playbooks/universal/git-conventions.manifest.json +0 -10
- package/playbooks/universal/git-conventions.md +0 -186
- package/playbooks/universal/typescript.manifest.json +0 -11
- package/playbooks/universal/typescript.md +0 -272
- package/scripts/compatibility-matrix.mjs +0 -48
- /package/{playbooks/capabilities → library/development-tools}/ci/github-actions.md +0 -0
- /package/{playbooks/devops → library/development-tools/devops/pr-template}/pr-template.md +0 -0
- /package/{playbooks/capabilities/docker/docker.manifest.json → library/development-tools/docker/definition.json} +0 -0
- /package/{playbooks/capabilities → library/development-tools}/docker/overview.md +0 -0
- /package/{playbooks/capabilities → library/features}/auth/oidc-resource-server.md +0 -0
- /package/{playbooks/capabilities → library/features}/auth/spring-session.md +0 -0
- /package/{playbooks/capabilities/flyway/flyway.manifest.json → library/features/flyway/definition.json} +0 -0
- /package/{playbooks/capabilities → library/features}/flyway/environments.md +0 -0
- /package/{playbooks/capabilities → library/features}/flyway/migrations.md +0 -0
- /package/{playbooks/capabilities → library/features}/flyway/testing.md +0 -0
- /package/{playbooks/capabilities → library/features}/laravel/database.md +0 -0
- /package/{playbooks/capabilities → library/features}/laravel/migrations.md +0 -0
- /package/{playbooks/capabilities → library/features}/laravel/observability.md +0 -0
- /package/{playbooks/capabilities → library/features}/laravel/oidc-resource-server.md +0 -0
- /package/{playbooks/capabilities → library/features}/laravel/queues.md +0 -0
- /package/{playbooks/capabilities → library/features}/laravel/sanctum-spa.md +0 -0
- /package/{playbooks/capabilities → library/features}/laravel/scheduler.md +0 -0
- /package/{playbooks/capabilities → library/features}/laravel/session-auth.md +0 -0
- /package/{playbooks/capabilities → library/features}/laravel/storage-uploads.md +0 -0
- /package/{playbooks/capabilities → library/features}/postgresql/architecture.md +0 -0
- /package/{playbooks/capabilities/postgresql/postgresql.manifest.json → library/features/postgresql/definition.json} +0 -0
- /package/{playbooks/capabilities → library/features}/postgresql/migrations.md +0 -0
- /package/{playbooks/capabilities → library/features}/postgresql/schema-design.md +0 -0
- /package/{playbooks/capabilities → library/features}/postgresql/security.md +0 -0
- /package/{playbooks/capabilities → library/features}/postgresql/testing.md +0 -0
- /package/{playbooks/capabilities → library/features}/prisma/architecture.md +0 -0
- /package/{playbooks/capabilities/prisma/prisma.manifest.json → library/features/prisma/definition.json} +0 -0
- /package/{playbooks/capabilities → library/features}/prisma/migrations.md +0 -0
- /package/{playbooks/capabilities → library/features}/prisma/runtime.md +0 -0
- /package/{playbooks/capabilities → library/features}/prisma/schema.md +0 -0
- /package/{playbooks/capabilities → library/features}/prisma/testing.md +0 -0
- /package/{playbooks/capabilities → library/features}/supabase/architecture.md +0 -0
- /package/{playbooks/capabilities → library/features}/supabase/authentication.md +0 -0
- /package/{playbooks/capabilities/supabase/supabase.manifest.json → library/features/supabase/definition.json} +0 -0
- /package/{playbooks/capabilities → library/features}/supabase/expo.md +0 -0
- /package/{playbooks/capabilities → library/features}/supabase/migrations.md +0 -0
- /package/{playbooks/capabilities → library/features}/supabase/nextjs.md +0 -0
- /package/{playbooks/capabilities → library/features}/supabase/rls.md +0 -0
- /package/{playbooks/capabilities → library/features}/supabase/testing.md +0 -0
- /package/{playbooks/capabilities → library/features}/supabase/vite.md +0 -0
- /package/{playbooks → library/optional-features}/concerns/axios.md +0 -0
- /package/{playbooks → library/optional-features}/concerns/next-safe-action.md +0 -0
- /package/{playbooks → library/optional-features}/concerns/next-themes.md +0 -0
- /package/{playbooks → library/optional-features}/concerns/nuqs.md +0 -0
- /package/{playbooks → library/optional-features}/concerns/t3-env.md +0 -0
- /package/{playbooks → library/optional-features}/concerns/tanstack-query.md +0 -0
- /package/{playbooks → library/optional-features}/concerns/zustand.md +0 -0
- /package/{playbooks/styling/native-styles.manifest.json → library/optional-features/styling/native-styles/definition.json} +0 -0
- /package/{playbooks/styling → library/optional-features/styling/native-styles}/native-styles.md +0 -0
- /package/{playbooks/styling/tailwind.manifest.json → library/optional-features/styling/tailwind/definition.json} +0 -0
- /package/{playbooks/styling → library/optional-features/styling/tailwind}/tailwind-extensions.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/blade/architecture.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/blade/runtime.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/blade/security.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/blade/structure.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/blade/testing.md +0 -0
- /package/{playbooks/stack/laravel-ui.manifest.json → library/platforms/laravel-ui/definition.json} +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/architecture.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/runtime.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/security.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/structure.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/inertia-react/testing.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/architecture.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/runtime.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/security.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/structure.md +0 -0
- /package/{playbooks/platform → library/platforms}/laravel-ui/livewire/testing.md +0 -0
- /package/{playbooks/platform → library/platforms/mobile}/mobile.md +0 -0
- /package/{playbooks/platform → library/platforms/web}/web.md +0 -0
- /package/{playbooks/stack → library/stacks}/expo/architecture.md +0 -0
- /package/{playbooks/stack → library/stacks}/expo/runtime.md +0 -0
- /package/{playbooks/stack → library/stacks}/expo/security.md +0 -0
- /package/{playbooks/stack → library/stacks}/expo/structure.md +0 -0
- /package/{playbooks/stack → library/stacks}/expo/testing.md +0 -0
- /package/{playbooks/stack → library/stacks}/laravel/architecture.md +0 -0
- /package/{playbooks/stack/laravel.manifest.json → library/stacks/laravel/definition.json} +0 -0
- /package/{playbooks/stack → library/stacks}/laravel/runtime.md +0 -0
- /package/{playbooks/stack → library/stacks}/laravel/security.md +0 -0
- /package/{playbooks/stack → library/stacks}/laravel/structure.md +0 -0
- /package/{playbooks/stack → library/stacks}/laravel/testing.md +0 -0
- /package/{playbooks/stack → library/stacks}/nextjs/architecture.md +0 -0
- /package/{playbooks/stack → library/stacks}/nextjs/runtime.md +0 -0
- /package/{playbooks/stack → library/stacks}/nextjs/security.md +0 -0
- /package/{playbooks/stack → library/stacks}/nextjs/structure.md +0 -0
- /package/{playbooks/stack → library/stacks}/nextjs/testing.md +0 -0
- /package/{playbooks/stack/none.manifest.json → library/stacks/none/definition.json} +0 -0
- /package/{playbooks/stack → library/stacks}/react-vite/architecture.md +0 -0
- /package/{playbooks/stack → library/stacks}/react-vite/runtime.md +0 -0
- /package/{playbooks/stack → library/stacks}/react-vite/security.md +0 -0
- /package/{playbooks/stack → library/stacks}/react-vite/structure.md +0 -0
- /package/{playbooks/stack → library/stacks}/react-vite/testing.md +0 -0
- /package/{playbooks/stack → library/stacks}/springboot/architecture.md +0 -0
- /package/{playbooks/stack/springboot.manifest.json → library/stacks/springboot/definition.json} +0 -0
- /package/{playbooks/stack → library/stacks}/springboot/runtime.md +0 -0
- /package/{playbooks/stack → library/stacks}/springboot/security.md +0 -0
- /package/{playbooks/stack → library/stacks}/springboot/structure.md +0 -0
- /package/{playbooks/stack → library/stacks}/springboot/testing.md +0 -0
- /package/{playbooks/universal → library/universal/accessibility}/accessibility.md +0 -0
- /package/{playbooks/universal → library/universal/error-handling}/error-handling.md +0 -0
- /package/{playbooks/universal → library/universal/observability}/observability.md +0 -0
- /package/{playbooks/universal → library/universal/security}/security.md +0 -0
- /package/{lib → src/engine}/project-location.js +0 -0
- /package/{lib → src}/stacks/context.js +0 -0
- /package/{lib/stacks/contract.js → src/stacks/rules.js} +0 -0
- /package/{ci → templates/ci}/expo.yml +0 -0
- /package/{ci → templates/ci}/laravel.yml +0 -0
- /package/{ci → templates/ci}/nextjs.yml +0 -0
- /package/{ci → templates/ci}/springboot.yml +0 -0
- /package/{ci → templates/ci}/vite.yml +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { defineStackAdapter } from '../../rules.js'
|
|
2
|
+
import { buildSupabaseProjectFiles } from './create-files.js'
|
|
3
|
+
import { ciContributions } from './ci.js'
|
|
4
|
+
import { dockerContributions } from './docker.js'
|
|
5
|
+
import { environmentContributions } from './environment.js'
|
|
6
|
+
|
|
7
|
+
export const supabaseAdapter = defineStackAdapter({
|
|
8
|
+
id: 'supabase',
|
|
9
|
+
kind: 'backend',
|
|
10
|
+
label: 'Supabase',
|
|
11
|
+
compatibleWith: { frontend: ['nextjs', 'react', 'react-native'] },
|
|
12
|
+
capabilities: {
|
|
13
|
+
applicationShapes: ['fullstack', 'separate', 'mobile'],
|
|
14
|
+
architectureProfiles: ['small', 'medium', 'large'],
|
|
15
|
+
authenticationModels: ['public', 'undecided', 'supabase'],
|
|
16
|
+
runtime: 'docker',
|
|
17
|
+
},
|
|
18
|
+
contributes: {
|
|
19
|
+
files: ({ stack }) => Object.entries(buildSupabaseProjectFiles(stack)),
|
|
20
|
+
environment: environmentContributions,
|
|
21
|
+
install: () => [{ cwd: '.', command: 'npm', args: ['run', 'supabase:start'] }],
|
|
22
|
+
docker: dockerContributions,
|
|
23
|
+
ci: ciContributions,
|
|
24
|
+
verification: () => [
|
|
25
|
+
{ frontend: 'nextjs', architecture: 'small', authentication: 'public' },
|
|
26
|
+
{ frontend: 'nextjs', architecture: 'large', authentication: 'supabase' },
|
|
27
|
+
{ frontend: 'react', architecture: 'medium', authentication: 'supabase' },
|
|
28
|
+
{ frontend: 'react-native', architecture: 'medium', authentication: 'supabase' },
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function augmentSupabaseNativeFiles(files, answers, stack) {
|
|
2
|
+
if (stack.backendKey === 'supabase') {
|
|
3
|
+
files['lib/supabase.ts'] = stack.authentication === 'supabase'
|
|
4
|
+
? `import { createClient } from '@supabase/supabase-js'\nimport * as SecureStore from 'expo-secure-store'\n\nconst storage = { getItem: SecureStore.getItemAsync, setItem: SecureStore.setItemAsync, removeItem: SecureStore.deleteItemAsync }\nexport const supabase = createClient(process.env.EXPO_PUBLIC_SUPABASE_URL!, process.env.EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY!, { auth: { storage, persistSession: true, autoRefreshToken: true, detectSessionInUrl: false } })\n`
|
|
5
|
+
: `import { createClient } from '@supabase/supabase-js'\n\nexport const supabase = createClient(process.env.EXPO_PUBLIC_SUPABASE_URL!, process.env.EXPO_PUBLIC_SUPABASE_PUBLISHABLE_KEY!, { auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false } })\n`
|
|
6
|
+
if (stack.authentication === 'supabase') {
|
|
7
|
+
files['lib/supabase-lifecycle.ts'] = `import { AppState, type AppStateStatus } from 'react-native'\nimport { supabase } from './supabase'\n\nexport function bindSupabaseAuthLifecycle() {\n const update = (state: AppStateStatus) => {\n if (state === 'active') supabase.auth.startAutoRefresh()\n else supabase.auth.stopAutoRefresh()\n }\n update(AppState.currentState)\n const subscription = AppState.addEventListener('change', update)\n return () => { subscription.remove(); supabase.auth.stopAutoRefresh() }\n}\n`
|
|
8
|
+
files['app/login.tsx'] = `import { useState } from 'react'\nimport { Pressable, StyleSheet, Text, TextInput, View } from 'react-native'\nimport { supabase } from '@/lib/supabase'\n\nexport default function LoginScreen() {\n const [email, setEmail] = useState('')\n const [password, setPassword] = useState('')\n const [error, setError] = useState('')\n const [pending, setPending] = useState(false)\n async function signIn() {\n setPending(true); setError('')\n const result = await supabase.auth.signInWithPassword({ email: email.trim(), password })\n if (result.error) setError('Unable to sign in with those credentials.')\n setPending(false)\n }\n return <View style={styles.container}><Text accessibilityRole="header">Sign in</Text>{error ? <Text accessibilityRole="alert">{error}</Text> : null}<TextInput accessibilityLabel="Email" autoCapitalize="none" autoComplete="email" keyboardType="email-address" onChangeText={setEmail} value={email} /><TextInput accessibilityLabel="Password" autoComplete="current-password" onChangeText={setPassword} secureTextEntry value={password} /><Pressable accessibilityRole="button" disabled={pending} onPress={signIn}><Text>{pending ? 'Signing in…' : 'Sign in'}</Text></Pressable></View>\n}\nconst styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', padding: 24, gap: 12 } })\n`
|
|
9
|
+
if ((answers.testing || 'basic') !== 'none') files['lib/supabase-lifecycle.test.ts'] = `import { AppState } from 'react-native'\nimport { bindSupabaseAuthLifecycle } from './supabase-lifecycle'\nimport { supabase } from './supabase'\n\njest.mock('./supabase', () => ({ supabase: { auth: { startAutoRefresh: jest.fn(), stopAutoRefresh: jest.fn() } } }))\n\ntest('starts refresh while active and stops it on cleanup', () => {\n const remove = jest.fn()\n jest.spyOn(AppState, 'addEventListener').mockReturnValue({ remove } as never)\n Object.defineProperty(AppState, 'currentState', { configurable: true, value: 'active' })\n const cleanup = bindSupabaseAuthLifecycle()\n expect(supabase.auth.startAutoRefresh).toHaveBeenCalled()\n cleanup()\n expect(remove).toHaveBeenCalled()\n expect(supabase.auth.stopAutoRefresh).toHaveBeenCalled()\n})\n`
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return files
|
|
13
|
+
}
|
|
14
|
+
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { packageVersion } from './shared/javascript-package.js'
|
|
3
|
+
import { stackRegistry } from './available-stacks.js'
|
|
4
|
+
import { capabilityPackFiles } from './shared/capability-packs.js'
|
|
5
|
+
import { collectContributions } from './shared/contributions.js'
|
|
6
|
+
import { buildSharedTestFiles, buildSupabaseWebFiles } from './backends/supabase/create-files.js'
|
|
7
|
+
import { augmentSupabaseNativeFiles } from './backends/supabase/native.js'
|
|
8
|
+
import { addPostgresScripts, buildPostgresFiles } from './backends/postgres/create-files.js'
|
|
9
|
+
import { buildEnvironmentFiles as nextjsEnvironment } from './frontends/nextjs/environment.js'
|
|
10
|
+
import { buildEnvironmentFiles as reactEnvironment } from './frontends/react-vite/environment.js'
|
|
11
|
+
import { buildEnvironmentFiles as nativeEnvironment } from './frontends/react-native/environment.js'
|
|
12
|
+
import { renderEnvironment } from './shared/environment.js'
|
|
13
|
+
|
|
14
|
+
function json(value) {
|
|
15
|
+
return `${JSON.stringify(value, null, 2)}\n`
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function html(value) {
|
|
19
|
+
return String(value).replaceAll('&', '&').replaceAll('"', '"').replaceAll('<', '<').replaceAll('>', '>')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function envFiles(answers, stack) {
|
|
23
|
+
if (stack.frontendKey === 'no-frontend') {
|
|
24
|
+
return { '.env.example': renderEnvironment(stack.env, answers) }
|
|
25
|
+
}
|
|
26
|
+
if (stack.frontendKey === 'react') return reactEnvironment(answers, stack)
|
|
27
|
+
if (stack.isMobile) return nativeEnvironment(answers, stack)
|
|
28
|
+
if (stack.frontendKey === 'nextjs') return nextjsEnvironment(answers, stack)
|
|
29
|
+
return { '.env.example': renderEnvironment(stack.env, answers) }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function projectReadme(answers, stack) {
|
|
33
|
+
if (stack.frontendKey === 'no-frontend') {
|
|
34
|
+
if (stack.backendKey === 'fastapi') {
|
|
35
|
+
return `# ${answers.projectName}\n\n> ${answers.projectDescription}\n\nGenerated backend-only ${stack.backendLabel} application.\n\n## Start\n\n\`\`\`bash\ncp .env.example .env\nuv sync\nalembic upgrade head\nuv run uvicorn app.main:app --reload\n\`\`\`\n\n## Validate\n\n\`\`\`bash\nuv run ruff check . && uv run ruff format --check . && uv run mypy . && uv run pytest\n\`\`\`\n`
|
|
36
|
+
}
|
|
37
|
+
return `# ${answers.projectName}\n\n> ${answers.projectDescription}\n\nGenerated backend-only ${stack.backendLabel} application.\n\n## Start\n\n\`\`\`bash\ncp .env.example .env\ncd backend\n./mvnw spring-boot:run # use mvnw.cmd on Windows\n\`\`\`\n\n## Validate\n\n\`\`\`bash\ncd backend\n./mvnw --batch-mode test\n./mvnw --batch-mode package -DskipTests\n\`\`\`\n`
|
|
38
|
+
}
|
|
39
|
+
const root = stack.frontendKey === 'react' ? 'frontend/' : ''
|
|
40
|
+
const quality = stack.isMobile
|
|
41
|
+
? `npm run typecheck\n${answers.testing === 'none' ? '' : 'npm test -- --runInBand\n'}npm run build -- --platform web`
|
|
42
|
+
: `npm run lint\nnpm run typecheck\nnpm run test --if-present\nnpm run build`
|
|
43
|
+
const backend = stack.backendKey === 'springboot'
|
|
44
|
+
? `\nThe backend lives in \`backend/\`:\n\n\`\`\`bash\ncd backend\nmvn spring-boot:run\n# verify: curl http://localhost:8080/api/health\n\`\`\`\n`
|
|
45
|
+
: ''
|
|
46
|
+
return `# ${answers.projectName}\n\n> ${answers.projectDescription}\n\nGenerated with create-win-project. This repository includes a runnable application, tests, CI guidance, and task-routed agent playbooks.\n\n## Start\n\n\`\`\`bash\n${root ? `cd ${root}\n` : ''}cp .env.example .env.local 2>/dev/null || cp .env.example .env\nnpm install\nnpm run dev\n\`\`\`\n${backend}\n## Validate\n\n\`\`\`bash\n${root ? `cd ${root}\n` : ''}${quality}\n\`\`\`\n\nCommit the generated lockfile before enabling CI; CI intentionally uses \`npm ci\`.\n\n## Agent-assisted work\n\n1. Put product goals and boundaries in \`CONTEXT.md\`.\n2. Read \`AGENTS.md\` for commands and authority boundaries.\n3. Use \`RULES.md\` to open only the relevant playbook section.\n4. Treat tests and application behavior as the source of truth when prose drifts.\n\n## Important files\n\n- \`AGENTS.md\`: small always-on operating contract.\n- \`RULES.md\`: concern-to-playbook router.\n- \`CONTEXT.md\`: project-specific intent and decisions.\n- \`docs/\`: architecture, API, setup, and deployment documentation.\n`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function testingPackage(stack, level) {
|
|
50
|
+
const scripts = { ...stack.scripts, start: stack.frontendKey === 'nextjs' ? 'next start' : undefined }
|
|
51
|
+
const devDeps = { ...stack.devDeps }
|
|
52
|
+
|
|
53
|
+
if (level === 'none') delete scripts.test
|
|
54
|
+
if (level !== 'none') {
|
|
55
|
+
if (stack.isMobile) {
|
|
56
|
+
Object.assign(devDeps, {
|
|
57
|
+
jest: packageVersion(stack.profile, 'jest', 'react-native'),
|
|
58
|
+
'@types/jest': packageVersion(stack.profile, '@types/jest', 'react-native'),
|
|
59
|
+
'jest-expo': packageVersion(stack.profile, 'jest-expo', 'react-native'),
|
|
60
|
+
'@testing-library/react-native': packageVersion(stack.profile, '@testing-library/react-native', 'react-native'),
|
|
61
|
+
})
|
|
62
|
+
} else {
|
|
63
|
+
Object.assign(devDeps, {
|
|
64
|
+
vitest: packageVersion(stack.profile, 'vitest', stack.frontendKey),
|
|
65
|
+
jsdom: packageVersion(stack.profile, 'jsdom', stack.frontendKey),
|
|
66
|
+
'@testing-library/react': packageVersion(stack.profile, '@testing-library/react', stack.frontendKey),
|
|
67
|
+
'@testing-library/jest-dom': packageVersion(stack.profile, '@testing-library/jest-dom', stack.frontendKey),
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (level === 'full' && !stack.isMobile) {
|
|
72
|
+
scripts['test:e2e'] = 'playwright test'
|
|
73
|
+
devDeps['@playwright/test'] = packageVersion(stack.profile, '@playwright/test', stack.frontendKey)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
scripts.typecheck = 'tsc --noEmit'
|
|
77
|
+
scripts.format = 'prettier --write .'
|
|
78
|
+
scripts['format:check'] = 'prettier --check .'
|
|
79
|
+
if (!stack.isMobile) scripts.lint = 'eslint .'
|
|
80
|
+
if (stack.architecture === 'large') scripts['check:boundaries'] = 'node scripts/check-boundaries.mjs'
|
|
81
|
+
if (stack.backendKey === 'supabase') {
|
|
82
|
+
const workdir = stack.frontendKey === 'react' ? ' --workdir ..' : ''
|
|
83
|
+
scripts['supabase:start'] = `supabase${workdir} start`
|
|
84
|
+
scripts['supabase:stop'] = `supabase${workdir} stop`
|
|
85
|
+
scripts['supabase:status'] = `supabase${workdir} status`
|
|
86
|
+
scripts['supabase:reset'] = `supabase${workdir} db reset`
|
|
87
|
+
scripts['supabase:test'] = `supabase${workdir} test db`
|
|
88
|
+
const typePath = stack.frontendKey === 'react' ? 'src/types/database.types.ts' : stack.isMobile ? 'types/database.types.ts' : 'src/types/database.types.ts'
|
|
89
|
+
scripts['supabase:types'] = `supabase${workdir} gen types typescript --local > ${typePath}`
|
|
90
|
+
}
|
|
91
|
+
const boundaryCheck = stack.architecture === 'large' ? ' && npm run check:boundaries' : ''
|
|
92
|
+
scripts.check = stack.isMobile
|
|
93
|
+
? `npm run format:check && npm run typecheck${level === 'none' ? '' : ' && npm test -- --runInBand'}${boundaryCheck}`
|
|
94
|
+
: `npm run format:check && npm run lint && npm run typecheck${level === 'none' ? '' : ' && npm test'}${boundaryCheck}`
|
|
95
|
+
Object.keys(scripts).forEach((key) => scripts[key] === undefined && delete scripts[key])
|
|
96
|
+
return { scripts, devDeps }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function packageFile(answers, stack) {
|
|
100
|
+
const { scripts, devDeps } = testingPackage(stack, answers.testing || 'basic')
|
|
101
|
+
if (stack.backendKey === 'postgres') {
|
|
102
|
+
addPostgresScripts(scripts)
|
|
103
|
+
}
|
|
104
|
+
if (stack.styleId === 'tailwind') {
|
|
105
|
+
devDeps.tailwindcss = packageVersion(stack.profile, 'tailwindcss', stack.frontendKey)
|
|
106
|
+
if (stack.frontendKey === 'nextjs') devDeps['@tailwindcss/postcss'] = packageVersion(stack.profile, '@tailwindcss/postcss', 'nextjs')
|
|
107
|
+
if (stack.frontendKey === 'react') devDeps['@tailwindcss/vite'] = packageVersion(stack.profile, '@tailwindcss/vite', 'react')
|
|
108
|
+
}
|
|
109
|
+
const dependencies = { ...stack.deps }
|
|
110
|
+
if (stack.frontendKey !== 'nextjs') delete dependencies['@supabase/ssr']
|
|
111
|
+
if (stack.isMobile && stack.authentication === 'supabase') {
|
|
112
|
+
dependencies['expo-secure-store'] = packageVersion(stack.profile, 'expo-secure-store', 'react-native')
|
|
113
|
+
}
|
|
114
|
+
const packageJson = {
|
|
115
|
+
name: answers.projectName,
|
|
116
|
+
version: '0.1.0',
|
|
117
|
+
private: true,
|
|
118
|
+
type: 'module',
|
|
119
|
+
packageManager: `npm@${stack.profile.runtimes.npmMinimum}`,
|
|
120
|
+
engines: {
|
|
121
|
+
node: `>=${stack.profile.runtimes.nodeMinimum}`,
|
|
122
|
+
npm: `>=${stack.profile.runtimes.npmMinimum}`,
|
|
123
|
+
},
|
|
124
|
+
main: stack.isMobile ? 'expo-router/entry' : undefined,
|
|
125
|
+
scripts,
|
|
126
|
+
dependencies,
|
|
127
|
+
devDependencies: devDeps,
|
|
128
|
+
}
|
|
129
|
+
if (!packageJson.main) delete packageJson.main
|
|
130
|
+
return json(packageJson)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function boundaryScript(sourceRoot) {
|
|
134
|
+
return `/* eslint-disable no-undef -- node script runs outside linted frontend bundle */
|
|
135
|
+
import fs from 'node:fs'\nimport path from 'node:path'\n\nconst root = path.resolve(${JSON.stringify(sourceRoot)}, 'features')\nconst violations = []\nif (fs.existsSync(root)) {\n for (const feature of fs.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name)) {\n const featureRoot = path.join(root, feature)\n const visit = (directory) => {\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const file = path.join(directory, entry.name)\n if (entry.isDirectory()) visit(file)\n else if (/\\.[cm]?[jt]sx?$/.test(entry.name)) {\n const content = fs.readFileSync(file, 'utf8')\n for (const match of content.matchAll(/from\\s+['\"]@\\/features\\/([^/'\"]+)(\\/[^'\"]+)?['\"]/g)) {\n if (match[1] !== feature && match[2]) violations.push(\`${'${file}'} deep-imports feature ${'${match[1]}'}; import its public API instead\`)\n }\n }\n }\n }\n visit(featureRoot)\n }\n}\nif (violations.length) { console.error(violations.join('\\n')); process.exit(1) }\nconsole.log('Feature boundaries are valid.')\n`
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function statusFeatureFiles(root, stack) {
|
|
139
|
+
if (stack.architecture === 'small') return {}
|
|
140
|
+
const prefix = root ? `${root}/` : ''
|
|
141
|
+
const files = {
|
|
142
|
+
[`${prefix}src/features/status/types.ts`]: "export interface StarterStatus { heading: string; profile: 'medium' | 'large' }\n",
|
|
143
|
+
[`${prefix}src/features/status/services/getStarterStatus.ts`]: `import type { StarterStatus } from '../types'\n\nexport function getStarterStatus(): StarterStatus {\n return { heading: 'Your starter is running', profile: '${stack.architecture}' }\n}\n`,
|
|
144
|
+
[`${prefix}src/features/status/components/StarterStatus.tsx`]: "import type { StarterStatus as Status } from '../types'\n\nexport function StarterStatus({ status }: { status: Status }) {\n return <><h1>{status.heading}</h1><p>Architecture: {status.profile}</p></>\n}\n",
|
|
145
|
+
}
|
|
146
|
+
if (stack.backendKey === 'springboot') {
|
|
147
|
+
const baseUrl = stack.frontendKey === 'nextjs' ? 'process.env.NEXT_PUBLIC_API_URL' : 'import.meta.env.VITE_API_URL'
|
|
148
|
+
files[`${prefix}src/features/status/api/getBackendStatus.ts`] = `export interface BackendStatus { status: string }\n\nexport async function getBackendStatus(signal?: AbortSignal): Promise<BackendStatus> {\n const response = await fetch(\`${'${' + baseUrl + '}'}/api/health\`, { signal })\n if (!response.ok) throw new Error(\`Backend health request failed (${'${response.status}'})\`)\n return response.json() as Promise<BackendStatus>\n}\n`
|
|
149
|
+
}
|
|
150
|
+
if (stack.architecture === 'large') {
|
|
151
|
+
files[`${prefix}src/features/status/index.ts`] = "export { StarterStatus } from './components/StarterStatus'\nexport { getStarterStatus } from './services/getStarterStatus'\nexport type { StarterStatus as StarterStatusModel } from './types'\n"
|
|
152
|
+
files[`${prefix}scripts/check-boundaries.mjs`] = boundaryScript(prefix ? 'src' : 'src')
|
|
153
|
+
}
|
|
154
|
+
return files
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function nativeStatusFeatureFiles(stack) {
|
|
158
|
+
if (stack.architecture === 'small') return {}
|
|
159
|
+
const files = {
|
|
160
|
+
'features/status/types.ts': "export interface StarterStatus { heading: string; profile: 'medium' | 'large' }\n",
|
|
161
|
+
'features/status/services/getStarterStatus.ts': `import type { StarterStatus } from '../types'\n\nexport function getStarterStatus(): StarterStatus {\n return { heading: 'Your starter is running', profile: '${stack.architecture}' }\n}\n`,
|
|
162
|
+
'features/status/components/StarterStatus.tsx': "import { Text } from 'react-native'\nimport type { StarterStatus as Status } from '../types'\n\nexport function StarterStatus({ status }: { status: Status }) {\n return <><Text accessibilityRole=\"header\">{status.heading}</Text><Text>Architecture: {status.profile}</Text></>\n}\n",
|
|
163
|
+
}
|
|
164
|
+
if (stack.backendKey === 'springboot') {
|
|
165
|
+
files['features/status/api/getBackendStatus.ts'] = "export interface BackendStatus { status: string }\n\nexport async function getBackendStatus(signal?: AbortSignal): Promise<BackendStatus> {\n const response = await fetch(`${process.env.EXPO_PUBLIC_API_URL}/api/health`, { signal })\n if (!response.ok) throw new Error(`Backend health request failed (${response.status})`)\n return response.json() as Promise<BackendStatus>\n}\n"
|
|
166
|
+
}
|
|
167
|
+
if (stack.architecture === 'large') {
|
|
168
|
+
files['features/status/index.ts'] = "export { StarterStatus } from './components/StarterStatus'\nexport { getStarterStatus } from './services/getStarterStatus'\nexport type { StarterStatus as StarterStatusModel } from './types'\n"
|
|
169
|
+
files['scripts/check-boundaries.mjs'] = boundaryScript('.')
|
|
170
|
+
}
|
|
171
|
+
return files
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function supabaseWebFiles(isNext, withAuth = false) {
|
|
175
|
+
return buildSupabaseWebFiles(isNext, withAuth)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const testFiles = buildSharedTestFiles
|
|
179
|
+
|
|
180
|
+
function prismaFiles() {
|
|
181
|
+
return buildPostgresFiles()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function augmentViteFiles(files, stack) {
|
|
185
|
+
const root = 'frontend'
|
|
186
|
+
if (stack.backendKey === 'supabase') {
|
|
187
|
+
for (const [name, value] of Object.entries(supabaseWebFiles(false, stack.authentication === 'supabase'))) files[`${root}/${name}`] = value
|
|
188
|
+
if (stack.authentication === 'supabase') {
|
|
189
|
+
files[`${root}/src/features/auth/services/auth.ts`] = `import { supabase } from '@/lib/supabase'\n\nexport async function signIn(email: string, password: string) {\n const { error } = await supabase.auth.signInWithPassword({ email, password })\n if (error) throw new Error('Unable to sign in with those credentials.')\n}\n\nexport async function signOut() {\n const { error } = await supabase.auth.signOut()\n if (error) throw new Error('Unable to sign out.')\n}\n`
|
|
190
|
+
files[`${root}/src/features/auth/components/AuthPanel.tsx`] = `import { useState, type FormEvent } from 'react'\nimport { signIn } from '../services/auth'\n\nexport function AuthPanel() {\n const [error, setError] = useState('')\n const [pending, setPending] = useState(false)\n async function submit(event: FormEvent<HTMLFormElement>) {\n event.preventDefault()\n setPending(true)\n setError('')\n const data = new FormData(event.currentTarget)\n try { await signIn(String(data.get('email') || ''), String(data.get('password') || '')) }\n catch (reason) { setError(reason instanceof Error ? reason.message : 'Unable to sign in.') }\n finally { setPending(false) }\n }\n return <section aria-labelledby="login-heading"><h2 id="login-heading">Sign in</h2>{error ? <p role="alert">{error}</p> : null}<form onSubmit={submit}><label>Email <input name="email" type="email" autoComplete="email" required /></label><label>Password <input name="password" type="password" autoComplete="current-password" required /></label><button disabled={pending} type="submit">{pending ? 'Signing in…' : 'Sign in'}</button></form></section>\n}\n`
|
|
191
|
+
files[`${root}/src/App.tsx`] = `import { AuthPanel } from '@/features/auth/components/AuthPanel'\n${files[`${root}/src/App.tsx`].replace('<p>Read <code>AGENTS.md</code> before your first agent-assisted change.</p>', '<p>Read <code>AGENTS.md</code> before your first agent-assisted change.</p><AuthPanel />')}`
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return files
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function nativeFiles(answers, stack) {
|
|
198
|
+
const files = frontendFiles(answers, stack)
|
|
199
|
+
augmentSupabaseNativeFiles(files, answers, stack)
|
|
200
|
+
return files
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function frontendFiles(answers, stack) {
|
|
204
|
+
if (stack.frontendKey === 'no-frontend' || stack.frontendKey === 'laravel-ui') return {}
|
|
205
|
+
const adapter = stackRegistry.require(stack.frontendKey)
|
|
206
|
+
return Object.fromEntries(collectContributions([adapter], 'files', {
|
|
207
|
+
answers,
|
|
208
|
+
stack,
|
|
209
|
+
shared: { json, packageFile, testFiles, statusFeatureFiles, nativeStatusFeatureFiles, supabaseWebFiles, prismaFiles },
|
|
210
|
+
}))
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function springFiles(answers, vars, stack) {
|
|
214
|
+
const adapter = stackRegistry.require(stack.backendKey)
|
|
215
|
+
return Object.fromEntries(collectContributions([adapter], 'files', { answers, stack, vars }))
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function buildRunnableFiles(answers, stack, vars) {
|
|
219
|
+
let files = stack.isMobile ? nativeFiles(answers, stack) : frontendFiles(answers, stack)
|
|
220
|
+
if (stack.frontendKey === 'react') files = augmentViteFiles(files, stack)
|
|
221
|
+
Object.assign(files, envFiles(answers, stack))
|
|
222
|
+
Object.assign(files, capabilityPackFiles(answers, stack))
|
|
223
|
+
files['create-win-project.profile.json'] = json({
|
|
224
|
+
schemaVersion: 2,
|
|
225
|
+
applicationShape: stack.applicationShape,
|
|
226
|
+
compatibilityProfile: {
|
|
227
|
+
id: stack.profile.id,
|
|
228
|
+
status: stack.profile.status,
|
|
229
|
+
supportedUntil: stack.profile.supportedUntil,
|
|
230
|
+
},
|
|
231
|
+
architectureProfile: stack.architecture,
|
|
232
|
+
authentication: {
|
|
233
|
+
intent: stack.authenticationIntent,
|
|
234
|
+
model: stack.authentication,
|
|
235
|
+
audience: stack.authAudience,
|
|
236
|
+
},
|
|
237
|
+
stack: stack.key,
|
|
238
|
+
productionBaseline: {
|
|
239
|
+
tests: true,
|
|
240
|
+
continuousIntegration: true,
|
|
241
|
+
productionBuild: !stack.isMobile,
|
|
242
|
+
securityRules: true,
|
|
243
|
+
operationsDocumentation: true,
|
|
244
|
+
deployment: stack.isMobile ? 'eas' : 'cloud-neutral-docker',
|
|
245
|
+
},
|
|
246
|
+
capabilities: {
|
|
247
|
+
uploads: answers.uploads || 'none',
|
|
248
|
+
backgroundJobs: answers.backgroundJobs || 'none',
|
|
249
|
+
offline: answers.offline || 'none',
|
|
250
|
+
},
|
|
251
|
+
runtimes: stack.profile.runtimes,
|
|
252
|
+
})
|
|
253
|
+
files['README.md'] = projectReadme(answers, stack)
|
|
254
|
+
if (stack.backendKey === 'springboot') {
|
|
255
|
+
files['README.md'] = files['README.md'].replace('mvn spring-boot:run', './mvnw spring-boot:run # use mvnw.cmd on Windows')
|
|
256
|
+
}
|
|
257
|
+
if (stackRegistry.get(stack.backendKey)) Object.assign(files, springFiles(answers, vars, stack))
|
|
258
|
+
return files
|
|
259
|
+
}
|