@@ -8,8 +8,11 @@ import { registryItemTypeSchema } from "@/src/registry/schema"
88import { isUniversalRegistryItem } from "@/src/registry/utils"
99import { getTemplateForFramework } from "@/src/templates/index"
1010import { addComponents } from "@/src/utils/add-components"
11+ import { dryRunComponents } from "@/src/utils/dry-run"
12+ import { formatDryRunResult } from "@/src/utils/dry-run-formatter"
1113import { createProject } from "@/src/utils/create-project"
1214import { loadEnvFiles } from "@/src/utils/env-loader"
15+ import { spinner } from "@/src/utils/spinner"
1316import * as ERRORS from "@/src/utils/errors"
1417import { createConfig , getConfig } from "@/src/utils/get-config"
1518import { getProjectInfo } from "@/src/utils/get-project-info"
@@ -35,6 +38,9 @@ export const addOptionsSchema = z.object({
3538 all : z . boolean ( ) ,
3639 path : z . string ( ) . optional ( ) ,
3740 silent : z . boolean ( ) ,
41+ dryRun : z . boolean ( ) ,
42+ diff : z . string ( ) . optional ( ) ,
43+ view : z . string ( ) . optional ( ) ,
3844} )
3945
4046export const add = new Command ( )
@@ -51,6 +57,9 @@ export const add = new Command()
5157 . option ( "-a, --all" , "add all available components" , false )
5258 . option ( "-p, --path <path>" , "the path to add the component to." )
5359 . option ( "-s, --silent" , "mute output." , false )
60+ . option ( "--dry-run" , "preview changes without writing files." , false )
61+ . option ( "--diff <path>" , "show diff for a file." )
62+ . option ( "--view <path>" , "show file contents." )
5463 . action ( async ( components , opts ) => {
5564 try {
5665 const options = addOptionsSchema . parse ( {
@@ -94,13 +103,15 @@ export const add = new Command()
94103 itemType !== "registry:style" &&
95104 itemType !== "registry:base"
96105
97- if ( isUniversalRegistryItem ( registryItem ) ) {
106+ const isDryRun = options . dryRun || options . diff || options . view
107+
108+ if ( isUniversalRegistryItem ( registryItem ) && ! isDryRun ) {
98109 await addComponents ( components , initialConfig , options )
99110 return
100111 }
101-
102112 if (
103113 ! options . yes &&
114+ ! isDryRun &&
104115 ( itemType === "registry:style" || itemType === "registry:theme" )
105116 ) {
106117 logger . break ( )
@@ -256,6 +267,30 @@ export const add = new Command()
256267 )
257268 config = updatedConfig
258269
270+ // Dry-run mode: preview changes without writing files.
271+ // --diff and --view imply --dry-run.
272+ if ( options . dryRun || options . diff || options . view ) {
273+ const dryRunSpinner = spinner ( "Resolving items." , {
274+ silent : options . silent ,
275+ } ) . start ( )
276+ const dryRunResult = await dryRunComponents (
277+ options . components ,
278+ config ,
279+ {
280+ overwrite : options . overwrite ,
281+ }
282+ )
283+ dryRunSpinner . stop ( )
284+
285+ logger . log (
286+ formatDryRunResult ( dryRunResult , options . components , {
287+ diff : options . diff ,
288+ view : options . view ,
289+ } )
290+ )
291+ return
292+ }
293+
259294 if ( ! initHasRun ) {
260295 await addComponents ( options . components , config , options )
261296 }
0 commit comments