@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.
- package/dist/bin.js +7 -0
- package/dist/cli.js +481 -0
- package/dist/command-line.js +174 -0
- package/dist/dev-watch.js +290 -0
- package/dist/file-syncer.js +148 -0
- package/dist/index.js +1 -0
- package/dist/mcp/api.js +31 -0
- package/dist/mcp/tools.js +250 -0
- package/dist/mcp/types.js +37 -0
- package/dist/mcp.js +121 -0
- package/dist/options.js +162 -0
- package/dist/types/bin.d.ts +2 -0
- package/dist/types/cli.d.ts +16 -0
- package/dist/types/command-line.d.ts +10 -0
- package/dist/types/dev-watch.d.ts +27 -0
- package/dist/types/file-syncer.d.ts +18 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/mcp/api.d.ts +4 -0
- package/dist/types/mcp/tools.d.ts +2 -0
- package/dist/types/mcp/types.d.ts +217 -0
- package/dist/types/mcp.d.ts +6 -0
- package/dist/types/options.d.ts +8 -0
- package/dist/types/types.d.ts +25 -0
- package/dist/types/ui-environment.d.ts +2 -0
- package/dist/types/ui-prompts.d.ts +12 -0
- package/dist/types/utils.d.ts +8 -0
- package/dist/types.js +1 -0
- package/dist/ui-environment.js +52 -0
- package/dist/ui-prompts.js +244 -0
- package/dist/utils.js +30 -0
- package/package.json +46 -46
- package/src/bin.ts +6 -93
- package/src/cli.ts +692 -0
- package/src/command-line.ts +236 -0
- package/src/dev-watch.ts +430 -0
- package/src/file-syncer.ts +205 -0
- package/src/index.ts +1 -85
- package/src/mcp.ts +190 -0
- package/src/options.ts +260 -0
- package/src/types.ts +27 -0
- package/src/ui-environment.ts +74 -0
- package/src/ui-prompts.ts +322 -0
- package/src/utils.ts +38 -0
- package/tests/command-line.test.ts +304 -0
- package/tests/index.test.ts +9 -0
- package/tests/mcp.test.ts +225 -0
- package/tests/options.test.ts +304 -0
- package/tests/setupVitest.ts +6 -0
- package/tests/ui-environment.test.ts +97 -0
- package/tests/ui-prompts.test.ts +238 -0
- package/tsconfig.json +17 -0
- package/vitest.config.js +7 -0
- package/dist/bin.cjs +0 -761
- package/dist/bin.d.cts +0 -1
- package/dist/bin.d.mts +0 -1
- package/dist/bin.mjs +0 -760
- package/dist/index.cjs +0 -36
- package/dist/index.d.cts +0 -1172
- package/dist/index.d.mts +0 -1172
- package/dist/index.mjs +0 -3
- package/dist/template-CkAkdP8n.mjs +0 -2545
- package/dist/template-Cup47s9h.cjs +0 -2783
- package/src/api/fetch.test.ts +0 -114
- package/src/api/fetch.ts +0 -249
- package/src/cache/index.ts +0 -89
- package/src/commands/create.ts +0 -463
- package/src/commands/mcp.test.ts +0 -152
- package/src/commands/mcp.ts +0 -203
- package/src/engine/compile-with-addons.test.ts +0 -302
- package/src/engine/compile.test.ts +0 -404
- package/src/engine/compile.ts +0 -551
- package/src/engine/config-file.test.ts +0 -118
- package/src/engine/config-file.ts +0 -61
- package/src/engine/custom-addons/integration.ts +0 -323
- package/src/engine/custom-addons/shared.test.ts +0 -98
- package/src/engine/custom-addons/shared.ts +0 -281
- package/src/engine/custom-addons/template.test.ts +0 -288
- package/src/engine/custom-addons/template.ts +0 -124
- package/src/engine/template.test.ts +0 -256
- package/src/engine/template.ts +0 -269
- package/src/engine/types.ts +0 -336
- package/src/parse-gitignore.d.ts +0 -5
- package/src/templates/base.ts +0 -891
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile } from 'node:fs/promises'
|
|
2
|
-
import { existsSync } from 'node:fs'
|
|
3
|
-
import { resolve } from 'node:path'
|
|
4
|
-
|
|
5
|
-
import type { CompileOptions, PackageManager, RouterMode } from './types.js'
|
|
6
|
-
|
|
7
|
-
export const CONFIG_FILE = '.tanstack.json'
|
|
8
|
-
|
|
9
|
-
export interface PersistedOptions {
|
|
10
|
-
version: number
|
|
11
|
-
projectName: string
|
|
12
|
-
framework: string
|
|
13
|
-
mode: RouterMode
|
|
14
|
-
typescript: boolean
|
|
15
|
-
tailwind: boolean
|
|
16
|
-
packageManager: PackageManager
|
|
17
|
-
chosenIntegrations: Array<string>
|
|
18
|
-
customTemplate?: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function createPersistedOptions(options: CompileOptions): PersistedOptions {
|
|
22
|
-
return {
|
|
23
|
-
version: 1,
|
|
24
|
-
projectName: options.projectName,
|
|
25
|
-
framework: options.framework,
|
|
26
|
-
mode: options.mode,
|
|
27
|
-
typescript: options.typescript,
|
|
28
|
-
tailwind: options.tailwind,
|
|
29
|
-
packageManager: options.packageManager,
|
|
30
|
-
chosenIntegrations: options.chosenIntegrations.map((integration) => integration.id),
|
|
31
|
-
customTemplate: options.customTemplate?.id,
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export async function writeConfigFile(
|
|
36
|
-
targetDir: string,
|
|
37
|
-
options: CompileOptions,
|
|
38
|
-
): Promise<void> {
|
|
39
|
-
const configPath = resolve(targetDir, CONFIG_FILE)
|
|
40
|
-
await writeFile(
|
|
41
|
-
configPath,
|
|
42
|
-
JSON.stringify(createPersistedOptions(options), null, 2),
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function readConfigFile(
|
|
47
|
-
targetDir: string,
|
|
48
|
-
): Promise<PersistedOptions | null> {
|
|
49
|
-
const configPath = resolve(targetDir, CONFIG_FILE)
|
|
50
|
-
|
|
51
|
-
if (!existsSync(configPath)) {
|
|
52
|
-
return null
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const content = await readFile(configPath, 'utf-8')
|
|
57
|
-
return JSON.parse(content)
|
|
58
|
-
} catch {
|
|
59
|
-
return null
|
|
60
|
-
}
|
|
61
|
-
}
|
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
2
|
-
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
3
|
-
import { basename, dirname, resolve } from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { IntegrationCompiledSchema } from '../types.js'
|
|
6
|
-
import {
|
|
7
|
-
compareFilesRecursively,
|
|
8
|
-
createCompileOptionsFromPersisted,
|
|
9
|
-
createIgnore,
|
|
10
|
-
createPackageAdditions,
|
|
11
|
-
readCurrentProjectOptions,
|
|
12
|
-
recursivelyGatherFiles,
|
|
13
|
-
runCompile,
|
|
14
|
-
} from './shared.js'
|
|
15
|
-
|
|
16
|
-
import type { PersistedOptions } from '../config-file.js'
|
|
17
|
-
import type { IntegrationCompiled, IntegrationInfo, Route } from '../types.js'
|
|
18
|
-
|
|
19
|
-
const INTEGRATION_DIR = '.integration'
|
|
20
|
-
const INFO_FILE = '.integration/info.json'
|
|
21
|
-
const COMPILED_FILE = 'integration.json'
|
|
22
|
-
const ASSETS_DIR = 'assets'
|
|
23
|
-
|
|
24
|
-
// Files to ignore when building integration assets (these are generated or template-specific)
|
|
25
|
-
const INTEGRATION_IGNORE_FILES = [
|
|
26
|
-
'main.jsx',
|
|
27
|
-
'App.jsx',
|
|
28
|
-
'main.tsx',
|
|
29
|
-
'App.tsx',
|
|
30
|
-
'routeTree.gen.ts',
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
function camelCase(str: string): string {
|
|
34
|
-
return str
|
|
35
|
-
.split(/(\.|-|\/)/)
|
|
36
|
-
.filter((part) => /^[a-zA-Z]+$/.test(part))
|
|
37
|
-
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
38
|
-
.join('')
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function templatize(routeCode: string, routeFile: string): {
|
|
42
|
-
url: string
|
|
43
|
-
code: string
|
|
44
|
-
name: string
|
|
45
|
-
jsName: string
|
|
46
|
-
} {
|
|
47
|
-
let code = routeCode
|
|
48
|
-
|
|
49
|
-
// Replace the import
|
|
50
|
-
code = code.replace(
|
|
51
|
-
/import { createFileRoute } from ['"]@tanstack\/react-router['"]/g,
|
|
52
|
-
`import { <% if (fileRouter) { %>createFileRoute<% } else { %>createRoute<% } %> } from '@tanstack/react-router'`,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
// Extract route path and definition, then transform the route declaration
|
|
56
|
-
const routeMatch = code.match(
|
|
57
|
-
/export\s+const\s+Route\s*=\s*createFileRoute\(['"]([^'"]+)['"]\)\s*\(\{([^}]+)\}\)/,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
let path = ''
|
|
61
|
-
|
|
62
|
-
if (routeMatch) {
|
|
63
|
-
const fullMatch = routeMatch[0]
|
|
64
|
-
path = routeMatch[1]!
|
|
65
|
-
const routeDefinition = routeMatch[2]
|
|
66
|
-
code = code.replace(
|
|
67
|
-
fullMatch,
|
|
68
|
-
`<% if (codeRouter) { %>
|
|
69
|
-
import type { RootRoute } from '@tanstack/react-router'
|
|
70
|
-
<% } else { %>
|
|
71
|
-
export const Route = createFileRoute('${path}')({${routeDefinition}})
|
|
72
|
-
<% } %>`,
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
code += `
|
|
76
|
-
<% if (codeRouter) { %>
|
|
77
|
-
export default (parentRoute: RootRoute) => createRoute({
|
|
78
|
-
path: '${path}',
|
|
79
|
-
${routeDefinition}
|
|
80
|
-
getParentRoute: () => parentRoute,
|
|
81
|
-
})
|
|
82
|
-
<% } %>
|
|
83
|
-
`
|
|
84
|
-
} else {
|
|
85
|
-
console.warn(`No route found in the file: ${routeFile}`)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const name = basename(path)
|
|
89
|
-
.replace('.tsx', '')
|
|
90
|
-
.replace(/^demo/, '')
|
|
91
|
-
.replace('.', ' ')
|
|
92
|
-
.trim()
|
|
93
|
-
|
|
94
|
-
const jsName = camelCase(basename(path))
|
|
95
|
-
|
|
96
|
-
return { url: path, code, name, jsName }
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async function validateIntegrationSetup(targetDir: string): Promise<void> {
|
|
100
|
-
const options = await readCurrentProjectOptions(targetDir)
|
|
101
|
-
|
|
102
|
-
if (options.mode === 'code-router') {
|
|
103
|
-
throw new Error(
|
|
104
|
-
'This project is using code-router mode.\n' +
|
|
105
|
-
'To create an integration, the project must use file-router mode.',
|
|
106
|
-
)
|
|
107
|
-
}
|
|
108
|
-
if (!options.tailwind) {
|
|
109
|
-
throw new Error(
|
|
110
|
-
'This project is not using Tailwind CSS.\n' +
|
|
111
|
-
'To create an integration, the project must be created with Tailwind CSS.',
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
if (!options.typescript) {
|
|
115
|
-
throw new Error(
|
|
116
|
-
'This project is not using TypeScript.\n' +
|
|
117
|
-
'To create an integration, the project must be created with TypeScript.',
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async function readOrGenerateIntegrationInfo(
|
|
123
|
-
options: PersistedOptions,
|
|
124
|
-
targetDir: string,
|
|
125
|
-
): Promise<IntegrationInfo> {
|
|
126
|
-
const infoPath = resolve(targetDir, INFO_FILE)
|
|
127
|
-
|
|
128
|
-
if (existsSync(infoPath)) {
|
|
129
|
-
const content = await readFile(infoPath, 'utf-8')
|
|
130
|
-
return JSON.parse(content)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
id: `${options.projectName}-integration`,
|
|
135
|
-
name: `${options.projectName} Integration`,
|
|
136
|
-
description: 'Custom integration',
|
|
137
|
-
author: 'Author <author@example.com>',
|
|
138
|
-
version: '0.0.1',
|
|
139
|
-
license: 'MIT',
|
|
140
|
-
link: `https://github.com/example/${options.projectName}-integration`,
|
|
141
|
-
|
|
142
|
-
type: 'integration',
|
|
143
|
-
phase: 'integration',
|
|
144
|
-
modes: [options.mode],
|
|
145
|
-
|
|
146
|
-
requiresTailwind: options.tailwind || undefined,
|
|
147
|
-
|
|
148
|
-
dependsOn: options.chosenIntegrations.length > 0 ? options.chosenIntegrations : undefined,
|
|
149
|
-
|
|
150
|
-
routes: [],
|
|
151
|
-
packageAdditions: {
|
|
152
|
-
scripts: {},
|
|
153
|
-
dependencies: {},
|
|
154
|
-
devDependencies: {},
|
|
155
|
-
},
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async function generateBaseProject(
|
|
160
|
-
persistedOptions: PersistedOptions,
|
|
161
|
-
targetDir: string,
|
|
162
|
-
integrationsPath?: string,
|
|
163
|
-
): Promise<{ info: IntegrationInfo; output: { files: Record<string, string> } }> {
|
|
164
|
-
const info = await readOrGenerateIntegrationInfo(persistedOptions, targetDir)
|
|
165
|
-
|
|
166
|
-
const compileOptions = await createCompileOptionsFromPersisted(
|
|
167
|
-
persistedOptions,
|
|
168
|
-
integrationsPath,
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
const output = runCompile(compileOptions)
|
|
172
|
-
|
|
173
|
-
return { info, output }
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async function buildAssetsDirectory(
|
|
177
|
-
targetDir: string,
|
|
178
|
-
output: { files: Record<string, string> },
|
|
179
|
-
info: IntegrationInfo,
|
|
180
|
-
): Promise<void> {
|
|
181
|
-
const assetsDir = resolve(targetDir, INTEGRATION_DIR, ASSETS_DIR)
|
|
182
|
-
|
|
183
|
-
// Only build if assets directory doesn't exist yet
|
|
184
|
-
if (existsSync(assetsDir)) {
|
|
185
|
-
return
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const ignoreFn = createIgnore(targetDir)
|
|
189
|
-
const changedFiles: Record<string, string> = {}
|
|
190
|
-
await compareFilesRecursively(targetDir, ignoreFn, output.files, changedFiles)
|
|
191
|
-
|
|
192
|
-
for (const file of Object.keys(changedFiles)) {
|
|
193
|
-
// Skip ignored files
|
|
194
|
-
if (INTEGRATION_IGNORE_FILES.includes(basename(file))) {
|
|
195
|
-
continue
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const targetPath = resolve(assetsDir, file)
|
|
199
|
-
mkdirSync(dirname(targetPath), { recursive: true })
|
|
200
|
-
|
|
201
|
-
// Templatize route files
|
|
202
|
-
const fileContent = changedFiles[file]!
|
|
203
|
-
if (file.includes('/routes/')) {
|
|
204
|
-
const { url, code, name, jsName } = templatize(fileContent, file)
|
|
205
|
-
|
|
206
|
-
info.routes ||= []
|
|
207
|
-
const existingRoute = info.routes.find((r: Route) => r.url === url)
|
|
208
|
-
if (!existingRoute) {
|
|
209
|
-
info.routes.push({
|
|
210
|
-
url,
|
|
211
|
-
name,
|
|
212
|
-
jsName,
|
|
213
|
-
path: file,
|
|
214
|
-
})
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
writeFileSync(`${targetPath}.ejs`, code)
|
|
218
|
-
} else {
|
|
219
|
-
writeFileSync(targetPath, fileContent)
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
async function updateIntegrationInfo(
|
|
225
|
-
targetDir: string,
|
|
226
|
-
integrationsPath?: string,
|
|
227
|
-
): Promise<void> {
|
|
228
|
-
const persistedOptions = await readCurrentProjectOptions(targetDir)
|
|
229
|
-
const { info, output } = await generateBaseProject(persistedOptions, targetDir, integrationsPath)
|
|
230
|
-
|
|
231
|
-
// Calculate package.json differences
|
|
232
|
-
const originalPackageJson = JSON.parse(output.files['package.json']!)
|
|
233
|
-
const currentPackageJson = JSON.parse(
|
|
234
|
-
await readFile(resolve(targetDir, 'package.json'), 'utf-8'),
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
info.packageAdditions = createPackageAdditions(
|
|
238
|
-
originalPackageJson,
|
|
239
|
-
currentPackageJson,
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
await buildAssetsDirectory(targetDir, output, info)
|
|
243
|
-
|
|
244
|
-
// Write info file
|
|
245
|
-
const infoDir = resolve(targetDir, dirname(INFO_FILE))
|
|
246
|
-
await mkdir(infoDir, { recursive: true })
|
|
247
|
-
await writeFile(
|
|
248
|
-
resolve(targetDir, INFO_FILE),
|
|
249
|
-
JSON.stringify(info, null, 2),
|
|
250
|
-
)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export async function compileIntegration(
|
|
254
|
-
targetDir: string,
|
|
255
|
-
_integrationsPath?: string,
|
|
256
|
-
): Promise<void> {
|
|
257
|
-
const persistedOptions = await readCurrentProjectOptions(targetDir)
|
|
258
|
-
const info = await readOrGenerateIntegrationInfo(persistedOptions, targetDir)
|
|
259
|
-
|
|
260
|
-
const assetsDir = resolve(targetDir, INTEGRATION_DIR, ASSETS_DIR)
|
|
261
|
-
|
|
262
|
-
const compiledInfo: IntegrationCompiled = {
|
|
263
|
-
...info,
|
|
264
|
-
id: info.id || `${persistedOptions.projectName}-integration`,
|
|
265
|
-
files: await recursivelyGatherFiles(assetsDir),
|
|
266
|
-
deletedFiles: [],
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
await writeFile(
|
|
270
|
-
resolve(targetDir, COMPILED_FILE),
|
|
271
|
-
JSON.stringify(compiledInfo, null, 2),
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
console.log(`Compiled integration written to ${COMPILED_FILE}`)
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export async function initIntegration(
|
|
278
|
-
targetDir: string,
|
|
279
|
-
integrationsPath?: string,
|
|
280
|
-
): Promise<void> {
|
|
281
|
-
await validateIntegrationSetup(targetDir)
|
|
282
|
-
await updateIntegrationInfo(targetDir, integrationsPath)
|
|
283
|
-
await compileIntegration(targetDir, integrationsPath)
|
|
284
|
-
|
|
285
|
-
console.log(`
|
|
286
|
-
Integration initialized successfully!
|
|
287
|
-
|
|
288
|
-
Files created:
|
|
289
|
-
${INFO_FILE} - Integration metadata (edit this to customize)
|
|
290
|
-
${INTEGRATION_DIR}/${ASSETS_DIR}/ - Integration asset files
|
|
291
|
-
${COMPILED_FILE} - Compiled integration (distribute this)
|
|
292
|
-
|
|
293
|
-
Next steps:
|
|
294
|
-
1. Edit ${INFO_FILE} to customize your integration metadata
|
|
295
|
-
2. Run 'tanstack integration compile' to rebuild after changes
|
|
296
|
-
3. Share ${COMPILED_FILE} or host it publicly
|
|
297
|
-
`)
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Load a remote integration from a URL
|
|
302
|
-
*/
|
|
303
|
-
export async function loadRemoteIntegration(url: string): Promise<IntegrationCompiled> {
|
|
304
|
-
const response = await fetch(url)
|
|
305
|
-
if (!response.ok) {
|
|
306
|
-
throw new Error(`Failed to fetch integration from ${url}: ${response.statusText}`)
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const jsonContent = await response.json()
|
|
310
|
-
|
|
311
|
-
const result = IntegrationCompiledSchema.safeParse(jsonContent)
|
|
312
|
-
if (!result.success) {
|
|
313
|
-
throw new Error(`Invalid integration at ${url}: ${result.error.message}`)
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const integration = result.data
|
|
317
|
-
// Use the URL as the ID if not set
|
|
318
|
-
if (!integration.id) {
|
|
319
|
-
integration.id = url
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return integration
|
|
323
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { createPackageAdditions } from './shared.js'
|
|
3
|
-
|
|
4
|
-
describe('createPackageAdditions', () => {
|
|
5
|
-
it('should return empty object when packages are identical', () => {
|
|
6
|
-
const original = {
|
|
7
|
-
dependencies: { react: '^18.0.0' },
|
|
8
|
-
devDependencies: { typescript: '^5.0.0' },
|
|
9
|
-
}
|
|
10
|
-
const current = {
|
|
11
|
-
dependencies: { react: '^18.0.0' },
|
|
12
|
-
devDependencies: { typescript: '^5.0.0' },
|
|
13
|
-
}
|
|
14
|
-
expect(createPackageAdditions(original, current)).toEqual({})
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('should detect new dependencies', () => {
|
|
18
|
-
const original = {
|
|
19
|
-
dependencies: { react: '^18.0.0' },
|
|
20
|
-
}
|
|
21
|
-
const current = {
|
|
22
|
-
dependencies: { react: '^18.0.0', 'react-dom': '^18.0.0' },
|
|
23
|
-
}
|
|
24
|
-
expect(createPackageAdditions(original, current)).toEqual({
|
|
25
|
-
dependencies: { 'react-dom': '^18.0.0' },
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('should detect updated dependency versions', () => {
|
|
30
|
-
const original = {
|
|
31
|
-
dependencies: { react: '^18.0.0' },
|
|
32
|
-
}
|
|
33
|
-
const current = {
|
|
34
|
-
dependencies: { react: '^19.0.0' },
|
|
35
|
-
}
|
|
36
|
-
expect(createPackageAdditions(original, current)).toEqual({
|
|
37
|
-
dependencies: { react: '^19.0.0' },
|
|
38
|
-
})
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('should detect new devDependencies', () => {
|
|
42
|
-
const original = {
|
|
43
|
-
devDependencies: { typescript: '^5.0.0' },
|
|
44
|
-
}
|
|
45
|
-
const current = {
|
|
46
|
-
devDependencies: { typescript: '^5.0.0', vitest: '^1.0.0' },
|
|
47
|
-
}
|
|
48
|
-
expect(createPackageAdditions(original, current)).toEqual({
|
|
49
|
-
devDependencies: { vitest: '^1.0.0' },
|
|
50
|
-
})
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('should detect new scripts', () => {
|
|
54
|
-
const original = {
|
|
55
|
-
scripts: { dev: 'vinxi dev' },
|
|
56
|
-
}
|
|
57
|
-
const current = {
|
|
58
|
-
scripts: { dev: 'vinxi dev', test: 'vitest' },
|
|
59
|
-
}
|
|
60
|
-
expect(createPackageAdditions(original, current)).toEqual({
|
|
61
|
-
scripts: { test: 'vitest' },
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('should detect updated scripts', () => {
|
|
66
|
-
const original = {
|
|
67
|
-
scripts: { dev: 'vinxi dev' },
|
|
68
|
-
}
|
|
69
|
-
const current = {
|
|
70
|
-
scripts: { dev: 'vite dev' },
|
|
71
|
-
}
|
|
72
|
-
expect(createPackageAdditions(original, current)).toEqual({
|
|
73
|
-
scripts: { dev: 'vite dev' },
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('should handle missing sections in original', () => {
|
|
78
|
-
const original = {}
|
|
79
|
-
const current = {
|
|
80
|
-
dependencies: { react: '^18.0.0' },
|
|
81
|
-
devDependencies: { typescript: '^5.0.0' },
|
|
82
|
-
scripts: { dev: 'vite' },
|
|
83
|
-
}
|
|
84
|
-
expect(createPackageAdditions(original, current)).toEqual({
|
|
85
|
-
dependencies: { react: '^18.0.0' },
|
|
86
|
-
devDependencies: { typescript: '^5.0.0' },
|
|
87
|
-
scripts: { dev: 'vite' },
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('should handle missing sections in current', () => {
|
|
92
|
-
const original = {
|
|
93
|
-
dependencies: { react: '^18.0.0' },
|
|
94
|
-
}
|
|
95
|
-
const current = {}
|
|
96
|
-
expect(createPackageAdditions(original, current)).toEqual({})
|
|
97
|
-
})
|
|
98
|
-
})
|