forked from nrwl/nx
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(angular): importPath migration to fix broken paths (nrwl#6902)
Fixes broken importPaths and package.json names due to incorrect logic that has already been fixed ISSUES CLOSED: nrwl#6648
- Loading branch information
1 parent
ded0692
commit 7bfe4f3
Showing
3 changed files
with
231 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
85 changes: 85 additions & 0 deletions
85
packages/angular/src/migrations/update-12-9-0/update-invalid-import-paths.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import type { Tree } from '@nrwl/devkit'; | ||
import { updateJson, joinPathFragments, readJson } from '@nrwl/devkit'; | ||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; | ||
|
||
import libGenerator from '../../generators/library/library'; | ||
import updateInvalidImportPaths from './update-invalid-import-paths'; | ||
|
||
describe('Migration to fix invalid import paths in affected workspaces', () => { | ||
let tree: Tree; | ||
|
||
beforeEach(async () => { | ||
tree = createTreeWithEmptyWorkspace(); | ||
|
||
// set up some libs | ||
|
||
await libGenerator(tree, { | ||
name: 'buildable1', | ||
buildable: true, | ||
directory: 'dir1', | ||
}); | ||
|
||
await libGenerator(tree, { | ||
name: 'buildable2', | ||
buildable: true, | ||
directory: 'dir1', | ||
}); | ||
|
||
await libGenerator(tree, { | ||
name: 'publishable1', | ||
publishable: true, | ||
directory: 'dir1', | ||
importPath: '@proj/publishable1', | ||
}); | ||
|
||
await libGenerator(tree, { | ||
name: 'publishable2', | ||
publishable: true, | ||
directory: 'dir1', | ||
importPath: '@proj/publishable2', | ||
}); | ||
|
||
// break one of each kind | ||
updateJson( | ||
tree, | ||
joinPathFragments('libs/dir1/buildable1', 'package.json'), | ||
(pkgJson) => { | ||
pkgJson.name = '@proj/dir1-buildable1'; | ||
return pkgJson; | ||
} | ||
); | ||
|
||
updateJson(tree, 'tsconfig.base.json', (tsconfig) => { | ||
const srcPath = tsconfig['@proj/publishable2']; | ||
tsconfig['@proj/publishable2'] = undefined; | ||
|
||
tsconfig['@proj/dir1/publishable2'] = srcPath; | ||
|
||
return tsconfig; | ||
}); | ||
}); | ||
|
||
it('should fix the invalid libraries', async () => { | ||
// ACT | ||
await updateInvalidImportPaths(tree); | ||
|
||
// ASSERT | ||
const fixedBuildable = readJson( | ||
tree, | ||
joinPathFragments('libs/dir1/buildable1', 'package.json') | ||
); | ||
|
||
const { compilerOptions } = readJson<{ | ||
compilerOptions: { paths: Record<string, string[]> }; | ||
}>(tree, 'tsconfig.base.json'); | ||
const { paths: tsConfigPaths } = compilerOptions; | ||
const fixedPublishable = Boolean(tsConfigPaths['@proj/publishable2']); | ||
const brokenPublishableShouldntExist = !Boolean( | ||
tsConfigPaths['@proj/publishable2'] | ||
); | ||
|
||
expect(fixedBuildable.name).toEqual('@proj/dir1/buildable1'); | ||
expect(fixedPublishable).toBeTruthy(); | ||
expect(brokenPublishableShouldntExist).toBeFalsy(); | ||
}); | ||
}); |
140 changes: 140 additions & 0 deletions
140
packages/angular/src/migrations/update-12-9-0/update-invalid-import-paths.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import type { | ||
NxJsonProjectConfiguration, | ||
ProjectConfiguration, | ||
Tree, | ||
} from '@nrwl/devkit'; | ||
import { | ||
formatFiles, | ||
getProjects, | ||
readJson, | ||
joinPathFragments, | ||
updateJson, | ||
logger, | ||
} from '@nrwl/devkit'; | ||
|
||
type AffectedLib = ProjectConfiguration & NxJsonProjectConfiguration; | ||
type InvalidLibs = { | ||
buildableLibs: AffectedLib[]; | ||
publishableLibs: AffectedLib[]; | ||
}; | ||
|
||
export default async function (tree: Tree) { | ||
const possibleAffectedLibs = findBuildableAndPublishableLibs(tree); | ||
const invalidLibs = findInvalidLibs(tree, possibleAffectedLibs); | ||
fixLibs(tree, invalidLibs); | ||
|
||
await formatFiles(tree); | ||
} | ||
|
||
export function findBuildableAndPublishableLibs(tree: Tree): InvalidLibs { | ||
const projects = getProjects(tree); | ||
const buildableLibs: AffectedLib[] = []; | ||
const publishableLibs: AffectedLib[] = []; | ||
|
||
for (const [name, project] of projects) { | ||
for (const target of Object.values(project.targets || {})) { | ||
if (target.executor === '@nrwl/angular:package') { | ||
publishableLibs.push(project); | ||
} else if (target.executor === '@nrwl/angular:ng-packagr-lite') { | ||
buildableLibs.push(project); | ||
} | ||
} | ||
} | ||
|
||
return { buildableLibs, publishableLibs }; | ||
} | ||
|
||
export function findInvalidLibs(tree: Tree, libs: InvalidLibs): InvalidLibs { | ||
const { compilerOptions } = readJson(tree, 'tsconfig.base.json'); | ||
const { paths: tsConfigPaths } = compilerOptions; | ||
|
||
const invalidBuildableLibs = libs.buildableLibs.filter((lib) => | ||
checkInvalidLib(tree, lib, tsConfigPaths) | ||
); | ||
const invalidPublishableLibs = libs.publishableLibs.filter((lib) => | ||
checkInvalidLib(tree, lib, tsConfigPaths) | ||
); | ||
return { | ||
buildableLibs: invalidBuildableLibs, | ||
publishableLibs: invalidPublishableLibs, | ||
}; | ||
} | ||
|
||
function checkInvalidLib( | ||
tree: Tree, | ||
lib: AffectedLib, | ||
tsConfigPaths: Record<string, string> | ||
) { | ||
const { name } = readJson(tree, joinPathFragments(lib.root, 'package.json')); | ||
return !tsConfigPaths[name]; | ||
} | ||
|
||
function fixLibs(tree: Tree, { buildableLibs, publishableLibs }: InvalidLibs) { | ||
const { compilerOptions } = readJson(tree, 'tsconfig.base.json'); | ||
const { paths: tsConfigPaths } = compilerOptions; | ||
|
||
buildableLibs.map((lib) => fixBuildableLib(tree, lib, tsConfigPaths)); | ||
publishableLibs.map((lib) => fixPublishableLib(tree, lib, tsConfigPaths)); | ||
} | ||
|
||
function fixBuildableLib( | ||
tree: Tree, | ||
lib: AffectedLib, | ||
tsConfigPaths: Record<string, string> | ||
) { | ||
const srcRoot = joinPathFragments(lib.sourceRoot, 'index.ts'); | ||
|
||
for (const [validPackageName, tsLibSrcRoot] of Object.entries( | ||
tsConfigPaths | ||
)) { | ||
if (tsLibSrcRoot[0] === srcRoot) { | ||
updateJson( | ||
tree, | ||
joinPathFragments(lib.root, 'package.json'), | ||
(pkgJson) => { | ||
pkgJson.name = validPackageName; | ||
|
||
return pkgJson; | ||
} | ||
); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
function fixPublishableLib( | ||
tree: Tree, | ||
lib: AffectedLib, | ||
tsConfigPaths: Record<string, string> | ||
) { | ||
const srcRoot = joinPathFragments(lib.sourceRoot, 'index.ts'); | ||
const { name: pkgName } = readJson( | ||
tree, | ||
joinPathFragments(lib.root, 'package.json') | ||
); | ||
|
||
const pkgNameParts = pkgName.split('/'); | ||
if (Array.isArray(pkgNameParts) && pkgNameParts.length > 2) { | ||
logger.warn( | ||
`Your publishable package ${pkgName} is an invalid NPM Package name. Please ensure it only contains one '/'.` | ||
); | ||
logger.warn( | ||
`The affected package.json is at '${joinPathFragments( | ||
lib.root, | ||
'package.json' | ||
)}'` | ||
); | ||
} | ||
|
||
for (const [invalidPathKey, tsLibSrcRoot] of Object.entries(tsConfigPaths)) { | ||
if (tsLibSrcRoot[0] === srcRoot) { | ||
updateJson(tree, 'tsconfig.base.json', (tsconfig) => { | ||
tsconfig.compilerOptions.paths[invalidPathKey] = undefined; | ||
tsconfig.compilerOptions.paths[pkgName] = tsLibSrcRoot; | ||
|
||
return tsconfig; | ||
}); | ||
break; | ||
} | ||
} | ||
} |