@tanstack/cli 0.0.7 → 0.48.2

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 (83) hide show
  1. package/dist/bin.js +7 -0
  2. package/dist/cli.js +481 -0
  3. package/dist/command-line.js +174 -0
  4. package/dist/dev-watch.js +290 -0
  5. package/dist/file-syncer.js +148 -0
  6. package/dist/index.js +1 -0
  7. package/dist/mcp/api.js +31 -0
  8. package/dist/mcp/tools.js +250 -0
  9. package/dist/mcp/types.js +37 -0
  10. package/dist/mcp.js +121 -0
  11. package/dist/options.js +162 -0
  12. package/dist/types/bin.d.ts +2 -0
  13. package/dist/types/cli.d.ts +16 -0
  14. package/dist/types/command-line.d.ts +10 -0
  15. package/dist/types/dev-watch.d.ts +27 -0
  16. package/dist/types/file-syncer.d.ts +18 -0
  17. package/dist/types/index.d.ts +1 -0
  18. package/dist/types/mcp/api.d.ts +4 -0
  19. package/dist/types/mcp/tools.d.ts +2 -0
  20. package/dist/types/mcp/types.d.ts +217 -0
  21. package/dist/types/mcp.d.ts +6 -0
  22. package/dist/types/options.d.ts +8 -0
  23. package/dist/types/types.d.ts +25 -0
  24. package/dist/types/ui-environment.d.ts +2 -0
  25. package/dist/types/ui-prompts.d.ts +12 -0
  26. package/dist/types/utils.d.ts +8 -0
  27. package/dist/types.js +1 -0
  28. package/dist/ui-environment.js +52 -0
  29. package/dist/ui-prompts.js +244 -0
  30. package/dist/utils.js +30 -0
  31. package/package.json +46 -46
  32. package/src/bin.ts +6 -93
  33. package/src/cli.ts +692 -0
  34. package/src/command-line.ts +236 -0
  35. package/src/dev-watch.ts +430 -0
  36. package/src/file-syncer.ts +205 -0
  37. package/src/index.ts +1 -85
  38. package/src/mcp.ts +190 -0
  39. package/src/options.ts +260 -0
  40. package/src/types.ts +27 -0
  41. package/src/ui-environment.ts +74 -0
  42. package/src/ui-prompts.ts +322 -0
  43. package/src/utils.ts +38 -0
  44. package/tests/command-line.test.ts +304 -0
  45. package/tests/index.test.ts +9 -0
  46. package/tests/mcp.test.ts +225 -0
  47. package/tests/options.test.ts +304 -0
  48. package/tests/setupVitest.ts +6 -0
  49. package/tests/ui-environment.test.ts +97 -0
  50. package/tests/ui-prompts.test.ts +238 -0
  51. package/tsconfig.json +17 -0
  52. package/vitest.config.js +7 -0
  53. package/dist/bin.cjs +0 -761
  54. package/dist/bin.d.cts +0 -1
  55. package/dist/bin.d.mts +0 -1
  56. package/dist/bin.mjs +0 -760
  57. package/dist/index.cjs +0 -36
  58. package/dist/index.d.cts +0 -1172
  59. package/dist/index.d.mts +0 -1172
  60. package/dist/index.mjs +0 -3
  61. package/dist/template-CkAkdP8n.mjs +0 -2545
  62. package/dist/template-Cup47s9h.cjs +0 -2783
  63. package/src/api/fetch.test.ts +0 -114
  64. package/src/api/fetch.ts +0 -249
  65. package/src/cache/index.ts +0 -89
  66. package/src/commands/create.ts +0 -463
  67. package/src/commands/mcp.test.ts +0 -152
  68. package/src/commands/mcp.ts +0 -203
  69. package/src/engine/compile-with-addons.test.ts +0 -302
  70. package/src/engine/compile.test.ts +0 -404
  71. package/src/engine/compile.ts +0 -551
  72. package/src/engine/config-file.test.ts +0 -118
  73. package/src/engine/config-file.ts +0 -61
  74. package/src/engine/custom-addons/integration.ts +0 -323
  75. package/src/engine/custom-addons/shared.test.ts +0 -98
  76. package/src/engine/custom-addons/shared.ts +0 -281
  77. package/src/engine/custom-addons/template.test.ts +0 -288
  78. package/src/engine/custom-addons/template.ts +0 -124
  79. package/src/engine/template.test.ts +0 -256
  80. package/src/engine/template.ts +0 -269
  81. package/src/engine/types.ts +0 -336
  82. package/src/parse-gitignore.d.ts +0 -5
  83. package/src/templates/base.ts +0 -891
@@ -1,404 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { compile, compileWithAttribution } from './compile.js'
3
- import type { CompileOptions, CustomTemplateCompiled, IntegrationCompiled } from './types.js'
4
-
5
- const baseOptions: CompileOptions = {
6
- projectName: 'test-project',
7
- framework: 'react',
8
- mode: 'file-router',
9
- typescript: true,
10
- tailwind: true,
11
- packageManager: 'pnpm',
12
- chosenIntegrations: [],
13
- integrationOptions: {},
14
- }
15
-
16
- describe('compile', () => {
17
- describe('base template', () => {
18
- it('should generate base project files', () => {
19
- const output = compile(baseOptions)
20
-
21
- // Should have essential files
22
- expect(output.files).toHaveProperty('package.json')
23
- expect(output.files).toHaveProperty('vite.config.ts')
24
- expect(output.files).toHaveProperty('tsconfig.json')
25
- expect(output.files).toHaveProperty('src/routes/__root.tsx')
26
- expect(output.files).toHaveProperty('src/routes/index.tsx')
27
- expect(output.files).toHaveProperty('src/styles.css')
28
- expect(output.files).toHaveProperty('.gitignore')
29
- expect(output.files).toHaveProperty('.env.example')
30
- })
31
-
32
- it('should generate valid package.json', () => {
33
- const output = compile(baseOptions)
34
- const pkg = JSON.parse(output.files['package.json']!)
35
-
36
- expect(pkg.name).toBe('test-project')
37
- expect(pkg.scripts).toHaveProperty('dev')
38
- expect(pkg.scripts).toHaveProperty('build')
39
- expect(pkg.scripts).toHaveProperty('start')
40
- expect(pkg.dependencies).toHaveProperty('@tanstack/react-start')
41
- expect(pkg.dependencies).toHaveProperty('@tanstack/react-router')
42
- })
43
-
44
- it('should include tailwind when enabled', () => {
45
- const output = compile({ ...baseOptions, tailwind: true })
46
- const pkg = JSON.parse(output.files['package.json']!)
47
-
48
- expect(pkg.devDependencies).toHaveProperty('@tailwindcss/vite')
49
- expect(output.files['vite.config.ts']).toContain('tailwindcss')
50
- })
51
-
52
- it('should exclude tailwind when disabled', () => {
53
- const output = compile({ ...baseOptions, tailwind: false })
54
- const pkg = JSON.parse(output.files['package.json']!)
55
-
56
- expect(pkg.dependencies).not.toHaveProperty('@tailwindcss/vite')
57
- expect(output.files['vite.config.ts']).not.toContain('tailwindcss')
58
- })
59
-
60
- it('should generate vite.config.ts with correct plugins', () => {
61
- const output = compile(baseOptions)
62
- const viteConfig = output.files['vite.config.ts']!
63
-
64
- expect(viteConfig).toContain("import { defineConfig } from 'vite'")
65
- expect(viteConfig).toContain('tanstackStart')
66
- expect(viteConfig).toContain('viteReact')
67
- expect(viteConfig).toContain('viteTsConfigPaths')
68
- })
69
-
70
- it('should generate __root.tsx with router devtools', () => {
71
- const output = compile(baseOptions)
72
- const rootRoute = output.files['src/routes/__root.tsx']!
73
-
74
- expect(rootRoute).toContain('createRootRoute')
75
- expect(rootRoute).toContain('TanStackRouterDevtools')
76
- expect(rootRoute).toContain('shellComponent')
77
- expect(rootRoute).toContain('{children}')
78
- })
79
- })
80
-
81
- describe('integration', () => {
82
- const mockIntegration: IntegrationCompiled = {
83
- id: 'test-integration',
84
- name: 'Test Integration',
85
- description: 'A test integration',
86
- type: 'integration',
87
- phase: 'integration',
88
- modes: ['file-router'],
89
- files: {
90
- 'src/integrations/test-integration/index.ts': 'export const testIntegration = true',
91
- },
92
- packageAdditions: {
93
- dependencies: {
94
- 'test-package': '^1.0.0',
95
- },
96
- devDependencies: {
97
- 'test-dev-package': '^2.0.0',
98
- },
99
- },
100
- }
101
-
102
- it('should include integration files in output', () => {
103
- const output = compile({
104
- ...baseOptions,
105
- chosenIntegrations: [mockIntegration],
106
- })
107
-
108
- expect(output.files).toHaveProperty('src/integrations/test-integration/index.ts')
109
- expect(output.files['src/integrations/test-integration/index.ts']).toBe(
110
- 'export const testIntegration = true',
111
- )
112
- })
113
-
114
- it('should merge integration package dependencies', () => {
115
- const output = compile({
116
- ...baseOptions,
117
- chosenIntegrations: [mockIntegration],
118
- })
119
-
120
- expect(output.packages.dependencies).toHaveProperty('test-package', '^1.0.0')
121
- expect(output.packages.devDependencies).toHaveProperty('test-dev-package', '^2.0.0')
122
- })
123
-
124
- it('should collect integration warnings', () => {
125
- const integrationWithWarning: IntegrationCompiled = {
126
- ...mockIntegration,
127
- id: 'warning-integration',
128
- name: 'Warning Integration',
129
- warning: 'This integration requires configuration!',
130
- }
131
-
132
- const output = compile({
133
- ...baseOptions,
134
- chosenIntegrations: [integrationWithWarning],
135
- })
136
-
137
- // Warnings are prefixed with integration name
138
- expect(output.warnings).toContain('Warning Integration: This integration requires configuration!')
139
- })
140
-
141
- it('should collect integration env vars', () => {
142
- const integrationWithEnv: IntegrationCompiled = {
143
- ...mockIntegration,
144
- id: 'env-integration',
145
- envVars: [
146
- { name: 'API_KEY', description: 'Your API key', required: true },
147
- { name: 'API_URL', description: 'API endpoint', example: 'https://api.example.com' },
148
- ],
149
- }
150
-
151
- const output = compile({
152
- ...baseOptions,
153
- chosenIntegrations: [integrationWithEnv],
154
- })
155
-
156
- expect(output.envVars).toHaveLength(2)
157
- expect(output.envVars[0]).toEqual({
158
- name: 'API_KEY',
159
- description: 'Your API key',
160
- required: true,
161
- })
162
- })
163
- })
164
-
165
- describe('vite-plugin hook', () => {
166
- it('should inject vite plugins into vite.config.ts', () => {
167
- const integrationWithVitePlugin: IntegrationCompiled = {
168
- id: 'vite-plugin-integration',
169
- name: 'Vite Plugin Integration',
170
- description: 'Integration with vite plugin',
171
- type: 'integration',
172
- phase: 'integration',
173
- modes: ['file-router'],
174
- files: {
175
- 'src/integrations/vite-plugin-integration/vite-plugin.ts':
176
- 'export default function myPlugin() { return { name: "my-plugin" } }',
177
- },
178
- hooks: [
179
- {
180
- type: 'vite-plugin',
181
- jsName: 'myPlugin',
182
- path: 'src/integrations/vite-plugin-integration/vite-plugin.ts',
183
- code: 'myPlugin()',
184
- },
185
- ],
186
- }
187
-
188
- const output = compile({
189
- ...baseOptions,
190
- chosenIntegrations: [integrationWithVitePlugin],
191
- })
192
-
193
- const viteConfig = output.files['vite.config.ts']!
194
- expect(viteConfig).toContain('myPlugin')
195
- })
196
- })
197
-
198
- describe('root-provider hook', () => {
199
- it('should wrap app with provider in __root.tsx', () => {
200
- const integrationWithProvider: IntegrationCompiled = {
201
- id: 'provider-integration',
202
- name: 'Provider Integration',
203
- description: 'Integration with root provider',
204
- type: 'integration',
205
- phase: 'integration',
206
- modes: ['file-router'],
207
- files: {
208
- 'src/integrations/provider-integration/provider.tsx':
209
- 'export function Provider({ children }) { return <div>{children}</div> }',
210
- },
211
- hooks: [
212
- {
213
- type: 'root-provider',
214
- jsName: 'Provider',
215
- path: 'src/integrations/provider-integration/provider.tsx',
216
- code: '<Provider>',
217
- },
218
- ],
219
- }
220
-
221
- const output = compile({
222
- ...baseOptions,
223
- chosenIntegrations: [integrationWithProvider],
224
- })
225
-
226
- const rootRoute = output.files['src/routes/__root.tsx']!
227
- expect(rootRoute).toContain('Provider')
228
- })
229
- })
230
-
231
- describe('devtools hook', () => {
232
- it('should add devtools to __root.tsx', () => {
233
- const integrationWithDevtools: IntegrationCompiled = {
234
- id: 'devtools-integration',
235
- name: 'Devtools Integration',
236
- description: 'Integration with devtools',
237
- type: 'integration',
238
- phase: 'integration',
239
- modes: ['file-router'],
240
- files: {
241
- 'src/integrations/devtools-integration/devtools.tsx':
242
- 'export function Devtools() { return <div>Devtools</div> }',
243
- },
244
- hooks: [
245
- {
246
- type: 'devtools',
247
- jsName: 'Devtools',
248
- path: 'src/integrations/devtools-integration/devtools.tsx',
249
- code: '<Devtools />',
250
- },
251
- ],
252
- }
253
-
254
- const output = compile({
255
- ...baseOptions,
256
- chosenIntegrations: [integrationWithDevtools],
257
- })
258
-
259
- const rootRoute = output.files['src/routes/__root.tsx']!
260
- expect(rootRoute).toContain('Devtools')
261
- })
262
- })
263
-
264
- describe('custom template support', () => {
265
- // Custom templates are just integration presets - they don't add files directly
266
- const mockTemplate: CustomTemplateCompiled = {
267
- id: 'test-template',
268
- name: 'Test Template',
269
- description: 'A test template',
270
- framework: 'react',
271
- mode: 'file-router',
272
- typescript: true,
273
- tailwind: true,
274
- integrations: [], // List of integration IDs to include
275
- }
276
-
277
- it('should compile with custom template (templates are just integration presets)', () => {
278
- const output = compile({
279
- ...baseOptions,
280
- customTemplate: mockTemplate,
281
- })
282
-
283
- // Template doesn't add files directly - it just specifies integrations
284
- // The template's integrations should be resolved into chosenIntegrations by caller
285
- expect(output.files).toHaveProperty('package.json')
286
- expect(output.files).toHaveProperty('vite.config.ts')
287
- })
288
-
289
- it('should use custom template settings', () => {
290
- const output = compile({
291
- ...baseOptions,
292
- // Template settings would be applied by the create command
293
- // Here we just verify compile works with a template present
294
- customTemplate: mockTemplate,
295
- })
296
-
297
- expect(output.files).toBeDefined()
298
- })
299
- })
300
-
301
- describe('integration sorting by phase', () => {
302
- it('should process setup integrations before integration phase', () => {
303
- const setupIntegration: IntegrationCompiled = {
304
- id: 'setup-integration',
305
- name: 'Setup Integration',
306
- description: 'Setup phase integration',
307
- type: 'toolchain',
308
- phase: 'setup',
309
- modes: ['file-router'],
310
- files: { 'setup.txt': 'setup' },
311
- }
312
-
313
- const integrationPhase: IntegrationCompiled = {
314
- id: 'integration-phase',
315
- name: 'Integration Phase',
316
- description: 'Integration phase integration',
317
- type: 'integration',
318
- phase: 'integration',
319
- modes: ['file-router'],
320
- files: { 'integration.txt': 'integration' },
321
- }
322
-
323
- // Order shouldn't matter in input - they should be sorted internally
324
- const output = compile({
325
- ...baseOptions,
326
- chosenIntegrations: [integrationPhase, setupIntegration],
327
- })
328
-
329
- // Both files should exist
330
- expect(output.files).toHaveProperty('setup.txt')
331
- expect(output.files).toHaveProperty('integration.txt')
332
- })
333
- })
334
- })
335
-
336
- describe('compileWithAttribution', () => {
337
- it('should include line attributions for files', () => {
338
- const output = compileWithAttribution(baseOptions)
339
-
340
- expect(output.attributedFiles).toBeDefined()
341
- expect(output.attributedFiles['vite.config.ts']).toBeDefined()
342
- expect(output.attributedFiles['vite.config.ts']!.attributions.length).toBeGreaterThan(0)
343
- })
344
-
345
- it('should attribute integration lines to the integration', () => {
346
- const integration: IntegrationCompiled = {
347
- id: 'attr-integration',
348
- name: 'Attribution Integration',
349
- description: 'Test attribution',
350
- type: 'integration',
351
- phase: 'integration',
352
- modes: ['file-router'],
353
- files: {},
354
- hooks: [
355
- {
356
- type: 'vite-plugin',
357
- jsName: 'myPlugin',
358
- path: 'src/integrations/attr-integration/plugin.ts',
359
- code: 'myPlugin()',
360
- },
361
- ],
362
- }
363
-
364
- const output = compileWithAttribution({
365
- ...baseOptions,
366
- chosenIntegrations: [integration],
367
- })
368
-
369
- const viteAttrs = output.attributedFiles['vite.config.ts']!.attributions
370
- const integrationLine = viteAttrs.find((a) => a.featureId === 'attr-integration')
371
- expect(integrationLine).toBeDefined()
372
- })
373
-
374
- it('should attribute gitignore patterns to integrations', () => {
375
- const integration: IntegrationCompiled = {
376
- id: 'drizzle',
377
- name: 'Drizzle',
378
- description: 'Database ORM',
379
- type: 'integration',
380
- phase: 'integration',
381
- modes: ['file-router'],
382
- files: {},
383
- gitignorePatterns: ['drizzle/', '*.db'],
384
- }
385
-
386
- const output = compileWithAttribution({
387
- ...baseOptions,
388
- chosenIntegrations: [integration],
389
- })
390
-
391
- // Check gitignore has attributions
392
- const gitignoreAttrs = output.attributedFiles['.gitignore']!.attributions
393
- expect(gitignoreAttrs).toBeDefined()
394
-
395
- // Should have integration-attributed lines
396
- const integrationLines = gitignoreAttrs.filter((a) => a.featureId === 'drizzle')
397
- expect(integrationLines.length).toBe(2) // drizzle/ and *.db
398
-
399
- // Check the actual content includes the patterns
400
- const gitignoreContent = output.files['.gitignore']!
401
- expect(gitignoreContent).toContain('drizzle/')
402
- expect(gitignoreContent).toContain('*.db')
403
- })
404
- })