@@ -28,6 +28,11 @@ impl DevMode {
2828 matches ! ( self , Self :: Exclude | Self :: Include )
2929 }
3030
31+ /// Returns `true` if the specification only includes development dependencies.
32+ pub fn only ( & self ) -> bool {
33+ matches ! ( self , Self :: Only )
34+ }
35+
3136 /// Returns the flag that was used to request development dependencies.
3237 pub fn as_flag ( & self ) -> & ' static str {
3338 match self {
@@ -38,7 +43,7 @@ impl DevMode {
3843 }
3944}
4045
41- #[ derive( Debug , Clone ) ]
46+ #[ derive( Default , Debug , Clone ) ]
4247pub struct DevGroupsSpecification {
4348 /// Legacy option for `dependency-group.dev` and `tool.uv.dev-dependencies`.
4449 ///
@@ -48,15 +53,13 @@ pub struct DevGroupsSpecification {
4853 /// The groups to include.
4954 ///
5055 /// Requested via the `--group` and `--only-group` options.
51- groups : GroupsSpecification ,
56+ groups : Option < GroupsSpecification > ,
5257}
5358
5459#[ derive( Debug , Clone ) ]
5560pub enum GroupsSpecification {
5661 /// Include dependencies from the specified groups.
5762 Include ( Vec < GroupName > ) ,
58- /// Do not include dependencies from groups.
59- Exclude ,
6063 /// Only include dependencies from the specified groups, exclude all other dependencies.
6164 Only ( Vec < GroupName > ) ,
6265}
@@ -65,20 +68,23 @@ impl GroupsSpecification {
6568 /// Returns an [`Iterator`] over the group names to include.
6669 pub fn iter ( & self ) -> impl Iterator < Item = & GroupName > {
6770 match self {
68- Self :: Exclude => Either :: Left ( std:: iter:: empty ( ) ) ,
69- Self :: Include ( groups) | Self :: Only ( groups) => Either :: Right ( groups. iter ( ) ) ,
71+ Self :: Include ( groups) | Self :: Only ( groups) => groups. iter ( ) ,
7072 }
7173 }
7274
7375 /// Returns `true` if the specification allows for production dependencies.
7476 pub fn prod ( & self ) -> bool {
75- matches ! ( self , Self :: Exclude | Self :: Include ( _) )
77+ matches ! ( self , Self :: Include ( _) )
78+ }
79+
80+ /// Returns `true` if the specification is limited to a select set of groups.
81+ pub fn only ( & self ) -> bool {
82+ matches ! ( self , Self :: Only ( _) )
7683 }
7784
7885 /// Returns the option that was used to request the groups, if any.
7986 pub fn as_flag ( & self ) -> Option < Cow < ' _ , str > > {
8087 match self {
81- Self :: Exclude => None ,
8288 Self :: Include ( groups) => match groups. as_slice ( ) {
8389 [ ] => None ,
8490 [ group] => Some ( Cow :: Owned ( format ! ( "--group {group}" ) ) ) ,
@@ -96,9 +102,13 @@ impl GroupsSpecification {
96102impl DevGroupsSpecification {
97103 /// Returns an [`Iterator`] over the group names to include.
98104 pub fn iter ( & self ) -> impl Iterator < Item = & GroupName > {
99- match self . dev {
100- None => Either :: Left ( self . groups . iter ( ) ) ,
101- Some ( ref dev_mode) => Either :: Right ( self . groups . iter ( ) . chain ( dev_mode. iter ( ) ) ) ,
105+ match ( self . dev . as_ref ( ) , self . groups . as_ref ( ) ) {
106+ ( None , None ) => Either :: Left ( Either :: Left ( std:: iter:: empty ( ) ) ) ,
107+ ( Some ( dev) , None ) => Either :: Left ( Either :: Right ( dev. iter ( ) ) ) ,
108+ ( None , Some ( groups) ) => Either :: Right ( Either :: Left ( groups. iter ( ) ) ) ,
109+ ( Some ( dev) , Some ( groups) ) => {
110+ Either :: Right ( Either :: Right ( dev. iter ( ) . chain ( groups. iter ( ) ) ) )
111+ }
102112 }
103113 }
104114
@@ -110,7 +120,7 @@ impl DevGroupsSpecification {
110120 group : Vec < GroupName > ,
111121 only_group : Vec < GroupName > ,
112122 ) -> Self {
113- let dev_mode = if only_dev {
123+ let dev = if only_dev {
114124 Some ( DevMode :: Only )
115125 } else if no_dev {
116126 Some ( DevMode :: Exclude )
@@ -121,70 +131,120 @@ impl DevGroupsSpecification {
121131 } ;
122132
123133 let groups = if !group. is_empty ( ) {
124- if matches ! ( dev_mode , Some ( DevMode :: Only ) ) {
134+ if matches ! ( dev , Some ( DevMode :: Only ) ) {
125135 unreachable ! ( "cannot specify both `--only-dev` and `--group`" )
126136 } ;
127- GroupsSpecification :: Include ( group)
137+ Some ( GroupsSpecification :: Include ( group) )
128138 } else if !only_group. is_empty ( ) {
129- if matches ! ( dev_mode , Some ( DevMode :: Include ) ) {
139+ if matches ! ( dev , Some ( DevMode :: Include ) ) {
130140 unreachable ! ( "cannot specify both `--dev` and `--only-group`" )
131141 } ;
132- GroupsSpecification :: Only ( only_group)
142+ Some ( GroupsSpecification :: Only ( only_group) )
133143 } else {
134- GroupsSpecification :: Exclude
144+ None
135145 } ;
136146
137- Self {
138- dev : dev_mode,
139- groups,
140- }
147+ Self { dev, groups }
141148 }
142149
143150 /// Return a new [`DevGroupsSpecification`] with development dependencies included by default.
144151 ///
145152 /// This is appropriate in projects, where the `dev` group is synced by default.
146153 #[ must_use]
147- pub fn with_default_dev ( self ) -> Self {
148- match self . dev {
149- Some ( _) => self ,
150- None => match self . groups {
151- // Only include the default `dev` group if `--only-group` wasn't used
152- GroupsSpecification :: Only ( _) => self ,
153- GroupsSpecification :: Exclude | GroupsSpecification :: Include ( _) => Self {
154- dev : Some ( DevMode :: Include ) ,
155- ..self
156- } ,
157- } ,
154+ pub fn with_defaults ( self , defaults : Vec < GroupName > ) -> DevGroupsManifest {
155+ DevGroupsManifest {
156+ spec : self ,
157+ defaults,
158158 }
159159 }
160160
161161 /// Returns `true` if the specification allows for production dependencies.
162162 pub fn prod ( & self ) -> bool {
163- ( self . dev . is_none ( ) || self . dev . as_ref ( ) . is_some_and ( DevMode :: prod) ) && self . groups . prod ( )
163+ self . dev . as_ref ( ) . map_or ( true , DevMode :: prod)
164+ && self . groups . as_ref ( ) . map_or ( true , GroupsSpecification :: prod)
164165 }
165166
166- /// Returns the flag that was used to request development dependencies.
167+ /// Returns `true` if the specification is limited to a select set of groups.
168+ pub fn only ( & self ) -> bool {
169+ self . dev . as_ref ( ) . is_some_and ( DevMode :: only)
170+ || self . groups . as_ref ( ) . is_some_and ( GroupsSpecification :: only)
171+ }
172+
173+ /// Returns the flag that was used to request development dependencies, if specified.
167174 pub fn dev_mode ( & self ) -> Option < & DevMode > {
168175 self . dev . as_ref ( )
169176 }
170177
171- /// Returns the list of groups to include.
172- pub fn groups ( & self ) -> & GroupsSpecification {
173- & self . groups
178+ /// Returns the list of groups to include, if specified .
179+ pub fn groups ( & self ) -> Option < & GroupsSpecification > {
180+ self . groups . as_ref ( )
174181 }
175182}
176183
177184impl From < DevMode > for DevGroupsSpecification {
178185 fn from ( dev : DevMode ) -> Self {
179186 Self {
180187 dev : Some ( dev) ,
181- groups : GroupsSpecification :: Exclude ,
188+ groups : None ,
182189 }
183190 }
184191}
185192
186193impl From < GroupsSpecification > for DevGroupsSpecification {
187194 fn from ( groups : GroupsSpecification ) -> Self {
188- Self { dev : None , groups }
195+ Self {
196+ dev : None ,
197+ groups : Some ( groups) ,
198+ }
199+ }
200+ }
201+
202+ /// The manifest of `dependency-groups` to include, taking into account the user-provided
203+ /// [`DevGroupsSpecification`] and the project-specific default groups.
204+ #[ derive( Debug , Clone ) ]
205+ pub struct DevGroupsManifest {
206+ /// The specification for the development dependencies.
207+ pub ( crate ) spec : DevGroupsSpecification ,
208+ /// The default groups to include.
209+ pub ( crate ) defaults : Vec < GroupName > ,
210+ }
211+
212+ impl DevGroupsManifest {
213+ /// Returns a new [`DevGroupsManifest`] with the given default groups.
214+ pub fn from_defaults ( defaults : Vec < GroupName > ) -> Self {
215+ Self {
216+ spec : DevGroupsSpecification :: default ( ) ,
217+ defaults,
218+ }
219+ }
220+
221+ /// Returns a new [`DevGroupsManifest`] with the given specification.
222+ pub fn from_spec ( spec : DevGroupsSpecification ) -> Self {
223+ Self {
224+ spec,
225+ defaults : Vec :: new ( ) ,
226+ }
227+ }
228+
229+ /// Returns an [`Iterator`] over the group names to include.
230+ pub fn iter ( & self ) -> impl Iterator < Item = & GroupName > {
231+ if self . spec . only ( ) {
232+ Either :: Left ( self . spec . iter ( ) )
233+ } else {
234+ Either :: Right (
235+ self . spec
236+ . iter ( )
237+ . chain ( self . defaults . iter ( ) . filter ( |default| {
238+ // If `--no-dev` was provided, exclude the `dev` group from the list of defaults.
239+ !matches ! ( self . spec. dev_mode( ) , Some ( DevMode :: Exclude ) )
240+ || * default != & * DEV_DEPENDENCIES
241+ } ) ) ,
242+ )
243+ }
244+ }
245+
246+ /// Returns `true` if the specification allows for production dependencies.
247+ pub fn prod ( & self ) -> bool {
248+ self . spec . prod ( )
189249 }
190250}
0 commit comments