@@ -10,6 +10,7 @@ import {
10
10
type ProjectGraphProjectNode ,
11
11
type Tree ,
12
12
} from '@nx/devkit' ;
13
+ import ignore from 'ignore' ;
13
14
import { applyEdits , modify } from 'jsonc-parser' ;
14
15
import { dirname , normalize , relative } from 'node:path/posix' ;
15
16
import type { SyncGeneratorResult } from 'nx/src/utils/sync-generators' ;
@@ -26,6 +27,11 @@ interface Tsconfig {
26
27
rootDir ?: string ;
27
28
outDir ?: string ;
28
29
} ;
30
+ nx ?: {
31
+ sync ?: {
32
+ ignoredReferences ?: string [ ] ;
33
+ } ;
34
+ } ;
29
35
}
30
36
31
37
const COMMON_RUNTIME_TS_CONFIG_FILE_NAMES = [
@@ -37,6 +43,12 @@ const COMMON_RUNTIME_TS_CONFIG_FILE_NAMES = [
37
43
'tsconfig.runtime.json' ,
38
44
] ;
39
45
46
+ type GeneratorOptions = {
47
+ runtimeTsConfigFileNames ?: string [ ] ;
48
+ } ;
49
+
50
+ type NormalizedGeneratorOptions = Required < GeneratorOptions > ;
51
+
40
52
export async function syncGenerator ( tree : Tree ) : Promise < SyncGeneratorResult > {
41
53
// Ensure that the plugin has been wired up in nx.json
42
54
const nxJson = readNxJson ( tree ) ;
@@ -151,23 +163,27 @@ export async function syncGenerator(tree: Tree): Promise<SyncGeneratorResult> {
151
163
}
152
164
}
153
165
154
- const runtimeTsConfigFileNames =
155
- ( nxJson . sync ?. generatorOptions ?. [ '@nx/js:typescript-sync' ]
156
- ?. runtimeTsConfigFileNames as string [ ] ) ??
157
- COMMON_RUNTIME_TS_CONFIG_FILE_NAMES ;
166
+ const userOptions = nxJson . sync ?. generatorOptions ?. [
167
+ '@nx/js:typescript-sync'
168
+ ] as GeneratorOptions | undefined ;
169
+ const { runtimeTsConfigFileNames } : NormalizedGeneratorOptions = {
170
+ runtimeTsConfigFileNames :
171
+ userOptions ?. runtimeTsConfigFileNames ??
172
+ COMMON_RUNTIME_TS_CONFIG_FILE_NAMES ,
173
+ } ;
158
174
159
175
const collectedDependencies = new Map < string , ProjectGraphProjectNode [ ] > ( ) ;
160
- for ( const [ name , data ] of Object . entries ( projectGraph . dependencies ) ) {
176
+ for ( const [ projectName , data ] of Object . entries ( projectGraph . dependencies ) ) {
161
177
if (
162
- ! projectGraph . nodes [ name ] ||
163
- projectGraph . nodes [ name ] . data . root === '.' ||
178
+ ! projectGraph . nodes [ projectName ] ||
179
+ projectGraph . nodes [ projectName ] . data . root === '.' ||
164
180
! data . length
165
181
) {
166
182
continue ;
167
183
}
168
184
169
185
// Get the source project nodes for the source and target
170
- const sourceProjectNode = projectGraph . nodes [ name ] ;
186
+ const sourceProjectNode = projectGraph . nodes [ projectName ] ;
171
187
172
188
// Find the relevant tsconfig file for the source project
173
189
const sourceProjectTsconfigPath = joinPathFragments (
@@ -179,7 +195,7 @@ export async function syncGenerator(tree: Tree): Promise<SyncGeneratorResult> {
179
195
) {
180
196
if ( process . env . NX_VERBOSE_LOGGING === 'true' ) {
181
197
logger . warn (
182
- `Skipping project "${ name } " as there is no tsconfig.json file found in the project root "${ sourceProjectNode . data . root } ".`
198
+ `Skipping project "${ projectName } " as there is no tsconfig.json file found in the project root "${ sourceProjectNode . data . root } ".`
183
199
) ;
184
200
}
185
201
continue ;
@@ -188,7 +204,7 @@ export async function syncGenerator(tree: Tree): Promise<SyncGeneratorResult> {
188
204
// Collect the dependencies of the source project
189
205
const dependencies = collectProjectDependencies (
190
206
tree ,
191
- name ,
207
+ projectName ,
192
208
projectGraph ,
193
209
collectedDependencies
194
210
) ;
@@ -299,14 +315,23 @@ function updateTsConfigReferences(
299
315
tsConfigPath
300
316
) ;
301
317
const tsConfig = parseJson < Tsconfig > ( stringifiedJsonContents ) ;
318
+ const ignoredReferences = new Set ( tsConfig . nx ?. sync ?. ignoredReferences ?? [ ] ) ;
302
319
303
320
// We have at least one dependency so we can safely set it to an empty array if not already set
304
321
const references = [ ] ;
305
322
const originalReferencesSet = new Set ( ) ;
306
323
const newReferencesSet = new Set ( ) ;
324
+
307
325
for ( const ref of tsConfig . references ?? [ ] ) {
308
326
const normalizedPath = normalizeReferencePath ( ref . path ) ;
309
327
originalReferencesSet . add ( normalizedPath ) ;
328
+ if ( ignoredReferences . has ( ref . path ) ) {
329
+ // we keep the user-defined ignored references
330
+ references . push ( ref ) ;
331
+ newReferencesSet . add ( normalizedPath ) ;
332
+ continue ;
333
+ }
334
+
310
335
// reference path is relative to the tsconfig file
311
336
const resolvedRefPath = getTsConfigPathFromReferencePath (
312
337
tree ,
@@ -320,9 +345,10 @@ function updateTsConfigReferences(
320
345
resolvedRefPath ,
321
346
projectRoot ,
322
347
projectRoots
323
- )
348
+ ) ||
349
+ isProjectReferenceIgnored ( tree , resolvedRefPath )
324
350
) {
325
- // we keep all references within the current Nx project
351
+ // we keep all references within the current Nx project or that are ignored
326
352
references . push ( ref ) ;
327
353
newReferencesSet . add ( normalizedPath ) ;
328
354
}
@@ -511,6 +537,22 @@ function isProjectReferenceWithinNxProject(
511
537
return true ;
512
538
}
513
539
540
+ function isProjectReferenceIgnored (
541
+ tree : Tree ,
542
+ refTsConfigPath : string
543
+ ) : boolean {
544
+ const ig = ignore ( ) ;
545
+ if ( tree . exists ( '.gitignore' ) ) {
546
+ ig . add ( '.git' ) ;
547
+ ig . add ( tree . read ( '.gitignore' , 'utf-8' ) ) ;
548
+ }
549
+ if ( tree . exists ( '.nxignore' ) ) {
550
+ ig . add ( tree . read ( '.nxignore' , 'utf-8' ) ) ;
551
+ }
552
+
553
+ return ig . ignores ( refTsConfigPath ) ;
554
+ }
555
+
514
556
function getTsConfigDirName (
515
557
tree : Tree ,
516
558
rawTsconfigContentsCache : Map < string , string > ,
0 commit comments