@@ -81,7 +81,7 @@ class ExecutorToPluginMigrator<T> {
81
81
for ( const targetName of this . #targetAndProjectsToMigrate. keys ( ) ) {
82
82
this . #migrateTarget( targetName ) ;
83
83
}
84
- this . #addPlugins( ) ;
84
+ await this . #addPlugins( ) ;
85
85
}
86
86
return this . #targetAndProjectsToMigrate;
87
87
}
@@ -159,7 +159,39 @@ class ExecutorToPluginMigrator<T> {
159
159
return `${ projectFromGraph . data . root } /**/*` ;
160
160
}
161
161
162
- #addPlugins( ) {
162
+ async #pluginRequiresIncludes(
163
+ targetName : string ,
164
+ plugin : ExpandedPluginConfiguration < T >
165
+ ) {
166
+ const loadedPlugin = new LoadedNxPlugin (
167
+ {
168
+ createNodes : this . #createNodes,
169
+ name : this . #pluginPath,
170
+ } ,
171
+ plugin
172
+ ) ;
173
+
174
+ const originalResults = this . #createNodesResultsForTargets. get ( targetName ) ;
175
+
176
+ let resultsWithIncludes : ConfigurationResult ;
177
+ try {
178
+ resultsWithIncludes = await retrieveProjectConfigurations (
179
+ [ loadedPlugin ] ,
180
+ this . tree . root ,
181
+ this . #nxJson
182
+ ) ;
183
+ } catch ( e ) {
184
+ if ( e instanceof ProjectConfigurationsError ) {
185
+ resultsWithIncludes = e . partialProjectConfigurationsResult ;
186
+ } else {
187
+ throw e ;
188
+ }
189
+ }
190
+
191
+ return ! deepEqual ( originalResults , resultsWithIncludes ) ;
192
+ }
193
+
194
+ async #addPlugins( ) {
163
195
for ( const [ targetName , plugin ] of this . #pluginToAddForTarget. entries ( ) ) {
164
196
const pluginOptions = this . #pluginOptionsBuilder( targetName ) ;
165
197
@@ -183,42 +215,25 @@ class ExecutorToPluginMigrator<T> {
183
215
) as ExpandedPluginConfiguration < T > ;
184
216
185
217
if ( existingPlugin ?. include ) {
186
- for ( const pluginIncludes of existingPlugin . include ) {
187
- for ( const projectPath of plugin . include ) {
188
- if ( ! minimatch ( projectPath , pluginIncludes , { dot : true } ) ) {
189
- existingPlugin . include . push ( projectPath ) ;
190
- }
191
- }
192
- }
193
-
194
- const allConfigFilesAreIncluded = this . #configFiles. every (
195
- ( configFile ) => {
196
- for ( const includePattern of existingPlugin . include ) {
197
- if ( minimatch ( configFile , includePattern , { dot : true } ) ) {
198
- return true ;
199
- }
200
- }
201
- return false ;
202
- }
218
+ // Add to the existing plugin includes
219
+ existingPlugin . include = existingPlugin . include . concat (
220
+ // Any include that is in the new plugin's include list
221
+ plugin . include . filter (
222
+ ( projectPath ) =>
223
+ // And is not already covered by the existing plugin's include list
224
+ ! existingPlugin . include . some ( ( pluginIncludes ) =>
225
+ minimatch ( projectPath , pluginIncludes , { dot : true } )
226
+ )
227
+ )
203
228
) ;
204
229
205
- if ( allConfigFilesAreIncluded ) {
206
- existingPlugin . include = undefined ;
230
+ if ( ! ( await this . #pluginRequiresIncludes ( targetName , existingPlugin ) ) ) {
231
+ delete existingPlugin . include ;
207
232
}
208
233
}
209
234
210
235
if ( ! existingPlugin ) {
211
- const allConfigFilesAreIncluded = this . #configFiles. every (
212
- ( configFile ) => {
213
- for ( const includePattern of plugin . include ) {
214
- if ( minimatch ( configFile , includePattern , { dot : true } ) ) {
215
- return true ;
216
- }
217
- }
218
- return false ;
219
- }
220
- ) ;
221
- if ( allConfigFilesAreIncluded ) {
236
+ if ( ! ( await this . #pluginRequiresIncludes( targetName , plugin ) ) ) {
222
237
plugin . include = undefined ;
223
238
}
224
239
this . #nxJson. plugins . push ( plugin ) ;
@@ -274,11 +289,17 @@ class ExecutorToPluginMigrator<T> {
274
289
}
275
290
276
291
#getCreatedTargetForProjectRoot( targetName : string , projectRoot : string ) {
277
- const createdProject = Object . entries (
292
+ const entry = Object . entries (
278
293
this . #createNodesResultsForTargets. get ( targetName ) ?. projects ?? { }
279
- ) . find ( ( [ root ] ) => root === projectRoot ) [ 1 ] ;
294
+ ) . find ( ( [ root ] ) => root === projectRoot ) ;
295
+ if ( ! entry ) {
296
+ throw new Error (
297
+ `The nx plugin did not find a project inside ${ projectRoot } . File an issue at https://github.com/nrwl/nx with information about your project structure.`
298
+ ) ;
299
+ }
300
+ const createdProject = entry [ 1 ] ;
280
301
const createdTarget : TargetConfiguration < RunCommandsOptions > =
281
- createdProject . targets [ targetName ] ;
302
+ structuredClone ( createdProject . targets [ targetName ] ) ;
282
303
delete createdTarget . command ;
283
304
delete createdTarget . options ?. cwd ;
284
305
@@ -346,3 +367,30 @@ export async function migrateExecutorToPlugin<T>(
346
367
) ;
347
368
return await migrator . run ( ) ;
348
369
}
370
+
371
+ // Checks if two objects are structurely equal, without caring
372
+ // about the order of the keys.
373
+ function deepEqual < T extends Object > ( a : T , b : T , logKey = '' ) : boolean {
374
+ const aKeys = Object . keys ( a ) ;
375
+ const bKeys = new Set ( Object . keys ( b ) ) ;
376
+
377
+ if ( aKeys . length !== bKeys . size ) {
378
+ return false ;
379
+ }
380
+
381
+ for ( const key of aKeys ) {
382
+ if ( ! bKeys . has ( key ) ) {
383
+ return false ;
384
+ }
385
+
386
+ if ( typeof a [ key ] === 'object' && typeof b [ key ] === 'object' ) {
387
+ if ( ! deepEqual ( a [ key ] , b [ key ] , logKey + '.' + key ) ) {
388
+ return false ;
389
+ }
390
+ } else if ( a [ key ] !== b [ key ] ) {
391
+ return false ;
392
+ }
393
+ }
394
+
395
+ return true ;
396
+ }
0 commit comments