@better-fullstack/types 2.5.0 → 2.6.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/dist/{defaults-CbLlpynl.d.mts → defaults-7VECSARb.d.mts} +2 -2
- package/dist/defaults-7VECSARb.d.mts.map +1 -0
- package/dist/{defaults-BzWJP6p0.mjs → defaults-Bp46Ajyg.mjs} +2 -1
- package/dist/defaults-Bp46Ajyg.mjs.map +1 -0
- package/dist/defaults.d.mts +3 -3
- package/dist/defaults.mjs +1 -1
- package/dist/index.d.mts +52 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +22 -20
- package/dist/index.mjs.map +1 -1
- package/dist/json-schema.d.mts +180 -0
- package/dist/json-schema.d.mts.map +1 -1
- package/dist/json-schema.mjs +1 -1
- package/dist/{schemas-CtieNRfz.mjs → schemas-CH1UszP5.mjs} +36 -9
- package/dist/schemas-CH1UszP5.mjs.map +1 -0
- package/dist/{schemas-BRAokgPa.d.mts → schemas-CY0MaZmU.d.mts} +191 -10
- package/dist/schemas-CY0MaZmU.d.mts.map +1 -0
- package/dist/schemas.d.mts +2 -2
- package/dist/schemas.mjs +2 -2
- package/dist/{stack-graph-CXTiPofQ.mjs → stack-graph-AWbdUrN3.mjs} +615 -131
- package/dist/stack-graph-AWbdUrN3.mjs.map +1 -0
- package/dist/{stack-graph-BPw9KsNm.d.mts → stack-graph-DkJ944IX.d.mts} +7 -3
- package/dist/stack-graph-DkJ944IX.d.mts.map +1 -0
- package/dist/stack-graph.d.mts +4 -4
- package/dist/stack-graph.mjs +3 -3
- package/dist/{stack-translation-D7KkQm8W.d.mts → stack-translation-C9yYLNwM.d.mts} +27 -7
- package/dist/stack-translation-C9yYLNwM.d.mts.map +1 -0
- package/dist/{stack-translation-B-zArJLM.mjs → stack-translation-Cn6zGJ5q.mjs} +253 -26
- package/dist/stack-translation-Cn6zGJ5q.mjs.map +1 -0
- package/dist/stack-translation.d.mts +5 -5
- package/dist/stack-translation.mjs +4 -4
- package/dist/{types-Br0NsnBr.d.mts → types-fGT5qf7O.d.mts} +5 -3
- package/dist/types-fGT5qf7O.d.mts.map +1 -0
- package/dist/types.d.mts +3 -3
- package/package.json +1 -1
- package/dist/defaults-BzWJP6p0.mjs.map +0 -1
- package/dist/defaults-CbLlpynl.d.mts.map +0 -1
- package/dist/schemas-BRAokgPa.d.mts.map +0 -1
- package/dist/schemas-CtieNRfz.mjs.map +0 -1
- package/dist/stack-graph-BPw9KsNm.d.mts.map +0 -1
- package/dist/stack-graph-CXTiPofQ.mjs.map +0 -1
- package/dist/stack-translation-B-zArJLM.mjs.map +0 -1
- package/dist/stack-translation-D7KkQm8W.d.mts.map +0 -1
- package/dist/types-Br0NsnBr.d.mts.map +0 -1
|
@@ -1,5 +1,430 @@
|
|
|
1
|
-
import { $i as
|
|
1
|
+
import { $a as StackPartRoleSchema, $i as REALTIME_VALUES, A as CMS_VALUES, An as GO_MESSAGE_QUEUE_VALUES, Ar as KOTLIN_MOBILE_LIBRARIES_VALUES, B as DOTNET_AUTH_VALUES, Bn as GO_WEB_FRAMEWORK_VALUES, Br as MOBILE_PUSH_VALUES, Bt as EXAMPLES_VALUES, Ci as PYTHON_TESTING_VALUES, Cn as GO_API_VALUES, Ct as ELIXIR_DEPLOY_VALUES, D as CACHING_VALUES, Dn as GO_CONFIG_VALUES, Dt as ELIXIR_HTTP_VALUES, En as GO_CLI_VALUES, Et as ELIXIR_HTTP_SERVER_VALUES, F as DART_MOBILE_VALUES, Fn as GO_QUALITY_VALUES, Ft as ELIXIR_REALTIME_VALUES, G as DOTNET_LIBRARIES_VALUES, H as DOTNET_DEPLOY_VALUES, Ha as SWIFT_MOBILE_VALUES, Hr as MOBILE_TESTING_VALUES, I as DATABASE_SETUP_VALUES, In as GO_REALTIME_VALUES, Ir as MOBILE_DEEP_LINKING_VALUES, It as ELIXIR_TESTING_VALUES, J as DOTNET_REALTIME_VALUES, K as DOTNET_OBSERVABILITY_VALUES, L as DATABASE_VALUES, Ln as GO_TEMPLATING_VALUES, Lr as MOBILE_LIBRARIES_VALUES, Lt as ELIXIR_VALIDATION_VALUES, M as CSS_FRAMEWORK_VALUES, Ma as SEARCH_VALUES, Mn as GO_OBSERVABILITY_VALUES, Mt as ELIXIR_OBSERVABILITY_VALUES, Na as SERVER_DEPLOY_VALUES, Nn as GO_ORM_VALUES, Nt as ELIXIR_ORM_VALUES, On as GO_DI_VALUES, Ot as ELIXIR_I18N_VALUES, Pn as GO_PROTO_TOOLING_VALUES, Pr as LOGGING_VALUES, Pt as ELIXIR_QUALITY_VALUES, Qi as RATE_LIMIT_VALUES, Qr as OBSERVABILITY_VALUES, Rn as GO_TESTING_VALUES, Rr as MOBILE_NAVIGATION_VALUES, Rt as ELIXIR_WEB_FRAMEWORK_VALUES, Si as PYTHON_TASK_QUEUE_VALUES, St as ELIXIR_CLUSTERING_VALUES, Ti as PYTHON_WEB_FRAMEWORK_VALUES, Tn as GO_CACHING_VALUES, Tt as ELIXIR_EMAIL_VALUES, U as DOTNET_FRONTEND_VALUES, Ur as MOBILE_UI_VALUES, V as DOTNET_CACHING_VALUES, Va as STATE_MANAGEMENT_VALUES, Vr as MOBILE_STORAGE_VALUES, W as DOTNET_JOB_QUEUE_VALUES, X as DOTNET_VALIDATION_VALUES, Y as DOTNET_TESTING_VALUES, Z as DOTNET_WEB_FRAMEWORK_VALUES, _i as PYTHON_ORM_VALUES, _n as FRONTEND_VALUES, _r as JAVA_TESTING_LIBRARIES_VALUES, _t as EFFECT_VALUES, a as ANALYTICS_VALUES, aa as RUST_ERROR_HANDLING_VALUES, ai as PYTHON_AI_VALUES, ao as TESTING_VALUES, ar as I18N_VALUES, b as BOT_PROTECTION_VALUES, bi as PYTHON_REALTIME_VALUES, bt as ELIXIR_AUTH_VALUES, c as API_VALUES, ca as RUST_LOGGING_VALUES, ci as PYTHON_CACHING_VALUES, d as AUTH_VALUES, da as RUST_ORM_VALUES, di as PYTHON_DATA_VALUES, do as VECTOR_DB_VALUES, dr as JAVA_AUTH_VALUES, ea as RUNTIME_VALUES, ei as ORM_VALUES, fa as RUST_REALTIME_VALUES, fi as PYTHON_GRAPHQL_VALUES, fr as JAVA_BUILD_TOOL_VALUES, gi as PYTHON_OBSERVABILITY_VALUES, gn as FORMS_VALUES, go as WEB_DEPLOY_VALUES, gr as JAVA_ORM_VALUES, hi as PYTHON_MESSAGE_QUEUE_VALUES, hn as FILE_UPLOAD_VALUES, hr as JAVA_LOGGING_VALUES, ht as ECOMMERCE_VALUES, i as AI_VALUES, ia as RUST_CLI_VALUES, jn as GO_MIGRATIONS_VALUES, jr as KOTLIN_MOBILE_VALUES, jt as ELIXIR_LIBRARIES_VALUES, kn as GO_LOGGING_VALUES, kt as ELIXIR_JOBS_VALUES, la as RUST_MESSAGE_QUEUE_VALUES, li as PYTHON_CLI_VALUES, lo as UI_LIBRARY_VALUES, ma as RUST_WEB_FRAMEWORK_VALUES, mi as PYTHON_MEDIA_VALUES, mn as FILE_STORAGE_VALUES, mr as JAVA_LIBRARIES_VALUES, na as RUST_AUTH_VALUES, o as ANIMATION_VALUES, oa as RUST_FRONTEND_VALUES, oi as PYTHON_API_VALUES, pa as RUST_TEMPLATING_VALUES, pi as PYTHON_HTTP_CLIENT_VALUES, pn as FEATURE_FLAGS_VALUES, pr as JAVA_LANGUAGE_VALUES, q as DOTNET_ORM_VALUES, ra as RUST_CACHING_VALUES, ri as PAYMENTS_VALUES, sa as RUST_LIBRARIES_VALUES, si as PYTHON_AUTH_VALUES, sr as INTEGRATIONS_VALUES, ta as RUST_API_VALUES, ua as RUST_OBSERVABILITY_VALUES, ui as PYTHON_CLOUD_SDK_VALUES, uo as VALIDATION_VALUES, ur as JAVA_API_VALUES, vi as PYTHON_PACKAGE_MANAGER_VALUES, vr as JAVA_WEB_FRAMEWORK_VALUES, vt as ELIXIR_API_VALUES, wi as PYTHON_VALIDATION_VALUES, wn as GO_AUTH_VALUES, wt as ELIXIR_DOCUMENTATION_VALUES, xi as PYTHON_SERVER_VALUES, xt as ELIXIR_CACHING_VALUES, y as BACKEND_VALUES, yi as PYTHON_QUALITY_VALUES, yr as JOB_QUEUE_VALUES, yt as ELIXIR_APPLICATION_FRAMEWORK_VALUES, z as DOTNET_API_VALUES, zn as GO_VALIDATION_VALUES, zr as MOBILE_OTA_VALUES, zt as EMAIL_VALUES } from "./schemas-CH1UszP5.mjs";
|
|
2
2
|
|
|
3
|
+
//#region src/tooling-capabilities.ts
|
|
4
|
+
const TOOLING_CATEGORY_IDS = [
|
|
5
|
+
"toolchain",
|
|
6
|
+
"workspaceRunner",
|
|
7
|
+
"codeQuality",
|
|
8
|
+
"gitHooks",
|
|
9
|
+
"staticAnalysis",
|
|
10
|
+
"aiTooling",
|
|
11
|
+
"documentation",
|
|
12
|
+
"appPlatforms",
|
|
13
|
+
"testingTools",
|
|
14
|
+
"dataClient",
|
|
15
|
+
"frontendUtilities",
|
|
16
|
+
"httpClient",
|
|
17
|
+
"codeGeneration",
|
|
18
|
+
"developerEnvironment",
|
|
19
|
+
"containerOrchestration",
|
|
20
|
+
"apiGateway",
|
|
21
|
+
"continuousIntegration",
|
|
22
|
+
"backendUtilities"
|
|
23
|
+
];
|
|
24
|
+
const TOOLING_CATEGORIES = [
|
|
25
|
+
{
|
|
26
|
+
id: "toolchain",
|
|
27
|
+
label: "JavaScript Toolchain",
|
|
28
|
+
description: "Choose the primary development toolchain for JavaScript workspaces.",
|
|
29
|
+
selectionMode: "single"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "workspaceRunner",
|
|
33
|
+
label: "Workspace Runner",
|
|
34
|
+
description: "Choose one task runner and cache for a modular monorepo.",
|
|
35
|
+
selectionMode: "single"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "codeQuality",
|
|
39
|
+
label: "Code Quality",
|
|
40
|
+
description: "Choose one coherent linting and formatting profile.",
|
|
41
|
+
selectionMode: "single"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "gitHooks",
|
|
45
|
+
label: "Git Hooks",
|
|
46
|
+
description: "Choose one Git hook manager.",
|
|
47
|
+
selectionMode: "single"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "staticAnalysis",
|
|
51
|
+
label: "Static Analysis",
|
|
52
|
+
description: "Add compatible project and secret analysis checks.",
|
|
53
|
+
selectionMode: "multiple"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "aiTooling",
|
|
57
|
+
label: "AI Tooling",
|
|
58
|
+
description: "Install compatible agent rules, MCP guidance, and skills.",
|
|
59
|
+
selectionMode: "multiple"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "documentation",
|
|
63
|
+
label: "Documentation App",
|
|
64
|
+
description: "Choose one generated documentation application.",
|
|
65
|
+
selectionMode: "single"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: "appPlatforms",
|
|
69
|
+
label: "App Platforms",
|
|
70
|
+
description: "Add compatible desktop, mobile, extension, terminal, or PWA targets.",
|
|
71
|
+
selectionMode: "multiple",
|
|
72
|
+
ownerRole: "frontend"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "testingTools",
|
|
76
|
+
label: "Testing Support",
|
|
77
|
+
description: "Add complementary API mocking and component-workshop tools.",
|
|
78
|
+
selectionMode: "multiple",
|
|
79
|
+
ownerRole: "frontend"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: "dataClient",
|
|
83
|
+
label: "Data Client",
|
|
84
|
+
description: "Choose one primary remote-data client for each frontend.",
|
|
85
|
+
selectionMode: "single",
|
|
86
|
+
ownerRole: "frontend"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "frontendUtilities",
|
|
90
|
+
label: "Frontend Utilities",
|
|
91
|
+
description: "Add compatible, independent frontend libraries.",
|
|
92
|
+
selectionMode: "multiple",
|
|
93
|
+
ownerRole: "frontend"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "httpClient",
|
|
97
|
+
label: "HTTP Client",
|
|
98
|
+
description: "Choose an explicit HTTP client or use the platform fetch API.",
|
|
99
|
+
selectionMode: "single",
|
|
100
|
+
ownerRole: "frontend"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: "codeGeneration",
|
|
104
|
+
label: "API Code Generation",
|
|
105
|
+
description: "Generate typed clients from compatible GraphQL or OpenAPI contracts.",
|
|
106
|
+
selectionMode: "multiple"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: "developerEnvironment",
|
|
110
|
+
label: "Developer Environment",
|
|
111
|
+
description: "Generate a reproducible editor and container development environment.",
|
|
112
|
+
selectionMode: "multiple"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: "containerOrchestration",
|
|
116
|
+
label: "Local Containers",
|
|
117
|
+
description: "Generate local container orchestration for project services.",
|
|
118
|
+
selectionMode: "single"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: "apiGateway",
|
|
122
|
+
label: "API Gateway",
|
|
123
|
+
description: "Choose a gateway for compatible containerized APIs.",
|
|
124
|
+
selectionMode: "single"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "continuousIntegration",
|
|
128
|
+
label: "Continuous Integration",
|
|
129
|
+
description: "Choose generated CI automation for the repository.",
|
|
130
|
+
selectionMode: "single"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: "backendUtilities",
|
|
134
|
+
label: "Backend Utilities",
|
|
135
|
+
description: "Add compatible server-side helper packages and generated utilities.",
|
|
136
|
+
selectionMode: "multiple",
|
|
137
|
+
ownerRole: "backend"
|
|
138
|
+
}
|
|
139
|
+
];
|
|
140
|
+
const option = (category, id, label, description, toolIds = id === "none" ? [] : [id]) => ({
|
|
141
|
+
category,
|
|
142
|
+
id,
|
|
143
|
+
label,
|
|
144
|
+
description,
|
|
145
|
+
toolIds
|
|
146
|
+
});
|
|
147
|
+
const TOOLING_SELECTION_OPTIONS = [
|
|
148
|
+
option("toolchain", "modular", "Modular", "Choose each JavaScript tool independently.", []),
|
|
149
|
+
option("toolchain", "vite-plus", "Vite+", "Unified Vite, Vitest, Oxlint, Oxfmt, Rolldown, tsdown, and workspace runner (Beta)."),
|
|
150
|
+
option("workspaceRunner", "none", "None", "Use package-manager workspace scripts only."),
|
|
151
|
+
option("workspaceRunner", "turborepo", "Turborepo", "Task runner with remote caching."),
|
|
152
|
+
option("workspaceRunner", "nx", "Nx", "Task runner with a project graph and caching."),
|
|
153
|
+
option("codeQuality", "none", "None", "Do not generate a linting and formatting profile."),
|
|
154
|
+
option("codeQuality", "biome", "Biome", "Biome linting and formatting."),
|
|
155
|
+
option("codeQuality", "eslint-prettier", "ESLint + Prettier", "ESLint flat config with Prettier formatting.", ["eslint", "prettier"]),
|
|
156
|
+
option("codeQuality", "oxlint", "Oxlint + Oxfmt", "Oxc linting and formatting.", ["oxlint"]),
|
|
157
|
+
option("codeQuality", "ultracite", "Ultracite", "Opinionated Biome profile with AI support."),
|
|
158
|
+
option("gitHooks", "none", "None", "Do not generate a Git hook manager."),
|
|
159
|
+
option("gitHooks", "lefthook", "Lefthook", "Fast language-independent Git hooks."),
|
|
160
|
+
option("gitHooks", "husky", "Husky", "JavaScript-native Git hooks."),
|
|
161
|
+
option("staticAnalysis", "knip", "Knip", "Find unused files, exports, and dependencies."),
|
|
162
|
+
option("staticAnalysis", "gitleaks", "Gitleaks", "Detect secrets in Git history and changes."),
|
|
163
|
+
option("aiTooling", "ruler", "Ruler", "Centralize and distribute AI coding rules."),
|
|
164
|
+
option("aiTooling", "mcp", "MCP Guidance", "Generate stack-aware MCP recommendations."),
|
|
165
|
+
option("aiTooling", "skills", "Agent Skills", "Install curated stack-aware agent skills."),
|
|
166
|
+
option("documentation", "none", "None", "Do not generate a documentation application."),
|
|
167
|
+
option("documentation", "starlight", "Starlight", "Astro-powered documentation application."),
|
|
168
|
+
option("documentation", "fumadocs", "Fumadocs", "Next.js-powered documentation application."),
|
|
169
|
+
option("appPlatforms", "pwa", "PWA", "Installable and offline-capable web application."),
|
|
170
|
+
option("appPlatforms", "tauri", "Tauri", "Rust-powered desktop shell."),
|
|
171
|
+
option("appPlatforms", "electron", "Electron", "JavaScript-powered desktop shell."),
|
|
172
|
+
option("appPlatforms", "capacitor", "Capacitor", "iOS and Android shell for a web application."),
|
|
173
|
+
option("appPlatforms", "wxt", "WXT", "Browser extension application."),
|
|
174
|
+
option("appPlatforms", "opentui", "OpenTUI", "Terminal user interface application."),
|
|
175
|
+
option("testingTools", "msw", "MSW", "Network-level API mocking."),
|
|
176
|
+
option("testingTools", "storybook", "Storybook", "Component workshop and visual testing."),
|
|
177
|
+
option("dataClient", "none", "None", "Use framework-native data loading."),
|
|
178
|
+
option("dataClient", "swr", "SWR", "React Hooks for remote data."),
|
|
179
|
+
option("dataClient", "tanstack-query", "TanStack Query", "Async server-state management."),
|
|
180
|
+
option("dataClient", "apollo-client", "Apollo Client", "GraphQL client and normalized cache."),
|
|
181
|
+
option("frontendUtilities", "tanstack-table", "TanStack Table", "Headless tables."),
|
|
182
|
+
option("frontendUtilities", "tanstack-virtual", "TanStack Virtual", "Virtualized lists and grids."),
|
|
183
|
+
option("frontendUtilities", "tanstack-db", "TanStack DB", "Reactive client data store (Beta)."),
|
|
184
|
+
option("frontendUtilities", "tanstack-pacer", "TanStack Pacer", "Rate and queue utilities (Beta)."),
|
|
185
|
+
option("frontendUtilities", "firebase", "Firebase JS SDK", "Firebase client services."),
|
|
186
|
+
option("httpClient", "none", "Platform Fetch", "Use the platform fetch API."),
|
|
187
|
+
option("httpClient", "axios", "Axios", "HTTP client with interceptors and cancellation."),
|
|
188
|
+
option("codeGeneration", "graphql-codegen", "GraphQL Code Generator", "Generate typed GraphQL operations."),
|
|
189
|
+
option("codeGeneration", "openapi-typescript", "openapi-typescript", "Generate types from OpenAPI."),
|
|
190
|
+
option("developerEnvironment", "devcontainer", "Dev Container", "Generate a containerized editor environment."),
|
|
191
|
+
option("containerOrchestration", "none", "None", "Do not generate local container orchestration."),
|
|
192
|
+
option("containerOrchestration", "docker-compose", "Docker Compose", "Run project services in local containers."),
|
|
193
|
+
option("apiGateway", "none", "None", "Do not generate an API gateway."),
|
|
194
|
+
option("apiGateway", "kong", "Kong Gateway", "DB-less gateway for containerized APIs."),
|
|
195
|
+
option("continuousIntegration", "none", "None", "Do not generate CI automation."),
|
|
196
|
+
option("continuousIntegration", "github-actions", "GitHub Actions", "Repository CI for install, check, and build."),
|
|
197
|
+
option("backendUtilities", "backend-utils", "Backend Utilities", "Generated handlers, responses, and error helpers.")
|
|
198
|
+
];
|
|
199
|
+
const TOOLING_CAPABILITIES = [
|
|
200
|
+
{
|
|
201
|
+
toolId: "vite-plus",
|
|
202
|
+
category: "toolchain",
|
|
203
|
+
role: "toolchain",
|
|
204
|
+
ecosystem: "universal"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
toolId: "turborepo",
|
|
208
|
+
category: "workspaceRunner",
|
|
209
|
+
role: "workspaceRunner",
|
|
210
|
+
ecosystem: "universal"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
toolId: "nx",
|
|
214
|
+
category: "workspaceRunner",
|
|
215
|
+
role: "workspaceRunner",
|
|
216
|
+
ecosystem: "universal"
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
toolId: "biome",
|
|
220
|
+
category: "codeQuality",
|
|
221
|
+
role: "codeQuality",
|
|
222
|
+
ecosystem: "universal"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
toolId: "eslint",
|
|
226
|
+
category: "codeQuality",
|
|
227
|
+
role: "codeQuality",
|
|
228
|
+
ecosystem: "universal"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
toolId: "prettier",
|
|
232
|
+
category: "codeQuality",
|
|
233
|
+
role: "codeQuality",
|
|
234
|
+
ecosystem: "universal"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
toolId: "oxlint",
|
|
238
|
+
category: "codeQuality",
|
|
239
|
+
role: "codeQuality",
|
|
240
|
+
ecosystem: "universal"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
toolId: "ultracite",
|
|
244
|
+
category: "codeQuality",
|
|
245
|
+
role: "codeQuality",
|
|
246
|
+
ecosystem: "universal"
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
toolId: "lefthook",
|
|
250
|
+
category: "gitHooks",
|
|
251
|
+
role: "gitHooks",
|
|
252
|
+
ecosystem: "universal"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
toolId: "husky",
|
|
256
|
+
category: "gitHooks",
|
|
257
|
+
role: "gitHooks",
|
|
258
|
+
ecosystem: "universal"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
toolId: "knip",
|
|
262
|
+
category: "staticAnalysis",
|
|
263
|
+
role: "staticAnalysis",
|
|
264
|
+
ecosystem: "typescript"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
toolId: "gitleaks",
|
|
268
|
+
category: "staticAnalysis",
|
|
269
|
+
role: "staticAnalysis",
|
|
270
|
+
ecosystem: "universal"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
toolId: "ruler",
|
|
274
|
+
category: "aiTooling",
|
|
275
|
+
role: "aiTooling",
|
|
276
|
+
ecosystem: "universal"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
toolId: "mcp",
|
|
280
|
+
category: "aiTooling",
|
|
281
|
+
role: "aiTooling",
|
|
282
|
+
ecosystem: "universal"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
toolId: "skills",
|
|
286
|
+
category: "aiTooling",
|
|
287
|
+
role: "aiTooling",
|
|
288
|
+
ecosystem: "universal"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
toolId: "starlight",
|
|
292
|
+
category: "documentation",
|
|
293
|
+
role: "documentation",
|
|
294
|
+
ecosystem: "universal"
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
toolId: "fumadocs",
|
|
298
|
+
category: "documentation",
|
|
299
|
+
role: "documentation",
|
|
300
|
+
ecosystem: "universal"
|
|
301
|
+
},
|
|
302
|
+
...[
|
|
303
|
+
"pwa",
|
|
304
|
+
"tauri",
|
|
305
|
+
"electron",
|
|
306
|
+
"capacitor"
|
|
307
|
+
].map((toolId) => ({
|
|
308
|
+
toolId,
|
|
309
|
+
category: "appPlatforms",
|
|
310
|
+
role: "appPlatform",
|
|
311
|
+
ecosystem: "typescript",
|
|
312
|
+
ownerRole: "frontend"
|
|
313
|
+
})),
|
|
314
|
+
...["wxt", "opentui"].map((toolId) => ({
|
|
315
|
+
toolId,
|
|
316
|
+
category: "appPlatforms",
|
|
317
|
+
role: "appPlatform",
|
|
318
|
+
ecosystem: "typescript"
|
|
319
|
+
})),
|
|
320
|
+
{
|
|
321
|
+
toolId: "msw",
|
|
322
|
+
category: "testingTools",
|
|
323
|
+
role: "testing",
|
|
324
|
+
ecosystem: "typescript"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
toolId: "storybook",
|
|
328
|
+
category: "testingTools",
|
|
329
|
+
role: "testing",
|
|
330
|
+
ecosystem: "typescript",
|
|
331
|
+
ownerRole: "frontend"
|
|
332
|
+
},
|
|
333
|
+
...[
|
|
334
|
+
"swr",
|
|
335
|
+
"tanstack-query",
|
|
336
|
+
"apollo-client"
|
|
337
|
+
].map((toolId) => ({
|
|
338
|
+
toolId,
|
|
339
|
+
category: "dataClient",
|
|
340
|
+
role: "dataFetching",
|
|
341
|
+
ecosystem: "typescript",
|
|
342
|
+
ownerRole: "frontend"
|
|
343
|
+
})),
|
|
344
|
+
...[
|
|
345
|
+
"tanstack-table",
|
|
346
|
+
"tanstack-virtual",
|
|
347
|
+
"tanstack-db",
|
|
348
|
+
"tanstack-pacer",
|
|
349
|
+
"firebase"
|
|
350
|
+
].map((toolId) => ({
|
|
351
|
+
toolId,
|
|
352
|
+
category: "frontendUtilities",
|
|
353
|
+
role: "libraries",
|
|
354
|
+
ecosystem: "typescript",
|
|
355
|
+
ownerRole: "frontend"
|
|
356
|
+
})),
|
|
357
|
+
{
|
|
358
|
+
toolId: "axios",
|
|
359
|
+
category: "httpClient",
|
|
360
|
+
role: "httpClient",
|
|
361
|
+
ecosystem: "typescript",
|
|
362
|
+
ownerRole: "frontend"
|
|
363
|
+
},
|
|
364
|
+
...["graphql-codegen", "openapi-typescript"].map((toolId) => ({
|
|
365
|
+
toolId,
|
|
366
|
+
category: "codeGeneration",
|
|
367
|
+
role: "codeGeneration",
|
|
368
|
+
ecosystem: "universal"
|
|
369
|
+
})),
|
|
370
|
+
{
|
|
371
|
+
toolId: "devcontainer",
|
|
372
|
+
category: "developerEnvironment",
|
|
373
|
+
role: "developerEnvironment",
|
|
374
|
+
ecosystem: "universal"
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
toolId: "docker-compose",
|
|
378
|
+
category: "containerOrchestration",
|
|
379
|
+
role: "containerOrchestration",
|
|
380
|
+
ecosystem: "universal"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
toolId: "kong",
|
|
384
|
+
category: "apiGateway",
|
|
385
|
+
role: "apiGateway",
|
|
386
|
+
ecosystem: "universal"
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
toolId: "github-actions",
|
|
390
|
+
category: "continuousIntegration",
|
|
391
|
+
role: "continuousIntegration",
|
|
392
|
+
ecosystem: "universal"
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
toolId: "backend-utils",
|
|
396
|
+
category: "backendUtilities",
|
|
397
|
+
role: "backendUtilities",
|
|
398
|
+
ecosystem: "typescript",
|
|
399
|
+
ownerRole: "backend"
|
|
400
|
+
}
|
|
401
|
+
];
|
|
402
|
+
const TOOLING_TOOL_IDS = TOOLING_CAPABILITIES.map((capability) => capability.toolId);
|
|
403
|
+
function getToolingCategory(category) {
|
|
404
|
+
return TOOLING_CATEGORIES.find((definition) => definition.id === category);
|
|
405
|
+
}
|
|
406
|
+
function getToolingCapability(toolId) {
|
|
407
|
+
return TOOLING_CAPABILITIES.find((definition) => definition.toolId === toolId);
|
|
408
|
+
}
|
|
409
|
+
function getToolingCapabilities(category) {
|
|
410
|
+
return TOOLING_CAPABILITIES.filter((definition) => definition.category === category);
|
|
411
|
+
}
|
|
412
|
+
function getToolingSelectionOptions(category) {
|
|
413
|
+
return TOOLING_SELECTION_OPTIONS.filter((definition) => definition.category === category);
|
|
414
|
+
}
|
|
415
|
+
function isToolingOverlayPart(part) {
|
|
416
|
+
const capability = getToolingCapability(part.toolId);
|
|
417
|
+
if (!capability || part.source === "provided") return false;
|
|
418
|
+
return capability.role === part.role && (part.ecosystem === void 0 || capability.ecosystem === part.ecosystem);
|
|
419
|
+
}
|
|
420
|
+
function isToolingOverlayOnly(parts) {
|
|
421
|
+
return (parts ?? []).every((part) => isToolingOverlayPart(part));
|
|
422
|
+
}
|
|
423
|
+
function getSelectedToolingOption(category, selectedToolIds) {
|
|
424
|
+
return getToolingSelectionOptions(category).find((selection) => selection.toolIds.length === 0 ? getToolingCapabilities(category).every((capability) => !selectedToolIds.includes(capability.toolId)) : selection.toolIds.every((toolId) => selectedToolIds.includes(toolId)));
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
//#endregion
|
|
3
428
|
//#region src/stack-compatibility-rules.ts
|
|
4
429
|
const WEB_FRAMEWORKS = [
|
|
5
430
|
"tanstack-router",
|
|
@@ -557,7 +982,8 @@ const LEGACY_TYPESCRIPT_FRONTEND_SINGLE_CATEGORIES = {
|
|
|
557
982
|
animation: "animation",
|
|
558
983
|
fileUpload: "fileUpload",
|
|
559
984
|
i18n: "i18n",
|
|
560
|
-
analytics: "analytics"
|
|
985
|
+
analytics: "analytics",
|
|
986
|
+
botProtection: "botProtection"
|
|
561
987
|
};
|
|
562
988
|
const LEGACY_DATABASE_SINGLE_CATEGORIES = { dbSetup: "dbSetup" };
|
|
563
989
|
const LEGACY_MOBILE_SINGLE_CATEGORIES = {
|
|
@@ -592,45 +1018,6 @@ const LEGACY_BACKEND_ARRAY_CATEGORIES_BY_ECOSYSTEM = {
|
|
|
592
1018
|
},
|
|
593
1019
|
elixir: { libraries: "elixirLibraries" }
|
|
594
1020
|
};
|
|
595
|
-
const CODE_QUALITY_ADDONS = new Set([
|
|
596
|
-
"biome",
|
|
597
|
-
"eslint",
|
|
598
|
-
"prettier",
|
|
599
|
-
"oxlint",
|
|
600
|
-
"ultracite",
|
|
601
|
-
"lefthook",
|
|
602
|
-
"husky",
|
|
603
|
-
"gitleaks"
|
|
604
|
-
]);
|
|
605
|
-
const TYPESCRIPT_CODE_QUALITY_ADDONS = new Set(["knip"]);
|
|
606
|
-
const DOCUMENTATION_ADDONS = new Set(["starlight", "fumadocs"]);
|
|
607
|
-
const FRONTEND_APP_PLATFORM_ADDONS = new Set(APP_PLATFORM_ADDON_VALUES);
|
|
608
|
-
const FRONTEND_DATA_FETCHING_ADDONS = new Set([
|
|
609
|
-
"swr",
|
|
610
|
-
"apollo-client",
|
|
611
|
-
"tanstack-query",
|
|
612
|
-
"tanstack-table",
|
|
613
|
-
"tanstack-virtual",
|
|
614
|
-
"tanstack-db",
|
|
615
|
-
"tanstack-pacer"
|
|
616
|
-
]);
|
|
617
|
-
const FRONTEND_HTTP_CLIENT_ADDONS = new Set(["axios"]);
|
|
618
|
-
const FRONTEND_LIBRARY_ADDONS = new Set(["firebase"]);
|
|
619
|
-
const FRONTEND_TESTING_ADDONS = new Set(["msw", "storybook"]);
|
|
620
|
-
const WORKSPACE_TOOLING_ADDONS = new Set([
|
|
621
|
-
"turborepo",
|
|
622
|
-
"nx",
|
|
623
|
-
"docker-compose",
|
|
624
|
-
"devcontainer",
|
|
625
|
-
"kong",
|
|
626
|
-
"github-actions",
|
|
627
|
-
"ruler",
|
|
628
|
-
"mcp",
|
|
629
|
-
"skills",
|
|
630
|
-
"backend-utils",
|
|
631
|
-
"graphql-codegen",
|
|
632
|
-
"openapi-typescript"
|
|
633
|
-
]);
|
|
634
1021
|
const DOCKER_COMPOSE_COMPATIBLE_ECOSYSTEMS = new Set([
|
|
635
1022
|
"typescript",
|
|
636
1023
|
"python",
|
|
@@ -638,16 +1025,48 @@ const DOCKER_COMPOSE_COMPATIBLE_ECOSYSTEMS = new Set([
|
|
|
638
1025
|
"rust",
|
|
639
1026
|
"java"
|
|
640
1027
|
]);
|
|
641
|
-
const LEGACY_ADDON_GRAPH_ROLES = new Set([
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
1028
|
+
const LEGACY_ADDON_GRAPH_ROLES = new Set([...TOOLING_CAPABILITIES.map((capability) => capability.role), "workspaceTooling"]);
|
|
1029
|
+
function getHistoricalAddonRole(toolId) {
|
|
1030
|
+
if ([
|
|
1031
|
+
"biome",
|
|
1032
|
+
"eslint",
|
|
1033
|
+
"prettier",
|
|
1034
|
+
"oxlint",
|
|
1035
|
+
"ultracite",
|
|
1036
|
+
"lefthook",
|
|
1037
|
+
"husky",
|
|
1038
|
+
"knip",
|
|
1039
|
+
"gitleaks"
|
|
1040
|
+
].includes(toolId)) return "codeQuality";
|
|
1041
|
+
if (["starlight", "fumadocs"].includes(toolId)) return "documentation";
|
|
1042
|
+
if ([
|
|
1043
|
+
"pwa",
|
|
1044
|
+
"tauri",
|
|
1045
|
+
"electron",
|
|
1046
|
+
"capacitor",
|
|
1047
|
+
"wxt",
|
|
1048
|
+
"opentui"
|
|
1049
|
+
].includes(toolId)) return "appPlatform";
|
|
1050
|
+
if ([
|
|
1051
|
+
"swr",
|
|
1052
|
+
"apollo-client",
|
|
1053
|
+
"tanstack-query",
|
|
1054
|
+
"tanstack-table",
|
|
1055
|
+
"tanstack-virtual",
|
|
1056
|
+
"tanstack-db",
|
|
1057
|
+
"tanstack-pacer"
|
|
1058
|
+
].includes(toolId)) return "dataFetching";
|
|
1059
|
+
if (toolId === "axios") return "httpClient";
|
|
1060
|
+
if (toolId === "firebase") return "libraries";
|
|
1061
|
+
if (["msw", "storybook"].includes(toolId)) return "testing";
|
|
1062
|
+
if (getToolingCapability(toolId)) return "workspaceTooling";
|
|
1063
|
+
}
|
|
1064
|
+
function getHistoricalAddonEcosystem(toolId) {
|
|
1065
|
+
const role = getHistoricalAddonRole(toolId);
|
|
1066
|
+
if (!role) return void 0;
|
|
1067
|
+
if (role === "workspaceTooling") return "universal";
|
|
1068
|
+
return getToolingCapability(toolId)?.ecosystem;
|
|
1069
|
+
}
|
|
651
1070
|
const LEGACY_ARRAY_CATEGORIES = new Set([
|
|
652
1071
|
"addons",
|
|
653
1072
|
"examples",
|
|
@@ -667,48 +1086,26 @@ const LEGACY_ARRAY_CATEGORIES = new Set([
|
|
|
667
1086
|
"elixirLibraries"
|
|
668
1087
|
]);
|
|
669
1088
|
function getAddonStackPartBinding(toolId) {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
ecosystem: "universal"
|
|
677
|
-
};
|
|
678
|
-
if (DOCUMENTATION_ADDONS.has(toolId)) return {
|
|
679
|
-
role: "documentation",
|
|
680
|
-
ecosystem: "universal"
|
|
681
|
-
};
|
|
682
|
-
if (FRONTEND_APP_PLATFORM_ADDONS.has(toolId)) return {
|
|
683
|
-
role: "appPlatform",
|
|
684
|
-
ecosystem: "typescript",
|
|
685
|
-
ownerRole: "frontend"
|
|
686
|
-
};
|
|
687
|
-
if (FRONTEND_DATA_FETCHING_ADDONS.has(toolId)) return {
|
|
688
|
-
role: "dataFetching",
|
|
689
|
-
ecosystem: "typescript",
|
|
690
|
-
ownerRole: "frontend"
|
|
691
|
-
};
|
|
692
|
-
if (FRONTEND_HTTP_CLIENT_ADDONS.has(toolId)) return {
|
|
693
|
-
role: "httpClient",
|
|
694
|
-
ecosystem: "typescript",
|
|
695
|
-
ownerRole: "frontend"
|
|
696
|
-
};
|
|
697
|
-
if (FRONTEND_LIBRARY_ADDONS.has(toolId)) return {
|
|
698
|
-
role: "libraries",
|
|
699
|
-
ecosystem: "typescript",
|
|
700
|
-
ownerRole: "frontend"
|
|
701
|
-
};
|
|
702
|
-
if (FRONTEND_TESTING_ADDONS.has(toolId)) return {
|
|
703
|
-
role: "testing",
|
|
704
|
-
ecosystem: "typescript",
|
|
705
|
-
ownerRole: "frontend"
|
|
706
|
-
};
|
|
707
|
-
if (WORKSPACE_TOOLING_ADDONS.has(toolId)) return {
|
|
708
|
-
role: "workspaceTooling",
|
|
709
|
-
ecosystem: "universal"
|
|
1089
|
+
const capability = getToolingCapability(toolId);
|
|
1090
|
+
if (!capability) return void 0;
|
|
1091
|
+
return {
|
|
1092
|
+
role: capability.role,
|
|
1093
|
+
ecosystem: capability.ecosystem,
|
|
1094
|
+
ownerRole: capability.ownerRole
|
|
710
1095
|
};
|
|
711
1096
|
}
|
|
1097
|
+
function toolingOverlayStackParts(addons, source = "selected") {
|
|
1098
|
+
return (addons ?? []).filter((toolId) => toolId !== "none").flatMap((toolId) => {
|
|
1099
|
+
const capability = getToolingCapability(toolId);
|
|
1100
|
+
if (!capability) return [];
|
|
1101
|
+
return [createStackPart({
|
|
1102
|
+
role: capability.role,
|
|
1103
|
+
ecosystem: capability.ecosystem,
|
|
1104
|
+
toolId,
|
|
1105
|
+
source
|
|
1106
|
+
})];
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
712
1109
|
const OWNER_ROLES_BY_SCOPED_ROLE = {
|
|
713
1110
|
...Object.fromEntries([...Object.keys(LEGACY_TYPESCRIPT_BACKEND_SINGLE_CATEGORIES), ...Object.keys(LEGACY_TYPESCRIPT_BACKEND_INFRA_CATEGORIES)].map((role) => [role, ["backend"]])),
|
|
714
1111
|
...Object.fromEntries(Object.keys(LEGACY_TYPESCRIPT_FRONTEND_SINGLE_CATEGORIES).map((role) => [role, ["frontend"]])),
|
|
@@ -961,26 +1358,28 @@ const STACK_TOOL_DEFINITIONS = [
|
|
|
961
1358
|
...defineTools(FILE_UPLOAD_VALUES, "fileUpload", "typescript", "fileUpload"),
|
|
962
1359
|
...defineTools(I18N_VALUES, "i18n", "typescript", "i18n"),
|
|
963
1360
|
...defineTools(ANALYTICS_VALUES, "analytics", "typescript", "analytics"),
|
|
964
|
-
...defineTools(
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1361
|
+
...defineTools(BOT_PROTECTION_VALUES, "botProtection", "typescript", "botProtection"),
|
|
1362
|
+
...TOOLING_CAPABILITIES.map((capability) => {
|
|
1363
|
+
const category = getToolingCategory(capability.category);
|
|
1364
|
+
return {
|
|
1365
|
+
toolId: capability.toolId,
|
|
1366
|
+
roles: [capability.role],
|
|
1367
|
+
ecosystems: [capability.ecosystem],
|
|
1368
|
+
allowMultiple: category?.selectionMode === "multiple" || capability.category === "codeQuality",
|
|
1369
|
+
ownerless: capability.ownerRole === void 0
|
|
1370
|
+
};
|
|
971
1371
|
}),
|
|
972
|
-
...
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
ownerless: true
|
|
1372
|
+
...TOOLING_CAPABILITIES.flatMap((capability) => {
|
|
1373
|
+
const historicalRole = getHistoricalAddonRole(capability.toolId);
|
|
1374
|
+
if (!historicalRole || historicalRole === capability.role) return [];
|
|
1375
|
+
return [{
|
|
1376
|
+
toolId: capability.toolId,
|
|
1377
|
+
roles: [historicalRole],
|
|
1378
|
+
ecosystems: [getHistoricalAddonEcosystem(capability.toolId) ?? capability.ecosystem],
|
|
1379
|
+
selectable: false,
|
|
1380
|
+
allowMultiple: true,
|
|
1381
|
+
ownerless: historicalRole === "workspaceTooling" || capability.ownerRole === void 0
|
|
1382
|
+
}];
|
|
984
1383
|
}),
|
|
985
1384
|
...defineTools(EXAMPLES_VALUES, "examples", "universal", void 0, {
|
|
986
1385
|
allowMultiple: true,
|
|
@@ -1725,35 +2124,77 @@ function createAddonCompatibilityIssue(part, context) {
|
|
|
1725
2124
|
toolId: part.toolId,
|
|
1726
2125
|
message: "TanStack Query is already included via the selected API layer."
|
|
1727
2126
|
});
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
2127
|
+
}
|
|
2128
|
+
if ((part.role === "dataFetching" || part.role === "libraries") && [
|
|
2129
|
+
"tanstack-query",
|
|
2130
|
+
"tanstack-table",
|
|
2131
|
+
"tanstack-virtual",
|
|
2132
|
+
"tanstack-db",
|
|
2133
|
+
"tanstack-pacer"
|
|
2134
|
+
].includes(part.toolId) && frontendTool === "astro" && context.settings?.astroIntegration === "none") return createStackGraphIssue({
|
|
2135
|
+
code: "INCOMPATIBLE_GRAPH_SELECTION",
|
|
2136
|
+
partId: part.id,
|
|
2137
|
+
role: part.role,
|
|
2138
|
+
toolId: part.toolId,
|
|
2139
|
+
message: "TanStack libraries with Astro require a UI framework integration (React, Vue, Svelte, or Solid)"
|
|
2140
|
+
});
|
|
2141
|
+
if (part.role === "toolchain" && part.toolId === "vite-plus") {
|
|
2142
|
+
if (!(context.selectedEcosystemsByRoleList?.frontend ?? (context.primaryEcosystemsByRole?.frontend ? [context.primaryEcosystemsByRole.frontend] : [])).includes("typescript")) return createStackGraphIssue({
|
|
1735
2143
|
code: "INCOMPATIBLE_GRAPH_SELECTION",
|
|
1736
2144
|
partId: part.id,
|
|
1737
2145
|
role: part.role,
|
|
1738
2146
|
toolId: part.toolId,
|
|
1739
|
-
message: "
|
|
2147
|
+
message: "Vite+ requires a generated TypeScript web frontend"
|
|
2148
|
+
});
|
|
2149
|
+
const conflictingTool = [
|
|
2150
|
+
...context.selectedToolIdsByRoleList?.workspaceRunner ?? [],
|
|
2151
|
+
...context.selectedToolIdsByRoleList?.codeQuality ?? [],
|
|
2152
|
+
...context.selectedToolIdsByRoleList?.gitHooks ?? [],
|
|
2153
|
+
...(context.selectedToolIdsByRoleList?.workspaceTooling ?? []).filter((toolId) => ["turborepo", "nx"].includes(toolId))
|
|
2154
|
+
].find((toolId) => toolId !== "none");
|
|
2155
|
+
if (conflictingTool) return createStackGraphIssue({
|
|
2156
|
+
code: "INCOMPATIBLE_GRAPH_SELECTION",
|
|
2157
|
+
partId: part.id,
|
|
2158
|
+
role: part.role,
|
|
2159
|
+
toolId: part.toolId,
|
|
2160
|
+
message: `Vite+ owns workspace tasks, code quality, and commit hooks; remove '${conflictingTool}'`
|
|
1740
2161
|
});
|
|
1741
2162
|
}
|
|
1742
|
-
if (part.role === "
|
|
1743
|
-
const
|
|
1744
|
-
|
|
2163
|
+
if (part.role === "workspaceRunner") {
|
|
2164
|
+
const workspaceRunners = [
|
|
2165
|
+
"turborepo",
|
|
2166
|
+
"nx",
|
|
2167
|
+
"vite-plus"
|
|
2168
|
+
];
|
|
2169
|
+
if ([...context.selectedToolIdsByRoleList?.workspaceRunner ?? [], ...context.selectedToolIdsByRoleList?.workspaceTooling ?? []].find((toolId) => toolId !== part.toolId && workspaceRunners.includes(toolId))) return createStackGraphIssue({
|
|
1745
2170
|
code: "INCOMPATIBLE_GRAPH_SELECTION",
|
|
1746
2171
|
partId: part.id,
|
|
1747
2172
|
role: part.role,
|
|
1748
2173
|
toolId: part.toolId,
|
|
1749
|
-
message: "Choose
|
|
2174
|
+
message: "Choose one workspace runner: Turborepo, Nx, or Vite+"
|
|
1750
2175
|
});
|
|
1751
|
-
|
|
2176
|
+
}
|
|
2177
|
+
if ((part.role === "workspaceRunner" || part.role === "codeQuality" || part.role === "gitHooks") && context.selectedToolIdsByRoleList?.toolchain?.includes("vite-plus")) return createStackGraphIssue({
|
|
2178
|
+
code: "INCOMPATIBLE_GRAPH_SELECTION",
|
|
2179
|
+
partId: part.id,
|
|
2180
|
+
role: part.role,
|
|
2181
|
+
toolId: part.toolId,
|
|
2182
|
+
message: "Vite+ owns workspace tasks, code quality, and commit hooks"
|
|
2183
|
+
});
|
|
2184
|
+
if (part.role === "workspaceTooling" || part.role === "containerOrchestration" || part.role === "developerEnvironment" || part.role === "apiGateway" || part.role === "backendUtilities") {
|
|
2185
|
+
const workspaceTooling = context.selectedToolIdsByRoleList?.workspaceTooling ?? [];
|
|
2186
|
+
const workspaceRunners = [
|
|
2187
|
+
"turborepo",
|
|
2188
|
+
"nx",
|
|
2189
|
+
"vite-plus"
|
|
2190
|
+
];
|
|
2191
|
+
const otherWorkspaceRunner = workspaceTooling.find((toolId) => toolId !== part.toolId && workspaceRunners.includes(toolId));
|
|
2192
|
+
if (workspaceRunners.includes(part.toolId) && otherWorkspaceRunner) return createStackGraphIssue({
|
|
1752
2193
|
code: "INCOMPATIBLE_GRAPH_SELECTION",
|
|
1753
2194
|
partId: part.id,
|
|
1754
2195
|
role: part.role,
|
|
1755
2196
|
toolId: part.toolId,
|
|
1756
|
-
message: "Choose
|
|
2197
|
+
message: "Choose one workspace runner: Turborepo, Nx, or Vite+"
|
|
1757
2198
|
});
|
|
1758
2199
|
if (part.toolId === "docker-compose" || part.toolId === "devcontainer" || part.toolId === "kong") {
|
|
1759
2200
|
const title = part.toolId === "devcontainer" ? "DevContainer" : part.toolId === "kong" ? "Kong Gateway" : "Docker Compose";
|
|
@@ -2198,6 +2639,12 @@ function getStackPartCompatibilityIssue(part, context) {
|
|
|
2198
2639
|
function getStackPartCompatibilityIssueForPart(part, parts) {
|
|
2199
2640
|
return getStackPartCompatibilityIssue(part, getStackPartOptionContextForPart(part, parts));
|
|
2200
2641
|
}
|
|
2642
|
+
function hasJavaScriptWorkspaceRoot(parts) {
|
|
2643
|
+
return parts?.some((part) => !part.ownerPartId && part.source !== "provided" && part.toolId !== "none" && (part.ecosystem === "typescript" || part.ecosystem === "react-native") && (part.role === "frontend" || part.role === "backend" || part.role === "mobile")) ?? false;
|
|
2644
|
+
}
|
|
2645
|
+
function hasVitePlusWorkspaceRoot(parts) {
|
|
2646
|
+
return parts?.some((part) => !part.ownerPartId && part.source !== "provided" && part.toolId !== "none" && part.ecosystem === "typescript" && part.role === "frontend") ?? false;
|
|
2647
|
+
}
|
|
2201
2648
|
function getStackToolDefinitions(context) {
|
|
2202
2649
|
if (!context) return [...STACK_TOOL_DEFINITIONS];
|
|
2203
2650
|
return STACK_TOOL_DEFINITIONS.filter((definition) => {
|
|
@@ -2326,6 +2773,15 @@ function getSelectedToolIdsByRoleList(parts) {
|
|
|
2326
2773
|
}
|
|
2327
2774
|
return selectedToolIdsByRoleList;
|
|
2328
2775
|
}
|
|
2776
|
+
function getSelectedEcosystemsByRoleList(parts) {
|
|
2777
|
+
const selectedEcosystemsByRoleList = {};
|
|
2778
|
+
for (const part of parts) {
|
|
2779
|
+
if (part.source === "provided" || part.ownerPartId || part.toolId === "none") continue;
|
|
2780
|
+
selectedEcosystemsByRoleList[part.role] ??= [];
|
|
2781
|
+
selectedEcosystemsByRoleList[part.role]?.push(part.ecosystem);
|
|
2782
|
+
}
|
|
2783
|
+
return selectedEcosystemsByRoleList;
|
|
2784
|
+
}
|
|
2329
2785
|
function getPrimaryToolContext(parts) {
|
|
2330
2786
|
const primaryToolIdsByRole = {};
|
|
2331
2787
|
const primaryEcosystemsByRole = {};
|
|
@@ -2373,6 +2829,7 @@ function getStackPartOptionContextForPart(part, parts) {
|
|
|
2373
2829
|
siblingToolIdsByRoleList: getSiblingToolIdsByRoleList(part, parts),
|
|
2374
2830
|
selectedToolIdsByRole: getSelectedToolIdsByRole(parts),
|
|
2375
2831
|
selectedToolIdsByRoleList: getSelectedToolIdsByRoleList(parts),
|
|
2832
|
+
selectedEcosystemsByRoleList: getSelectedEcosystemsByRoleList(parts),
|
|
2376
2833
|
primaryToolIdsByRole,
|
|
2377
2834
|
primaryEcosystemsByRole
|
|
2378
2835
|
};
|
|
@@ -2390,12 +2847,12 @@ function addLegacyPart(parts, role, ecosystem, toolId, source, ownerPartId, sett
|
|
|
2390
2847
|
parts.push(part);
|
|
2391
2848
|
return part;
|
|
2392
2849
|
}
|
|
2393
|
-
function addLegacyAddonPart(parts, toolId, source, frontendPart) {
|
|
2850
|
+
function addLegacyAddonPart(parts, toolId, source, frontendPart, backendPart) {
|
|
2394
2851
|
if (!toolId || toolId === "none") return;
|
|
2395
2852
|
const binding = getAddonStackPartBinding(toolId);
|
|
2396
2853
|
if (!binding) return;
|
|
2397
|
-
const ownerPartId = binding.ownerRole === "frontend" ? frontendPart?.id : void 0;
|
|
2398
|
-
if (binding.ownerRole
|
|
2854
|
+
const ownerPartId = binding.ownerRole === "frontend" ? frontendPart?.id : binding.ownerRole === "backend" ? backendPart?.id : void 0;
|
|
2855
|
+
if (binding.ownerRole && !ownerPartId) return;
|
|
2399
2856
|
addLegacyPart(parts, binding.role, binding.ecosystem, toolId, source, ownerPartId);
|
|
2400
2857
|
}
|
|
2401
2858
|
function appendUniqueLegacyArrayValue(config, category, value) {
|
|
@@ -2407,7 +2864,8 @@ function getLegacyArrayCategoryForPart(part) {
|
|
|
2407
2864
|
if (part.role === "examples") return "examples";
|
|
2408
2865
|
if (LEGACY_ADDON_GRAPH_ROLES.has(part.role)) {
|
|
2409
2866
|
const binding = getAddonStackPartBinding(part.toolId);
|
|
2410
|
-
|
|
2867
|
+
const historicalRole = getHistoricalAddonRole(part.toolId);
|
|
2868
|
+
if (binding && (binding.role === part.role || historicalRole === part.role) && (binding.ecosystem === part.ecosystem || getHistoricalAddonEcosystem(part.toolId) === part.ecosystem)) return "addons";
|
|
2411
2869
|
}
|
|
2412
2870
|
const legacyCategory = findDefinition(part)?.legacyCategory;
|
|
2413
2871
|
if (legacyCategory && LEGACY_ARRAY_CATEGORIES.has(legacyCategory)) return legacyCategory;
|
|
@@ -2439,7 +2897,7 @@ function legacyProjectConfigToStackParts(config, source = "legacy") {
|
|
|
2439
2897
|
const databasePart = addLegacyPart(parts, "database", "universal", config.database, source);
|
|
2440
2898
|
const capabilityOwner = backendPart?.id ?? frontendPart?.id ?? mobilePart?.id ?? databasePart?.id;
|
|
2441
2899
|
if (databasePart) addLegacyPart(parts, "dbSetup", "universal", config.dbSetup, source, databasePart.id);
|
|
2442
|
-
for (const addon of config.addons ?? []) addLegacyAddonPart(parts, addon, source, frontendPart);
|
|
2900
|
+
for (const addon of config.addons ?? []) addLegacyAddonPart(parts, addon, source, frontendPart, backendPart);
|
|
2443
2901
|
for (const example of config.examples ?? []) addLegacyPart(parts, "examples", "universal", example, source);
|
|
2444
2902
|
if (config.ecosystem === void 0 || config.ecosystem === "typescript" || config.ecosystem === "react-native") {
|
|
2445
2903
|
addLegacyPart(parts, "orm", "typescript", config.orm, source, capabilityOwner);
|
|
@@ -2747,9 +3205,35 @@ function validateStackParts(parts) {
|
|
|
2747
3205
|
message: `'${selected.toolId}' conflicts with '${provided.toolId}' provided by '${provider?.toolId ?? "another part"}'.`
|
|
2748
3206
|
});
|
|
2749
3207
|
}
|
|
3208
|
+
const toolingByCategoryAndScope = /* @__PURE__ */ new Map();
|
|
3209
|
+
for (const part of parts) {
|
|
3210
|
+
if (part.source === "provided") continue;
|
|
3211
|
+
const capability = getToolingCapability(part.toolId);
|
|
3212
|
+
if (!capability || capability.role !== part.role || capability.ecosystem !== part.ecosystem) continue;
|
|
3213
|
+
const key = `${part.ownerPartId ?? "root"}:${capability.category}`;
|
|
3214
|
+
toolingByCategoryAndScope.set(key, [...toolingByCategoryAndScope.get(key) ?? [], part]);
|
|
3215
|
+
}
|
|
3216
|
+
for (const categoryParts of toolingByCategoryAndScope.values()) {
|
|
3217
|
+
const first = categoryParts[0];
|
|
3218
|
+
if (!first) continue;
|
|
3219
|
+
const capability = getToolingCapability(first.toolId);
|
|
3220
|
+
if (!capability || getToolingCategory(capability.category)?.selectionMode !== "single") continue;
|
|
3221
|
+
if (categoryParts.every((part) => part.source === "legacy")) continue;
|
|
3222
|
+
const selected = [...new Set(categoryParts.map((part) => part.toolId))].sort();
|
|
3223
|
+
if (!getToolingSelectionOptions(capability.category).some((selection) => {
|
|
3224
|
+
const expected = [...selection.toolIds].sort();
|
|
3225
|
+
return expected.length === selected.length && expected.every((toolId, index) => toolId === selected[index]);
|
|
3226
|
+
})) issues.push({
|
|
3227
|
+
code: "INCOHERENT_TOOLING_PROFILE",
|
|
3228
|
+
partId: first.id,
|
|
3229
|
+
role: first.role,
|
|
3230
|
+
toolId: first.toolId,
|
|
3231
|
+
message: `Choose one complete '${getToolingCategory(capability.category)?.label}' profile.`
|
|
3232
|
+
});
|
|
3233
|
+
}
|
|
2750
3234
|
return { issues };
|
|
2751
3235
|
}
|
|
2752
3236
|
|
|
2753
3237
|
//#endregion
|
|
2754
|
-
export {
|
|
2755
|
-
//# sourceMappingURL=stack-graph-
|
|
3238
|
+
export { TOOLING_CAPABILITIES as A, isToolingOverlayOnly as B, hasPWACompatibleFrontend as C, isExampleAIAllowed as D, isBackendUtilsCompatibleBackend as E, getSelectedToolingOption as F, getToolingCapabilities as I, getToolingCapability as L, TOOLING_CATEGORY_IDS as M, TOOLING_SELECTION_OPTIONS as N, isExampleChatSdkAllowed as O, TOOLING_TOOL_IDS as P, getToolingCategory as R, hasDockerComposeCompatibleFrontend as S, hasTauriCompatibleFrontend as T, isToolingOverlayPart as V, toolingOverlayStackParts as _, getAddonStackPartBinding as a, UI_LIBRARY_COMPATIBILITY as b, getStackPartOptions as c, hasVitePlusWorkspaceRoot as d, legacyProjectConfigToStackParts as f, stackPartsToLegacyProjectConfigPartial as g, stackGraphToLegacyProjectConfigForEcosystem as h, formatStackPartSpec as i, TOOLING_CATEGORIES as j, requiresChatSdkVercelAIForExamples as k, getStackToolDefinitions as l, parseStackPartSpecs as m, STACK_TOOL_DEFINITIONS as n, getRoleTargetPath as o, materializeProvidedStackParts as p, createStackPart as r, getStackPartCompatibilityIssueForPart as s, ELIXIR_UNSUPPORTED_GRAPH_TOOLS as t, hasJavaScriptWorkspaceRoot as u, validateStackParts as v, hasTanStackAICompatibleFrontend as w, getUnsupportedWebDeployFrontend as x, BACKEND_UTILS_COMPATIBLE_BACKENDS as y, getToolingSelectionOptions as z };
|
|
3239
|
+
//# sourceMappingURL=stack-graph-AWbdUrN3.mjs.map
|