@tanstack/cta-cli 0.15.12 → 0.16.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 (3) hide show
  1. package/dist/cli.js +66 -3
  2. package/package.json +5 -3
  3. package/src/cli.ts +79 -3
package/dist/cli.js CHANGED
@@ -1,8 +1,10 @@
1
+ import fs from 'node:fs';
1
2
  import { resolve } from 'node:path';
2
3
  import { Command, InvalidArgumentError } from 'commander';
3
4
  import { intro, log } from '@clack/prompts';
4
5
  import chalk from 'chalk';
5
- import { SUPPORTED_PACKAGE_MANAGERS, addToApp, compileAddOn, compileStarter, createApp, createSerializedOptions, getAllAddOns, getFrameworkById, getFrameworkByName, getFrameworks, initAddOn, initStarter, } from '@tanstack/cta-engine';
6
+ import semver from 'semver';
7
+ import { SUPPORTED_PACKAGE_MANAGERS, addToApp, compileAddOn, compileStarter, createApp, createSerializedOptions, getAllAddOns, getFrameworkById, getFrameworks, initAddOn, initStarter, } from '@tanstack/cta-engine';
6
8
  import { launchUI } from '@tanstack/cta-ui';
7
9
  import { runMCPServer } from './mcp.js';
8
10
  import { promptForAddOns, promptForCreateOptions } from './options.js';
@@ -36,6 +38,66 @@ export function cli({ name, appName, forcedMode, forcedAddOns = [], defaultTempl
36
38
  defaultMode = Array.from(supportedModes)[0];
37
39
  }
38
40
  program.name(name).description(`CLI to create a new ${appName} application`);
41
+ program
42
+ .command('pin-versions')
43
+ .description('Pin versions of the TanStack libraries')
44
+ .action(async () => {
45
+ if (!fs.existsSync('package.json')) {
46
+ console.error('package.json not found');
47
+ return;
48
+ }
49
+ const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
50
+ const packages = {
51
+ '@tanstack/react-router': '',
52
+ '@tanstack/router-generator': '',
53
+ '@tanstack/react-router-devtools': '',
54
+ '@tanstack/react-start': '',
55
+ '@tanstack/react-start-config': '',
56
+ '@tanstack/router-plugin': '',
57
+ '@tanstack/react-start-client': '',
58
+ '@tanstack/react-start-plugin': '1.115.0',
59
+ '@tanstack/react-start-server': '',
60
+ '@tanstack/start-server-core': '1.115.0',
61
+ };
62
+ function sortObject(obj) {
63
+ return Object.keys(obj)
64
+ .sort()
65
+ .reduce((acc, key) => {
66
+ acc[key] = obj[key];
67
+ return acc;
68
+ }, {});
69
+ }
70
+ if (!packageJson.dependencies['@tanstack/react-start']) {
71
+ console.error('@tanstack/react-start not found in dependencies');
72
+ return;
73
+ }
74
+ let changed = 0;
75
+ const startVersion = packageJson.dependencies['@tanstack/react-start'].replace(/^\^/, '');
76
+ for (const pkg of Object.keys(packages)) {
77
+ if (!packageJson.dependencies[pkg]) {
78
+ packageJson.dependencies[pkg] = packages[pkg].length
79
+ ? semver.maxSatisfying([startVersion, packages[pkg]], `^${packages[pkg]}`)
80
+ : startVersion;
81
+ changed++;
82
+ }
83
+ else {
84
+ if (packageJson.dependencies[pkg].startsWith('^')) {
85
+ packageJson.dependencies[pkg] = packageJson.dependencies[pkg].replace(/^\^/, '');
86
+ changed++;
87
+ }
88
+ }
89
+ }
90
+ packageJson.dependencies = sortObject(packageJson.dependencies);
91
+ if (changed > 0) {
92
+ fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2));
93
+ console.log(`${changed} packages updated.
94
+
95
+ Remove your node_modules directory and package lock file and re-install.`);
96
+ }
97
+ else {
98
+ console.log('No changes needed. The relevant TanStack packages are already pinned.');
99
+ }
100
+ });
39
101
  program
40
102
  .command('add')
41
103
  .argument('[add-on...]', 'Name of the add-ons (or add-ons separated by spaces or commas)')
@@ -119,7 +181,7 @@ export function cli({ name, appName, forcedMode, forcedAddOns = [], defaultTempl
119
181
  throw new InvalidArgumentError(`Invalid framework: ${value}. Only the following are allowed: ${availableFrameworks.join(', ')}`);
120
182
  }
121
183
  return value;
122
- }, defaultFramework || 'React');
184
+ }, defaultFramework || 'react-cra');
123
185
  }
124
186
  program
125
187
  .option('--starter [url]', 'initialize this project from a starter URL', false)
@@ -155,6 +217,7 @@ export function cli({ name, appName, forcedMode, forcedAddOns = [], defaultTempl
155
217
  .option('--ui', 'Add with the UI');
156
218
  program.action(async (projectName, options) => {
157
219
  if (options.listAddOns) {
220
+ console.log(options.framework || defaultFramework || 'react-cra');
158
221
  const addOns = await getAllAddOns(getFrameworkById(options.framework || defaultFramework || 'react-cra'), defaultMode ||
159
222
  convertTemplateToMode(options.template || defaultTemplate));
160
223
  for (const addOn of addOns.filter((a) => !forcedAddOns.includes(a.id))) {
@@ -174,7 +237,7 @@ export function cli({ name, appName, forcedMode, forcedAddOns = [], defaultTempl
174
237
  projectName,
175
238
  ...options,
176
239
  };
177
- cliOptions.framework = getFrameworkByName(options.framework || defaultFramework || 'React').id;
240
+ cliOptions.framework = getFrameworkById(options.framework || defaultFramework || 'react-cra').id;
178
241
  if (defaultMode) {
179
242
  cliOptions.template = defaultMode;
180
243
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/cta-cli",
3
- "version": "0.15.12",
3
+ "version": "0.16.1",
4
4
  "description": "Tanstack Application Builder CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,14 +28,16 @@
28
28
  "chalk": "^5.4.1",
29
29
  "commander": "^13.1.0",
30
30
  "express": "^4.21.2",
31
+ "semver": "^7.7.2",
31
32
  "zod": "^3.24.2",
32
- "@tanstack/cta-engine": "0.15.12",
33
- "@tanstack/cta-ui": "0.15.12"
33
+ "@tanstack/cta-engine": "0.16.1",
34
+ "@tanstack/cta-ui": "0.16.1"
34
35
  },
35
36
  "devDependencies": {
36
37
  "@tanstack/config": "^0.16.2",
37
38
  "@types/express": "^5.0.1",
38
39
  "@types/node": "^22.13.4",
40
+ "@types/semver": "^7.7.0",
39
41
  "@vitest/coverage-v8": "3.1.1",
40
42
  "eslint": "^9.20.0",
41
43
  "typescript": "^5.6.3",
package/src/cli.ts CHANGED
@@ -1,7 +1,9 @@
1
+ import fs from 'node:fs'
1
2
  import { resolve } from 'node:path'
2
3
  import { Command, InvalidArgumentError } from 'commander'
3
4
  import { intro, log } from '@clack/prompts'
4
5
  import chalk from 'chalk'
6
+ import semver from 'semver'
5
7
 
6
8
  import {
7
9
  SUPPORTED_PACKAGE_MANAGERS,
@@ -87,6 +89,79 @@ export function cli({
87
89
 
88
90
  program.name(name).description(`CLI to create a new ${appName} application`)
89
91
 
92
+ program
93
+ .command('pin-versions')
94
+ .description('Pin versions of the TanStack libraries')
95
+ .action(async () => {
96
+ if (!fs.existsSync('package.json')) {
97
+ console.error('package.json not found')
98
+ return
99
+ }
100
+ const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'))
101
+
102
+ const packages: Record<string, string> = {
103
+ '@tanstack/react-router': '',
104
+ '@tanstack/router-generator': '',
105
+ '@tanstack/react-router-devtools': '',
106
+ '@tanstack/react-start': '',
107
+ '@tanstack/react-start-config': '',
108
+ '@tanstack/router-plugin': '',
109
+ '@tanstack/react-start-client': '',
110
+ '@tanstack/react-start-plugin': '1.115.0',
111
+ '@tanstack/react-start-server': '',
112
+ '@tanstack/start-server-core': '1.115.0',
113
+ }
114
+
115
+ function sortObject(obj: Record<string, string>): Record<string, string> {
116
+ return Object.keys(obj)
117
+ .sort()
118
+ .reduce<Record<string, string>>((acc, key) => {
119
+ acc[key] = obj[key]
120
+ return acc
121
+ }, {})
122
+ }
123
+
124
+ if (!packageJson.dependencies['@tanstack/react-start']) {
125
+ console.error('@tanstack/react-start not found in dependencies')
126
+ return
127
+ }
128
+ let changed = 0
129
+ const startVersion = packageJson.dependencies[
130
+ '@tanstack/react-start'
131
+ ].replace(/^\^/, '')
132
+ for (const pkg of Object.keys(packages)) {
133
+ if (!packageJson.dependencies[pkg]) {
134
+ packageJson.dependencies[pkg] = packages[pkg].length
135
+ ? semver.maxSatisfying(
136
+ [startVersion, packages[pkg]],
137
+ `^${packages[pkg]}`,
138
+ )!
139
+ : startVersion
140
+ changed++
141
+ } else {
142
+ if (packageJson.dependencies[pkg].startsWith('^')) {
143
+ packageJson.dependencies[pkg] = packageJson.dependencies[
144
+ pkg
145
+ ].replace(/^\^/, '')
146
+ changed++
147
+ }
148
+ }
149
+ }
150
+ packageJson.dependencies = sortObject(packageJson.dependencies)
151
+ if (changed > 0) {
152
+ fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2))
153
+ console.log(
154
+ `${changed} packages updated.
155
+
156
+ Remove your node_modules directory and package lock file and re-install.`,
157
+ )
158
+ } else {
159
+ console.log(
160
+ 'No changes needed. The relevant TanStack packages are already pinned.',
161
+ )
162
+ }
163
+ })
164
+
90
165
  program
91
166
  .command('add')
92
167
  .argument(
@@ -191,7 +266,7 @@ export function cli({
191
266
  }
192
267
  return value
193
268
  },
194
- defaultFramework || 'React',
269
+ defaultFramework || 'react-cra',
195
270
  )
196
271
  }
197
272
 
@@ -259,6 +334,7 @@ export function cli({
259
334
 
260
335
  program.action(async (projectName: string, options: CliOptions) => {
261
336
  if (options.listAddOns) {
337
+ console.log(options.framework || defaultFramework || 'react-cra')
262
338
  const addOns = await getAllAddOns(
263
339
  getFrameworkById(options.framework || defaultFramework || 'react-cra')!,
264
340
  defaultMode ||
@@ -280,8 +356,8 @@ export function cli({
280
356
  ...options,
281
357
  } as CliOptions
282
358
 
283
- cliOptions.framework = getFrameworkByName(
284
- options.framework || defaultFramework || 'React',
359
+ cliOptions.framework = getFrameworkById(
360
+ options.framework || defaultFramework || 'react-cra',
285
361
  )!.id
286
362
 
287
363
  if (defaultMode) {