@tanstack/cli 0.61.1 → 0.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/package.json +11 -5
  2. package/skills/CHANGELOG.md +18 -0
  3. package/skills/add-addons-existing-app/SKILL.md +113 -0
  4. package/skills/choose-ecosystem-integrations/SKILL.md +140 -0
  5. package/skills/choose-ecosystem-integrations/references/authentication-providers.md +19 -0
  6. package/skills/choose-ecosystem-integrations/references/data-layer-providers.md +20 -0
  7. package/skills/choose-ecosystem-integrations/references/deployment-targets.md +19 -0
  8. package/skills/create-app-scaffold/SKILL.md +132 -0
  9. package/skills/create-app-scaffold/references/create-flag-compatibility-matrix.md +34 -0
  10. package/skills/create-app-scaffold/references/deployment-providers.md +19 -0
  11. package/skills/create-app-scaffold/references/framework-adapters.md +17 -0
  12. package/skills/create-app-scaffold/references/toolchains.md +17 -0
  13. package/skills/maintain-custom-addons-dev-watch/SKILL.md +118 -0
  14. package/skills/query-docs-library-metadata/SKILL.md +85 -0
  15. package/skills/query-docs-library-metadata/references/discovery-command-output-schemas.md +70 -0
  16. package/CHANGELOG.md +0 -815
  17. package/playwright-report/index.html +0 -85
  18. package/playwright.config.ts +0 -21
  19. package/src/bin.ts +0 -15
  20. package/src/cli.ts +0 -1099
  21. package/src/command-line.ts +0 -612
  22. package/src/dev-watch.ts +0 -564
  23. package/src/discovery.ts +0 -209
  24. package/src/file-syncer.ts +0 -263
  25. package/src/index.ts +0 -21
  26. package/src/options.ts +0 -280
  27. package/src/types.ts +0 -27
  28. package/src/ui-environment.ts +0 -74
  29. package/src/ui-prompts.ts +0 -387
  30. package/src/utils.ts +0 -30
  31. package/test-results/.last-run.json +0 -4
  32. package/tests/command-line.test.ts +0 -703
  33. package/tests/index.test.ts +0 -9
  34. package/tests/options.test.ts +0 -281
  35. package/tests/setupVitest.ts +0 -6
  36. package/tests/ui-environment.test.ts +0 -97
  37. package/tests/ui-prompts.test.ts +0 -233
  38. package/tests-e2e/addons-smoke.spec.ts +0 -31
  39. package/tests-e2e/create-smoke.spec.ts +0 -39
  40. package/tests-e2e/helpers.ts +0 -526
  41. package/tests-e2e/matrix-opportunistic.spec.ts +0 -142
  42. package/tests-e2e/router-only-smoke.spec.ts +0 -54
  43. package/tests-e2e/solid-smoke.spec.ts +0 -26
  44. package/tests-e2e/templates-smoke.spec.ts +0 -52
  45. package/tsconfig.json +0 -17
  46. package/vitest.config.js +0 -8
package/src/ui-prompts.ts DELETED
@@ -1,387 +0,0 @@
1
- import {
2
- cancel,
3
- confirm,
4
- isCancel,
5
- multiselect,
6
- note,
7
- password,
8
- select,
9
- text,
10
- } from '@clack/prompts'
11
-
12
- import {
13
- DEFAULT_PACKAGE_MANAGER,
14
- SUPPORTED_PACKAGE_MANAGERS,
15
- getAllAddOns,
16
- } from '@tanstack/create'
17
-
18
- import { validateProjectName } from './utils.js'
19
- import type { AddOn, PackageManager } from '@tanstack/create'
20
-
21
- import type { Framework } from '@tanstack/create/dist/types/types.js'
22
-
23
- export async function getProjectName(): Promise<string> {
24
- const value = await text({
25
- message: 'What would you like to name your project?',
26
- defaultValue: 'my-app',
27
- validate(value) {
28
- if (!value) {
29
- return 'Please enter a name'
30
- }
31
-
32
- const { valid, error } = validateProjectName(value)
33
- if (!valid) {
34
- return error
35
- }
36
- },
37
- })
38
-
39
- if (isCancel(value)) {
40
- cancel('Operation cancelled.')
41
- process.exit(0)
42
- }
43
-
44
- return value
45
- }
46
-
47
- export async function selectPackageManager(): Promise<PackageManager> {
48
- const packageManager = await select({
49
- message: 'Select package manager:',
50
- options: SUPPORTED_PACKAGE_MANAGERS.map((pm) => ({
51
- value: pm,
52
- label: pm,
53
- })),
54
- initialValue: DEFAULT_PACKAGE_MANAGER,
55
- })
56
- if (isCancel(packageManager)) {
57
- cancel('Operation cancelled.')
58
- process.exit(0)
59
- }
60
- return packageManager
61
- }
62
-
63
- export async function selectTemplate(
64
- templates: Array<{ id: string; name: string; description?: string }>,
65
- ): Promise<string | undefined> {
66
- if (templates.length === 0) {
67
- return undefined
68
- }
69
-
70
- const selected = await select({
71
- message: 'Would you like to start from a template?',
72
- options: [
73
- {
74
- value: undefined,
75
- label: 'None (base starter)',
76
- hint: 'Two-page baseline (Home + About)',
77
- },
78
- ...templates.map((template) => ({
79
- value: template.id,
80
- label: template.name,
81
- hint: template.description,
82
- })),
83
- ],
84
- initialValue: undefined,
85
- })
86
-
87
- if (isCancel(selected)) {
88
- cancel('Operation cancelled.')
89
- process.exit(0)
90
- }
91
-
92
- return selected
93
- }
94
-
95
- // Track if we've shown the multiselect help text
96
- let hasShownMultiselectHelp = false
97
-
98
- export async function selectAddOns(
99
- framework: Framework,
100
- mode: string,
101
- type: string,
102
- message: string,
103
- forcedAddOns: Array<string> = [],
104
- allowMultiple: boolean = true,
105
- ): Promise<Array<string>> {
106
- const allAddOns = await getAllAddOns(framework, mode)
107
- const addOns = allAddOns.filter((addOn) => addOn.type === type)
108
- if (addOns.length === 0) {
109
- return []
110
- }
111
-
112
- // Show help text only once
113
- if (!hasShownMultiselectHelp) {
114
- note(
115
- 'Use ↑/↓ to navigate • Space to select/deselect • Enter to confirm',
116
- 'Keyboard Shortcuts',
117
- )
118
- hasShownMultiselectHelp = true
119
- }
120
-
121
- if (allowMultiple) {
122
- const selectableAddOns = addOns.filter(
123
- (addOn) => !forcedAddOns.includes(addOn.id),
124
- )
125
-
126
- if (selectableAddOns.length === 0) {
127
- return []
128
- }
129
-
130
- const value = await multiselect({
131
- message,
132
- options: selectableAddOns.map((addOn) => ({
133
- value: addOn.id,
134
- label: addOn.name,
135
- hint: addOn.description,
136
- })),
137
- maxItems: selectableAddOns.length,
138
- required: false,
139
- })
140
-
141
- if (isCancel(value)) {
142
- cancel('Operation cancelled.')
143
- process.exit(0)
144
- }
145
-
146
- return value
147
- } else {
148
- const value = await select({
149
- message,
150
- options: [
151
- {
152
- value: 'none',
153
- label: 'None',
154
- },
155
- ...addOns
156
- .filter((addOn) => !forcedAddOns.includes(addOn.id))
157
- .map((addOn) => ({
158
- value: addOn.id,
159
- label: addOn.name,
160
- hint: addOn.description,
161
- })),
162
- ],
163
- initialValue: 'none',
164
- })
165
-
166
- if (isCancel(value)) {
167
- cancel('Operation cancelled.')
168
- process.exit(0)
169
- }
170
-
171
- return value === 'none' ? [] : [value]
172
- }
173
- }
174
-
175
- export async function selectGit(): Promise<boolean> {
176
- const git = await confirm({
177
- message: 'Would you like to initialize a new git repository?',
178
- initialValue: true,
179
- })
180
- if (isCancel(git)) {
181
- cancel('Operation cancelled.')
182
- process.exit(0)
183
- }
184
- return git
185
- }
186
-
187
- export async function selectExamples(): Promise<boolean> {
188
- const includeExamples = await confirm({
189
- message: 'Would you like to include demo/example pages?',
190
- initialValue: true,
191
- })
192
- if (isCancel(includeExamples)) {
193
- cancel('Operation cancelled.')
194
- process.exit(0)
195
- }
196
- return includeExamples
197
- }
198
-
199
- export async function selectToolchain(
200
- framework: Framework,
201
- toolchain?: string | false,
202
- ): Promise<string | undefined> {
203
- if (toolchain === false) {
204
- return undefined
205
- }
206
-
207
- const toolchains = new Set<AddOn>()
208
- for (const addOn of framework.getAddOns()) {
209
- if (addOn.type === 'toolchain') {
210
- toolchains.add(addOn)
211
- if (toolchain && addOn.id === toolchain) {
212
- return toolchain
213
- }
214
- }
215
- }
216
-
217
- const tc = await select({
218
- message: 'Select toolchain',
219
- options: [
220
- {
221
- value: undefined,
222
- label: 'None',
223
- },
224
- ...Array.from(toolchains).map((tc) => ({
225
- value: tc.id,
226
- label: tc.name,
227
- })),
228
- ],
229
- initialValue: undefined,
230
- })
231
-
232
- if (isCancel(tc)) {
233
- cancel('Operation cancelled.')
234
- process.exit(0)
235
- }
236
-
237
- return tc
238
- }
239
-
240
- export async function promptForAddOnOptions(
241
- addOnIds: Array<string>,
242
- framework: Framework,
243
- ): Promise<Record<string, Record<string, any>>> {
244
- const addOnOptions: Record<string, Record<string, any>> = {}
245
-
246
- for (const addOnId of addOnIds) {
247
- const addOn = framework.getAddOns().find((a) => a.id === addOnId)
248
- if (!addOn || !addOn.options) continue
249
-
250
- addOnOptions[addOnId] = {}
251
-
252
- for (const [optionName, option] of Object.entries(addOn.options)) {
253
- if (option && typeof option === 'object' && 'type' in option) {
254
- if (option.type === 'select') {
255
- const selectOption = option as {
256
- type: 'select'
257
- label: string
258
- description?: string
259
- default: string
260
- options: Array<{ value: string; label: string }>
261
- }
262
-
263
- const value = await select({
264
- message: `${addOn.name}: ${selectOption.label}`,
265
- options: selectOption.options.map((opt) => ({
266
- value: opt.value,
267
- label: opt.label,
268
- })),
269
- initialValue: selectOption.default,
270
- })
271
-
272
- if (isCancel(value)) {
273
- cancel('Operation cancelled.')
274
- process.exit(0)
275
- }
276
-
277
- addOnOptions[addOnId][optionName] = value
278
- }
279
- // Future option types can be added here
280
- }
281
- }
282
- }
283
-
284
- return addOnOptions
285
- }
286
-
287
- export async function promptForEnvVars(
288
- addOns: Array<AddOn>,
289
- ): Promise<Record<string, string>> {
290
- const envVars = new Map<
291
- string,
292
- {
293
- name: string
294
- description?: string
295
- required?: boolean
296
- default?: string
297
- secret?: boolean
298
- }
299
- >()
300
-
301
- for (const addOn of addOns as Array<any>) {
302
- for (const envVar of addOn.envVars || []) {
303
- if (!envVars.has(envVar.name)) {
304
- envVars.set(envVar.name, envVar)
305
- }
306
- }
307
- }
308
-
309
- const result: Record<string, string> = {}
310
-
311
- for (const envVar of envVars.values()) {
312
- const label = envVar.description
313
- ? `${envVar.name} (${envVar.description})`
314
- : envVar.name
315
-
316
- const value = envVar.secret
317
- ? await password({
318
- message: `Enter ${label}`,
319
- validate: envVar.required
320
- ? (v) =>
321
- v && v.trim().length > 0
322
- ? undefined
323
- : `${envVar.name} is required`
324
- : undefined,
325
- })
326
- : await text({
327
- message: `Enter ${label}`,
328
- defaultValue: envVar.default,
329
- validate: envVar.required
330
- ? (v) =>
331
- v && v.trim().length > 0
332
- ? undefined
333
- : `${envVar.name} is required`
334
- : undefined,
335
- })
336
-
337
- if (isCancel(value)) {
338
- cancel('Operation cancelled.')
339
- process.exit(0)
340
- }
341
-
342
- if (value && value.trim()) {
343
- result[envVar.name] = value.trim()
344
- }
345
- }
346
-
347
- return result
348
- }
349
-
350
- export async function selectDeployment(
351
- framework: Framework,
352
- deployment?: string,
353
- ): Promise<string | undefined> {
354
- const deployments = new Set<AddOn>()
355
- let initialValue: string | undefined = undefined
356
- for (const addOn of framework
357
- .getAddOns()
358
- .sort((a, b) => a.name.localeCompare(b.name))) {
359
- if (addOn.type === 'deployment') {
360
- deployments.add(addOn)
361
- if (deployment && addOn.id === deployment) {
362
- return deployment
363
- }
364
- if (addOn.default) {
365
- initialValue = addOn.id
366
- }
367
- }
368
- }
369
-
370
- const dp = await select({
371
- message: 'Select deployment adapter',
372
- options: [
373
- ...Array.from(deployments).map((d) => ({
374
- value: d.id,
375
- label: d.name,
376
- })),
377
- ],
378
- initialValue: initialValue,
379
- })
380
-
381
- if (isCancel(dp)) {
382
- cancel('Operation cancelled.')
383
- process.exit(0)
384
- }
385
-
386
- return dp
387
- }
package/src/utils.ts DELETED
@@ -1,30 +0,0 @@
1
- import { basename } from 'node:path'
2
- import validatePackageName from 'validate-npm-package-name'
3
-
4
- export function sanitizePackageName(name: string): string {
5
- return name
6
- .toLowerCase()
7
- .replace(/\s+/g, '-') // Replace spaces with hyphens
8
- .replace(/_/g, '-') // Replace underscores with hyphens
9
- .replace(/[^a-z0-9-]/g, '') // Remove invalid characters
10
- .replace(/^[^a-z]+/, '') // Ensure it starts with a letter
11
- .replace(/-+/g, '-') // Collapse multiple hyphens
12
- .replace(/-$/, '') // Remove trailing hyphen
13
- }
14
-
15
- export function getCurrentDirectoryName(): string {
16
- return basename(process.cwd())
17
- }
18
-
19
- export function validateProjectName(name: string) {
20
- const { validForNewPackages, validForOldPackages, errors, warnings } =
21
- validatePackageName(name)
22
- const error = errors?.[0] || warnings?.[0]
23
-
24
- return {
25
- valid: validForNewPackages && validForOldPackages,
26
- error:
27
- error?.replace(/name/g, 'Project name') ||
28
- 'Project name does not meet npm package naming requirements',
29
- }
30
- }
@@ -1,4 +0,0 @@
1
- {
2
- "status": "passed",
3
- "failedTests": []
4
- }