cleanup(angular): add @angular-devkit/build-angular:ng-packagr builder migrator (#12682)
This commit is contained in:
parent
2f46797535
commit
f4288e6bc4
@ -1,7 +1,7 @@
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import {
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
writeJson,
|
||||
} from '@nrwl/devkit';
|
||||
|
||||
@ -1,34 +1,33 @@
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
formatFiles,
|
||||
installPackagesTask,
|
||||
readJson,
|
||||
readWorkspaceConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateWorkspaceConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import type { ProjectMigrator } from './migrators';
|
||||
import { AppMigrator, LibMigrator } from './migrators';
|
||||
import type { GeneratorOptions } from './schema';
|
||||
import { AppMigrator } from './utilities/app.migrator';
|
||||
import { getAllProjects } from './utilities/get-all-projects';
|
||||
import { LibMigrator } from './utilities/lib.migrator';
|
||||
import { normalizeOptions } from './utilities/normalize-options';
|
||||
import { ProjectMigrator } from './utilities/project.migrator';
|
||||
import { validateProjects } from './utilities/validate-projects';
|
||||
import {
|
||||
cleanupEsLintPackages,
|
||||
createNxJson,
|
||||
createRootKarmaConfig,
|
||||
createWorkspaceFiles,
|
||||
decorateAngularCli,
|
||||
getAllProjects,
|
||||
getWorkspaceCapabilities,
|
||||
normalizeOptions,
|
||||
updatePackageJson,
|
||||
updateRootEsLintConfig,
|
||||
updateRootTsConfig,
|
||||
updateWorkspaceConfigDefaults,
|
||||
validateProjects,
|
||||
validateWorkspace,
|
||||
} from './utilities/workspace';
|
||||
} from './utilities';
|
||||
|
||||
export async function migrateFromAngularCli(
|
||||
tree: Tree,
|
||||
|
||||
@ -0,0 +1,179 @@
|
||||
import type {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import {
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
|
||||
import { basename } from 'path';
|
||||
import { addBuildableLibrariesPostCssDependencies } from '../../../utils/dependencies';
|
||||
import type {
|
||||
Logger,
|
||||
ProjectMigrationInfo,
|
||||
ValidationError,
|
||||
ValidationResult,
|
||||
} from '../../utilities';
|
||||
import { arrayToString } from '../../utilities';
|
||||
import { BuilderMigrator } from './builder.migrator';
|
||||
|
||||
export class AngularDevkitNgPackagrMigrator extends BuilderMigrator {
|
||||
constructor(
|
||||
tree: Tree,
|
||||
project: ProjectMigrationInfo,
|
||||
projectConfig: ProjectConfiguration,
|
||||
logger: Logger
|
||||
) {
|
||||
super(
|
||||
tree,
|
||||
'@angular-devkit/build-angular:ng-packagr',
|
||||
project,
|
||||
projectConfig,
|
||||
logger
|
||||
);
|
||||
}
|
||||
|
||||
override migrate(): void {
|
||||
if (!this.targets.size) {
|
||||
this.logger.warn(
|
||||
`There is no target in the project configuration using the ${this.builderName} builder. This might not be an issue. ` +
|
||||
`Skipping updating the build configuration.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [name, target] of this.targets) {
|
||||
this.updateTargetConfiguration(name, target);
|
||||
this.updateNgPackageJson(name, target);
|
||||
this.updateTsConfigs(name, target);
|
||||
this.updateCacheableOperations([name]);
|
||||
addBuildableLibrariesPostCssDependencies(this.tree);
|
||||
}
|
||||
}
|
||||
|
||||
override validate(): ValidationResult {
|
||||
const errors: ValidationError[] = [];
|
||||
// TODO(leo): keeping restriction until the full refactor is done and we start
|
||||
// expanding what's supported.
|
||||
if (this.targets.size > 1) {
|
||||
errors.push({
|
||||
message: `There is more than one target using a builder that is used to build the project (${arrayToString(
|
||||
[...this.targets.keys()]
|
||||
)}).`,
|
||||
hint: `Make sure the project only has one target with a builder that is used to build the project.`,
|
||||
});
|
||||
}
|
||||
|
||||
return errors.length ? errors : null;
|
||||
}
|
||||
|
||||
private updateTargetConfiguration(
|
||||
targetName: string,
|
||||
target: TargetConfiguration
|
||||
): void {
|
||||
target.executor = '@nrwl/angular:package';
|
||||
|
||||
if (
|
||||
!target.options &&
|
||||
(!target.configurations || !Object.keys(target.configurations).length)
|
||||
) {
|
||||
this.logger.warn(
|
||||
`The target "${targetName}" is not specifying any options or configurations. Skipping updating the target configuration.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
['project', 'tsConfig'].forEach((option) => {
|
||||
if (target.options?.[option]) {
|
||||
target.options[option] = joinPathFragments(
|
||||
this.project.newRoot,
|
||||
basename(target.options[option])
|
||||
);
|
||||
}
|
||||
|
||||
for (const configuration of Object.values(target.configurations ?? {})) {
|
||||
configuration[option] =
|
||||
configuration[option] &&
|
||||
joinPathFragments(
|
||||
this.project.newRoot,
|
||||
basename(configuration[option])
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
updateProjectConfiguration(this.tree, this.project.name, {
|
||||
...this.projectConfig,
|
||||
});
|
||||
}
|
||||
|
||||
private updateNgPackageJson(
|
||||
targetName: string,
|
||||
target: TargetConfiguration
|
||||
): void {
|
||||
if (!target.options?.project) {
|
||||
this.logger.warn(
|
||||
`The "${targetName}" target does not have the "project" option configured. Skipping updating the ng-packagr project file ("ng-package.json").`
|
||||
);
|
||||
return;
|
||||
} else if (!this.tree.exists(target.options.project)) {
|
||||
this.logger.warn(
|
||||
`The ng-packagr project file "${this.originalProjectConfig.targets[targetName].options.project}" specified in the "${targetName}" ` +
|
||||
`target could not be found. Skipping updating the ng-packagr project file.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
updateJson(this.tree, target.options.project, (ngPackageJson) => {
|
||||
const offset = offsetFromRoot(this.project.newRoot);
|
||||
ngPackageJson.$schema =
|
||||
ngPackageJson.$schema &&
|
||||
`${offset}node_modules/ng-packagr/ng-package.schema.json`;
|
||||
ngPackageJson.dest = `${offset}dist/${this.project.name}`;
|
||||
|
||||
return ngPackageJson;
|
||||
});
|
||||
}
|
||||
|
||||
private updateTsConfigs(
|
||||
targetName: string,
|
||||
target: TargetConfiguration
|
||||
): void {
|
||||
const tsConfigPath =
|
||||
target.options?.tsConfig ?? target.configurations?.development?.tsConfig;
|
||||
if (!tsConfigPath) {
|
||||
this.logger.warn(
|
||||
`The "${targetName}" target does not have the "tsConfig" option configured. Skipping updating the tsConfig file.`
|
||||
);
|
||||
return;
|
||||
} else if (!this.tree.exists(tsConfigPath)) {
|
||||
const originalTsConfigPath = target.options?.tsConfig
|
||||
? this.originalProjectConfig.targets[targetName].options.tsConfig
|
||||
: this.originalProjectConfig.targets[targetName].configurations
|
||||
?.development?.tsConfig;
|
||||
this.logger.warn(
|
||||
`The tsConfig file "${originalTsConfigPath}" specified in the "${targetName}" target could not be found. Skipping updating the tsConfig file.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const rootTsConfigFile = getRootTsConfigPathInTree(this.tree);
|
||||
const projectOffsetFromRoot = offsetFromRoot(this.projectConfig.root);
|
||||
this.updateTsConfigFile(
|
||||
tsConfigPath,
|
||||
rootTsConfigFile,
|
||||
projectOffsetFromRoot
|
||||
);
|
||||
|
||||
updateJson(this.tree, tsConfigPath, (json) => {
|
||||
if (!json.include?.length && !json.files?.length) {
|
||||
json.include = ['**/*.ts'];
|
||||
}
|
||||
|
||||
return json;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
import type { ProjectConfiguration, Tree } from '@nrwl/devkit';
|
||||
import type { Logger, ProjectMigrationInfo } from '../../utilities';
|
||||
import type { BuilderMigrator } from './builder.migrator';
|
||||
|
||||
export type BuilderMigratorClassType = {
|
||||
new (
|
||||
tree: Tree,
|
||||
project: ProjectMigrationInfo,
|
||||
projectConfig: ProjectConfiguration,
|
||||
logger: Logger
|
||||
): BuilderMigrator;
|
||||
};
|
||||
@ -0,0 +1,36 @@
|
||||
import type {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import type { Logger, ProjectMigrationInfo } from '../../utilities';
|
||||
import { Migrator } from '../migrator';
|
||||
|
||||
export abstract class BuilderMigrator extends Migrator {
|
||||
protected targets: Map<string, TargetConfiguration> = new Map();
|
||||
|
||||
constructor(
|
||||
tree: Tree,
|
||||
public readonly builderName: string,
|
||||
project: ProjectMigrationInfo,
|
||||
projectConfig: ProjectConfiguration,
|
||||
logger: Logger
|
||||
) {
|
||||
super(tree, projectConfig, logger);
|
||||
|
||||
this.project = project;
|
||||
this.projectConfig = projectConfig;
|
||||
|
||||
this.collectBuilderTargets();
|
||||
}
|
||||
|
||||
protected collectBuilderTargets(): void {
|
||||
for (const [name, target] of Object.entries(
|
||||
this.projectConfig.targets ?? {}
|
||||
)) {
|
||||
if (target.executor === this.builderName) {
|
||||
this.targets.set(name, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
export * from './angular-devkit-ng-packagr.migrator';
|
||||
export * from './builder-migrator-class.type';
|
||||
export * from './builder.migrator';
|
||||
@ -0,0 +1,2 @@
|
||||
export * from './builders';
|
||||
export * from './projects';
|
||||
66
packages/angular/src/generators/ng-add/migrators/migrator.ts
Normal file
66
packages/angular/src/generators/ng-add/migrators/migrator.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import type { ProjectConfiguration, Tree } from '@nrwl/devkit';
|
||||
import {
|
||||
readWorkspaceConfiguration,
|
||||
updateJson,
|
||||
updateWorkspaceConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
import type { Logger } from '../utilities/logger';
|
||||
import type {
|
||||
ProjectMigrationInfo,
|
||||
ValidationResult,
|
||||
} from '../utilities/types';
|
||||
|
||||
export abstract class Migrator {
|
||||
protected project: ProjectMigrationInfo;
|
||||
protected readonly originalProjectConfig: ProjectConfiguration;
|
||||
|
||||
constructor(
|
||||
protected readonly tree: Tree,
|
||||
protected projectConfig: ProjectConfiguration,
|
||||
protected readonly logger: Logger
|
||||
) {
|
||||
this.originalProjectConfig = Object.freeze(
|
||||
JSON.parse(JSON.stringify(this.projectConfig))
|
||||
);
|
||||
}
|
||||
|
||||
abstract migrate(): Promise<void> | void;
|
||||
abstract validate(): ValidationResult;
|
||||
|
||||
// TODO(leo): This should be moved to BuilderMigrator once everything is split into builder migrators.
|
||||
protected updateCacheableOperations(targetNames: string[]): void {
|
||||
if (!targetNames.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workspaceConfig = readWorkspaceConfiguration(this.tree);
|
||||
|
||||
Object.keys(workspaceConfig.tasksRunnerOptions ?? {}).forEach(
|
||||
(taskRunnerName) => {
|
||||
const taskRunner = workspaceConfig.tasksRunnerOptions[taskRunnerName];
|
||||
taskRunner.options.cacheableOperations = Array.from(
|
||||
new Set([
|
||||
...(taskRunner.options.cacheableOperations ?? []),
|
||||
...targetNames,
|
||||
])
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
updateWorkspaceConfiguration(this.tree, workspaceConfig);
|
||||
}
|
||||
|
||||
// TODO(leo): This should be moved to BuilderMigrator once everything is split into builder migrators.
|
||||
protected updateTsConfigFile(
|
||||
tsConfigPath: string,
|
||||
rootTsConfigFile: string,
|
||||
projectOffsetFromRoot: string
|
||||
): void {
|
||||
updateJson(this.tree, tsConfigPath, (json) => {
|
||||
json.extends = `${projectOffsetFromRoot}${rootTsConfigFile}`;
|
||||
json.compilerOptions = json.compilerOptions ?? {};
|
||||
json.compilerOptions.outDir = `${projectOffsetFromRoot}dist/out-tsc`;
|
||||
return json;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,15 +1,17 @@
|
||||
import {
|
||||
import type {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import {
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
readWorkspaceConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
writeJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
||||
import type { MigrationProjectConfiguration } from '../../utilities/types';
|
||||
import { AppMigrator } from './app.migrator';
|
||||
import { MigrationProjectConfiguration } from './types';
|
||||
|
||||
type AngularCliProjectConfiguration = Omit<ProjectConfiguration, 'targets'> & {
|
||||
architect?: {
|
||||
@ -1,9 +1,8 @@
|
||||
import type { TargetConfiguration, Tree } from '@nrwl/devkit';
|
||||
import {
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
readJson,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
} from '@nrwl/devkit';
|
||||
@ -11,15 +10,15 @@ import { hasRulesRequiringTypeChecking } from '@nrwl/linter';
|
||||
import { convertToNxProjectGenerator } from '@nrwl/workspace/generators';
|
||||
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
|
||||
import { basename } from 'path';
|
||||
import { GeneratorOptions } from '../schema';
|
||||
import { E2eMigrator } from './e2e.migrator';
|
||||
import { Logger } from './logger';
|
||||
import { ProjectMigrator } from './project.migrator';
|
||||
import {
|
||||
import type { GeneratorOptions } from '../../schema';
|
||||
import type {
|
||||
Logger,
|
||||
MigrationProjectConfiguration,
|
||||
Target,
|
||||
ValidationResult,
|
||||
} from './types';
|
||||
} from '../../utilities';
|
||||
import { E2eMigrator } from './e2e.migrator';
|
||||
import { ProjectMigrator } from './project.migrator';
|
||||
|
||||
type SupportedTargets =
|
||||
| 'build'
|
||||
@ -78,7 +77,7 @@ export class AppMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
}
|
||||
}
|
||||
|
||||
async migrate(): Promise<void> {
|
||||
override async migrate(): Promise<void> {
|
||||
await this.e2eMigrator.migrate();
|
||||
|
||||
this.moveProjectFiles();
|
||||
@ -9,21 +9,23 @@ jest.mock('fs', () => {
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
import { installedCypressVersion } from '@nrwl/cypress/src/utils/cypress-version';
|
||||
import type {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import {
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
ProjectConfiguration,
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
writeJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
||||
import { lstatSync } from 'fs';
|
||||
import type { MigrationProjectConfiguration } from '../../utilities';
|
||||
import { E2eMigrator } from './e2e.migrator';
|
||||
import { MigrationProjectConfiguration } from './types';
|
||||
|
||||
type AngularCliProjectConfiguration = Omit<ProjectConfiguration, 'targets'> & {
|
||||
architect?: {
|
||||
@ -1,18 +1,20 @@
|
||||
import { cypressProjectGenerator } from '@nrwl/cypress';
|
||||
import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';
|
||||
import { installedCypressVersion } from '@nrwl/cypress/src/utils/cypress-version';
|
||||
import type {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import {
|
||||
addProjectConfiguration,
|
||||
joinPathFragments,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
ProjectConfiguration,
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
removeProjectConfiguration,
|
||||
stripIndents,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
visitNotIgnoredFiles,
|
||||
@ -23,25 +25,27 @@ import { insertImport } from '@nrwl/workspace/src/utilities/ast-utils';
|
||||
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
import { basename, relative } from 'path';
|
||||
import type {
|
||||
Node,
|
||||
ObjectLiteralExpression,
|
||||
PropertyAssignment,
|
||||
} from 'typescript';
|
||||
import {
|
||||
isObjectLiteralExpression,
|
||||
isPropertyAssignment,
|
||||
isStringLiteralLike,
|
||||
isTemplateExpression,
|
||||
Node,
|
||||
ObjectLiteralExpression,
|
||||
PropertyAssignment,
|
||||
SyntaxKind,
|
||||
} from 'typescript';
|
||||
import { GeneratorOptions } from '../schema';
|
||||
import { FileChangeRecorder } from './file-change-recorder';
|
||||
import { Logger } from './logger';
|
||||
import { ProjectMigrator } from './project.migrator';
|
||||
import {
|
||||
import type { GeneratorOptions } from '../../schema';
|
||||
import type {
|
||||
Logger,
|
||||
MigrationProjectConfiguration,
|
||||
Target,
|
||||
ValidationResult,
|
||||
} from './types';
|
||||
} from '../../utilities';
|
||||
import { FileChangeRecorder } from '../../utilities';
|
||||
import { ProjectMigrator } from './project.migrator';
|
||||
|
||||
type SupportedTargets = 'e2e';
|
||||
const supportedTargets: Record<SupportedTargets, Target> = {
|
||||
@ -101,7 +105,7 @@ export class E2eMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
async migrate(): Promise<void> {
|
||||
override async migrate(): Promise<void> {
|
||||
if (!this.targetNames.e2e) {
|
||||
this.logger.info(
|
||||
'No e2e project was migrated because there was no "e2e" target declared in the "angular.json".'
|
||||
@ -0,0 +1,4 @@
|
||||
export * from './app.migrator';
|
||||
export * from './e2e.migrator';
|
||||
export * from './lib.migrator';
|
||||
export * from './project.migrator';
|
||||
@ -1,15 +1,17 @@
|
||||
import {
|
||||
import type {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import {
|
||||
readJson,
|
||||
readProjectConfiguration,
|
||||
readWorkspaceConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
writeJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
|
||||
import type { MigrationProjectConfiguration } from '../../utilities';
|
||||
import { LibMigrator } from './lib.migrator';
|
||||
import { MigrationProjectConfiguration } from './types';
|
||||
|
||||
type AngularCliProjectConfiguration = Omit<ProjectConfiguration, 'targets'> & {
|
||||
architect?: {
|
||||
@ -126,8 +128,8 @@ describe('lib migrator', () => {
|
||||
expect(result[0].messageGroup.messages).toStrictEqual([
|
||||
'The "build" target is using an unsupported builder "@not/supported:builder".',
|
||||
]);
|
||||
expect(result[0].hint).toBe(
|
||||
'The supported builders for libraries are: "@angular-devkit/build-angular:ng-packagr", "@angular-devkit/build-angular:karma" and "@angular-eslint/builder:lint".'
|
||||
expect(result[0].hint).toMatchInlineSnapshot(
|
||||
`"The supported builders for libraries are: \\"@angular-devkit/build-angular:karma\\", \\"@angular-eslint/builder:lint\\" and \\"@angular-devkit/build-angular:ng-packagr\\"."`
|
||||
);
|
||||
});
|
||||
|
||||
@ -149,8 +151,8 @@ describe('lib migrator', () => {
|
||||
'The "build" target is using an unsupported builder "@not/supported:builder".',
|
||||
'The "test" target is using an unsupported builder "@other/not-supported:builder".',
|
||||
]);
|
||||
expect(result[0].hint).toBe(
|
||||
'The supported builders for libraries are: "@angular-devkit/build-angular:ng-packagr", "@angular-devkit/build-angular:karma" and "@angular-eslint/builder:lint".'
|
||||
expect(result[0].hint).toMatchInlineSnapshot(
|
||||
`"The supported builders for libraries are: \\"@angular-devkit/build-angular:karma\\", \\"@angular-eslint/builder:lint\\" and \\"@angular-devkit/build-angular:ng-packagr\\"."`
|
||||
);
|
||||
});
|
||||
|
||||
@ -168,8 +170,8 @@ describe('lib migrator', () => {
|
||||
expect(result[0].messageGroup.messages).toStrictEqual([
|
||||
'The "my-build" target is using an unsupported builder "@not/supported:builder".',
|
||||
]);
|
||||
expect(result[0].hint).toBe(
|
||||
'The supported builders for libraries are: "@angular-devkit/build-angular:ng-packagr", "@angular-devkit/build-angular:karma" and "@angular-eslint/builder:lint".'
|
||||
expect(result[0].hint).toMatchInlineSnapshot(
|
||||
`"The supported builders for libraries are: \\"@angular-devkit/build-angular:karma\\", \\"@angular-eslint/builder:lint\\" and \\"@angular-devkit/build-angular:ng-packagr\\"."`
|
||||
);
|
||||
});
|
||||
|
||||
@ -210,17 +212,17 @@ describe('lib migrator', () => {
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].message).toBe(
|
||||
'There is more than one target using a builder that is used to build the project ("build1" and "build2").'
|
||||
);
|
||||
expect(result[0].hint).toBe(
|
||||
'Make sure the project only has one target with a builder that is used to build the project.'
|
||||
);
|
||||
expect(result[1].message).toBe(
|
||||
'There is more than one target using a builder that is used to lint the project ("lint1" and "lint2").'
|
||||
);
|
||||
expect(result[1].hint).toBe(
|
||||
expect(result[0].hint).toBe(
|
||||
'Make sure the project only has one target with a builder that is used to lint the project.'
|
||||
);
|
||||
expect(result[1].message).toBe(
|
||||
'There is more than one target using a builder that is used to build the project ("build1" and "build2").'
|
||||
);
|
||||
expect(result[1].hint).toBe(
|
||||
'Make sure the project only has one target with a builder that is used to build the project.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should succeed validation', async () => {
|
||||
@ -274,7 +276,7 @@ describe('lib migrator', () => {
|
||||
await expect(migrator.migrate()).resolves.not.toThrow();
|
||||
|
||||
expect(mockedLogger.warn).toHaveBeenCalledWith(
|
||||
'There is no build target in the project configuration. This might not be an issue. Skipping updating the build configuration.'
|
||||
'There is no target in the project configuration using the @angular-devkit/build-angular:ng-packagr builder. This might not be an issue. Skipping updating the build configuration.'
|
||||
);
|
||||
});
|
||||
|
||||
@ -1,32 +1,36 @@
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import {
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
readJson,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { hasRulesRequiringTypeChecking } from '@nrwl/linter';
|
||||
import { convertToNxProjectGenerator } from '@nrwl/workspace/generators';
|
||||
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
|
||||
import { basename } from 'path';
|
||||
import { addBuildableLibrariesPostCssDependencies } from '../../utils/dependencies';
|
||||
import { GeneratorOptions } from '../schema';
|
||||
import { Logger } from './logger';
|
||||
import { ProjectMigrator } from './project.migrator';
|
||||
import {
|
||||
import type { GeneratorOptions } from '../../schema';
|
||||
import type {
|
||||
Logger,
|
||||
MigrationProjectConfiguration,
|
||||
Target,
|
||||
ValidationError,
|
||||
ValidationResult,
|
||||
} from './types';
|
||||
} from '../../utilities';
|
||||
import type { BuilderMigratorClassType } from '../builders';
|
||||
import { AngularDevkitNgPackagrMigrator } from '../builders';
|
||||
import { ProjectMigrator } from './project.migrator';
|
||||
|
||||
type SupportedTargets = 'build' | 'test' | 'lint';
|
||||
type SupportedTargets = 'test' | 'lint';
|
||||
const supportedTargets: Record<SupportedTargets, Target> = {
|
||||
build: { builders: ['@angular-devkit/build-angular:ng-packagr'] },
|
||||
test: { builders: ['@angular-devkit/build-angular:karma'] },
|
||||
lint: { builders: ['@angular-eslint/builder:lint'] },
|
||||
};
|
||||
// TODO(leo): this will replace `supportedTargets` once the full refactor is done.
|
||||
const supportedBuilderMigrators: BuilderMigratorClassType[] = [
|
||||
AngularDevkitNgPackagrMigrator,
|
||||
];
|
||||
|
||||
export class LibMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
private oldEsLintConfigPath: string;
|
||||
@ -38,7 +42,15 @@ export class LibMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
project: MigrationProjectConfiguration,
|
||||
logger?: Logger
|
||||
) {
|
||||
super(tree, options, supportedTargets, project, 'libs', logger);
|
||||
super(
|
||||
tree,
|
||||
options,
|
||||
supportedTargets,
|
||||
project,
|
||||
'libs',
|
||||
logger,
|
||||
supportedBuilderMigrators
|
||||
);
|
||||
|
||||
if (this.targetNames.lint) {
|
||||
this.oldEsLintConfigPath =
|
||||
@ -49,24 +61,29 @@ export class LibMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
}
|
||||
}
|
||||
|
||||
async migrate(): Promise<void> {
|
||||
override async migrate(): Promise<void> {
|
||||
await this.updateProjectConfiguration();
|
||||
this.moveProjectFiles();
|
||||
this.updateNgPackageJson();
|
||||
|
||||
for (const builderMigrator of this.builderMigrators ?? []) {
|
||||
await builderMigrator.migrate();
|
||||
}
|
||||
|
||||
this.updateTsConfigs();
|
||||
this.updateEsLintConfig();
|
||||
this.updateCacheableOperations(
|
||||
[
|
||||
this.targetNames.build,
|
||||
this.targetNames.lint,
|
||||
this.targetNames.test,
|
||||
].filter(Boolean)
|
||||
[this.targetNames.lint, this.targetNames.test].filter(Boolean)
|
||||
);
|
||||
addBuildableLibrariesPostCssDependencies(this.tree);
|
||||
}
|
||||
|
||||
override validate(): ValidationResult {
|
||||
return super.validate();
|
||||
const errors: ValidationError[] = [...(super.validate() ?? [])];
|
||||
|
||||
for (const builderMigrator of this.builderMigrators) {
|
||||
errors.push(...(builderMigrator.validate() ?? []));
|
||||
}
|
||||
|
||||
return errors.length ? errors : null;
|
||||
}
|
||||
|
||||
private moveProjectFiles(): void {
|
||||
@ -85,7 +102,6 @@ export class LibMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
'The project does not have any targets configured. This might not be an issue. Skipping updating targets.'
|
||||
);
|
||||
} else {
|
||||
this.updateBuildTargetConfiguration();
|
||||
this.updateLintTargetConfiguration();
|
||||
this.updateTestTargetConfiguration();
|
||||
}
|
||||
@ -100,33 +116,10 @@ export class LibMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
});
|
||||
}
|
||||
|
||||
private updateNgPackageJson(): void {
|
||||
const buildTarget = this.projectConfig.targets?.[this.targetNames.build];
|
||||
if (
|
||||
!buildTarget?.options?.project ||
|
||||
!this.tree.exists(buildTarget.options.project)
|
||||
) {
|
||||
// we already logged a warning for these cases, so just return
|
||||
return;
|
||||
}
|
||||
|
||||
const ngPackageJson = readJson(this.tree, buildTarget.options.project);
|
||||
const offset = offsetFromRoot(this.project.newRoot);
|
||||
ngPackageJson.$schema =
|
||||
ngPackageJson.$schema &&
|
||||
`${offset}node_modules/ng-packagr/ng-package.schema.json`;
|
||||
ngPackageJson.dest = `${offset}dist/${this.project.name}`;
|
||||
writeJson(this.tree, buildTarget.options.project, ngPackageJson);
|
||||
}
|
||||
|
||||
private updateTsConfigs(): void {
|
||||
const rootTsConfigFile = getRootTsConfigPathInTree(this.tree);
|
||||
const projectOffsetFromRoot = offsetFromRoot(this.projectConfig.root);
|
||||
|
||||
this.updateTsConfigFileUsedByBuildTarget(
|
||||
rootTsConfigFile,
|
||||
projectOffsetFromRoot
|
||||
);
|
||||
this.updateTsConfigFileUsedByTestTarget(
|
||||
rootTsConfigFile,
|
||||
projectOffsetFromRoot
|
||||
@ -176,72 +169,6 @@ export class LibMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
});
|
||||
}
|
||||
|
||||
private updateBuildTargetConfiguration(): void {
|
||||
if (!this.targetNames.build) {
|
||||
this.logger.warn(
|
||||
'There is no build target in the project configuration. This might not be an issue. Skipping updating the build configuration.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const buildTarget = this.projectConfig.targets[this.targetNames.build];
|
||||
buildTarget.executor = '@nrwl/angular:package';
|
||||
|
||||
if (
|
||||
!buildTarget.options &&
|
||||
(!buildTarget.configurations ||
|
||||
!Object.keys(buildTarget.configurations).length)
|
||||
) {
|
||||
this.logger.warn(
|
||||
`The target "${this.targetNames.build}" is not specifying any options or configurations. Skipping updating the target configuration.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const buildDevTsConfig =
|
||||
buildTarget.options?.tsConfig ??
|
||||
buildTarget.configurations?.development?.tsConfig;
|
||||
if (!buildDevTsConfig) {
|
||||
this.logger.warn(
|
||||
`The "${this.targetNames.build}" target does not have the "tsConfig" option configured. Skipping updating the tsConfig file.`
|
||||
);
|
||||
} else if (!this.tree.exists(buildDevTsConfig)) {
|
||||
this.logger.warn(
|
||||
`The tsConfig file "${buildDevTsConfig}" specified in the "${this.targetNames.build}" target could not be found. Skipping updating the tsConfig file.`
|
||||
);
|
||||
}
|
||||
|
||||
if (!buildTarget.options?.project) {
|
||||
this.logger.warn(
|
||||
`The "${this.targetNames.build}" target does not have the "project" option configured. Skipping updating the ng-packagr project file ("ng-package.json").`
|
||||
);
|
||||
} else if (!this.tree.exists(buildTarget.options.project)) {
|
||||
this.logger.warn(
|
||||
`The ng-packagr project file "${buildTarget.options.project}" specified in the "${this.targetNames.build}" target could not be found. Skipping updating the ng-packagr project file.`
|
||||
);
|
||||
}
|
||||
|
||||
['project', 'tsConfig'].forEach((option) => {
|
||||
if (buildTarget.options?.[option]) {
|
||||
buildTarget.options[option] = joinPathFragments(
|
||||
this.project.newRoot,
|
||||
basename(buildTarget.options[option])
|
||||
);
|
||||
}
|
||||
|
||||
for (const configuration of Object.values(
|
||||
buildTarget.configurations ?? {}
|
||||
)) {
|
||||
configuration[option] =
|
||||
configuration[option] &&
|
||||
joinPathFragments(
|
||||
this.project.newRoot,
|
||||
basename(configuration[option])
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private updateLintTargetConfiguration(): void {
|
||||
if (!this.targetNames.lint) {
|
||||
return;
|
||||
@ -353,39 +280,6 @@ export class LibMigrator extends ProjectMigrator<SupportedTargets> {
|
||||
testOptions.scripts.map((script) => this.convertAsset(script));
|
||||
}
|
||||
|
||||
private updateTsConfigFileUsedByBuildTarget(
|
||||
rootTsConfigFile: string,
|
||||
projectOffsetFromRoot: string
|
||||
): void {
|
||||
if (!this.targetNames.build) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tsConfigPath =
|
||||
this.projectConfig.targets[this.targetNames.build].options?.tsConfig ??
|
||||
this.projectConfig.targets[this.targetNames.build].configurations
|
||||
?.development?.tsConfig;
|
||||
|
||||
if (!tsConfigPath || !this.tree.exists(tsConfigPath)) {
|
||||
// we already logged a warning for these cases, so just return
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateTsConfigFile(
|
||||
tsConfigPath,
|
||||
rootTsConfigFile,
|
||||
projectOffsetFromRoot
|
||||
);
|
||||
|
||||
updateJson(this.tree, tsConfigPath, (json) => {
|
||||
if (!json.include?.length && !json.files?.length) {
|
||||
json.include = ['**/*.ts'];
|
||||
}
|
||||
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
private updateTsConfigFileUsedByTestTarget(
|
||||
rootTsConfigFile: string,
|
||||
projectOffsetFromRoot: string
|
||||
@ -1,50 +1,46 @@
|
||||
import type { TargetConfiguration, Tree } from '@nrwl/devkit';
|
||||
import {
|
||||
joinPathFragments,
|
||||
normalizePath,
|
||||
offsetFromRoot,
|
||||
ProjectConfiguration,
|
||||
readWorkspaceConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateWorkspaceConfiguration,
|
||||
visitNotIgnoredFiles,
|
||||
} from '@nrwl/devkit';
|
||||
import { basename, dirname } from 'path';
|
||||
import { GeneratorOptions } from '../schema';
|
||||
import { Logger } from './logger';
|
||||
import {
|
||||
import type { GeneratorOptions } from '../../schema';
|
||||
import type {
|
||||
MigrationProjectConfiguration,
|
||||
Target,
|
||||
ValidationError,
|
||||
ValidationResult,
|
||||
} from './types';
|
||||
import { arrayToString } from './validation-logging';
|
||||
} from '../../utilities';
|
||||
import { arrayToString, Logger } from '../../utilities';
|
||||
import type { BuilderMigratorClassType } from '../builders';
|
||||
import { BuilderMigrator } from '../builders';
|
||||
import { Migrator } from '../migrator';
|
||||
|
||||
export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
export abstract class ProjectMigrator<
|
||||
TargetType extends string = string
|
||||
> extends Migrator {
|
||||
public get projectName(): string {
|
||||
return this.project.name;
|
||||
}
|
||||
|
||||
protected projectConfig: ProjectConfiguration;
|
||||
protected project: {
|
||||
name: string;
|
||||
oldRoot: string;
|
||||
oldSourceRoot: string;
|
||||
newRoot: string;
|
||||
newSourceRoot: string;
|
||||
};
|
||||
protected logger: Logger;
|
||||
protected builderMigrators: BuilderMigrator[];
|
||||
protected readonly targetNames: Partial<Record<TargetType, string>> = {};
|
||||
|
||||
constructor(
|
||||
protected readonly tree: Tree,
|
||||
tree: Tree,
|
||||
protected readonly options: GeneratorOptions,
|
||||
protected readonly targets: Record<TargetType, Target>,
|
||||
project: MigrationProjectConfiguration,
|
||||
rootDir: string,
|
||||
logger?: Logger
|
||||
logger?: Logger,
|
||||
// TODO(leo): this will replace `targets` and become required once the full
|
||||
// refactor is done.
|
||||
supportedBuilderMigrators?: BuilderMigratorClassType[]
|
||||
) {
|
||||
this.projectConfig = project.config;
|
||||
super(tree, project.config, logger ?? new Logger(project.name));
|
||||
|
||||
this.project = {
|
||||
name: project.name,
|
||||
oldRoot: this.projectConfig.root ?? '',
|
||||
@ -55,22 +51,19 @@ export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
newSourceRoot: `${rootDir}/${project.name}/src`,
|
||||
};
|
||||
|
||||
this.logger = logger ?? new Logger(this.project.name);
|
||||
|
||||
this.collectTargetNames();
|
||||
this.createBuilderMigrators(supportedBuilderMigrators);
|
||||
}
|
||||
|
||||
abstract migrate(): Promise<void>;
|
||||
|
||||
validate(): ValidationResult {
|
||||
const result: ValidationResult = [];
|
||||
override validate(): ValidationResult {
|
||||
const errors: ValidationError[] = [];
|
||||
|
||||
// check project root
|
||||
if (
|
||||
this.projectConfig.root === undefined ||
|
||||
this.projectConfig.root === null
|
||||
) {
|
||||
result.push({
|
||||
errors.push({
|
||||
message:
|
||||
'The project root is not defined in the project configuration.',
|
||||
hint:
|
||||
@ -81,7 +74,7 @@ export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
this.projectConfig.root !== '' &&
|
||||
!this.tree.exists(this.projectConfig.root)
|
||||
) {
|
||||
result.push({
|
||||
errors.push({
|
||||
message: `The project root "${this.project.oldRoot}" could not be found.`,
|
||||
hint:
|
||||
`Make sure the value for "projects.${this.project.name}.root" is correct ` +
|
||||
@ -94,7 +87,7 @@ export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
this.projectConfig.sourceRoot &&
|
||||
!this.tree.exists(this.projectConfig.sourceRoot)
|
||||
) {
|
||||
result.push({
|
||||
errors.push({
|
||||
message: `The project source root "${this.project.oldSourceRoot}" could not be found.`,
|
||||
hint:
|
||||
`Make sure the value for "projects.${this.project.name}.sourceRoot" is correct ` +
|
||||
@ -108,6 +101,9 @@ export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
.map((x) => x.builders)
|
||||
.flat(),
|
||||
];
|
||||
allSupportedBuilders.push(
|
||||
...this.builderMigrators.map((migrator) => migrator.builderName)
|
||||
);
|
||||
const unsupportedBuilders: [target: string, builder: string][] = [];
|
||||
|
||||
Object.entries(this.projectConfig.targets ?? {}).forEach(
|
||||
@ -119,7 +115,7 @@ export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
);
|
||||
|
||||
if (unsupportedBuilders.length) {
|
||||
result.push({
|
||||
errors.push({
|
||||
messageGroup: {
|
||||
title: 'Unsupported builders',
|
||||
messages: unsupportedBuilders.map(
|
||||
@ -163,7 +159,7 @@ export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
return;
|
||||
}
|
||||
|
||||
result.push({
|
||||
errors.push({
|
||||
message: `There is more than one target using a builder that is used to ${targetType} the project (${arrayToString(
|
||||
targetsByType[targetType]
|
||||
)}).`,
|
||||
@ -171,7 +167,7 @@ export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
});
|
||||
});
|
||||
|
||||
return result.length ? result : null;
|
||||
return errors.length ? errors : null;
|
||||
}
|
||||
|
||||
protected convertAsset(asset: string | any): string | any {
|
||||
@ -310,41 +306,6 @@ export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
}
|
||||
}
|
||||
|
||||
protected updateCacheableOperations(targetNames: string[]): void {
|
||||
if (!targetNames.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const workspaceConfig = readWorkspaceConfiguration(this.tree);
|
||||
|
||||
Object.keys(workspaceConfig.tasksRunnerOptions ?? {}).forEach(
|
||||
(taskRunnerName) => {
|
||||
const taskRunner = workspaceConfig.tasksRunnerOptions[taskRunnerName];
|
||||
taskRunner.options.cacheableOperations = Array.from(
|
||||
new Set([
|
||||
...(taskRunner.options.cacheableOperations ?? []),
|
||||
...targetNames,
|
||||
])
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
updateWorkspaceConfiguration(this.tree, workspaceConfig);
|
||||
}
|
||||
|
||||
protected updateTsConfigFile(
|
||||
tsConfigPath: string,
|
||||
rootTsConfigFile: string,
|
||||
projectOffsetFromRoot: string
|
||||
): void {
|
||||
updateJson(this.tree, tsConfigPath, (json) => {
|
||||
json.extends = `${projectOffsetFromRoot}${rootTsConfigFile}`;
|
||||
json.compilerOptions = json.compilerOptions ?? {};
|
||||
json.compilerOptions.outDir = `${projectOffsetFromRoot}dist/out-tsc`;
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
private collectTargetNames(): void {
|
||||
const targetTypes = Object.keys(this.targets) as TargetType[];
|
||||
|
||||
@ -361,4 +322,23 @@ export abstract class ProjectMigrator<TargetType extends string = any> {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private createBuilderMigrators(
|
||||
supportedBuilderMigrators?: BuilderMigratorClassType[]
|
||||
): void {
|
||||
if (!supportedBuilderMigrators) {
|
||||
this.builderMigrators = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.builderMigrators = supportedBuilderMigrators.map(
|
||||
(migratorClass) =>
|
||||
new migratorClass(
|
||||
this.tree,
|
||||
this.project,
|
||||
this.projectConfig,
|
||||
this.logger
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import * as angularCliMigrator from './migrate-from-angular-cli';
|
||||
import * as initGenerator from '../init/init';
|
||||
import { ngAddGenerator } from './ng-add';
|
||||
import { Tree } from '@nrwl/devkit';
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
|
||||
describe('ngAdd generator', () => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { getProjects, Tree } from '@nrwl/devkit';
|
||||
import { MigrationProjectConfiguration, WorkspaceProjects } from './types';
|
||||
import type { MigrationProjectConfiguration, WorkspaceProjects } from './types';
|
||||
|
||||
export function getAllProjects(tree: Tree): WorkspaceProjects {
|
||||
const projects = getProjects(tree);
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
export * from './file-change-recorder';
|
||||
export * from './get-all-projects';
|
||||
export * from './logger';
|
||||
export * from './normalize-options';
|
||||
export * from './types';
|
||||
export * from './validate-projects';
|
||||
export * from './validation-logging';
|
||||
export * from './workspace';
|
||||
@ -1,12 +1,12 @@
|
||||
import type { Tree } from '@nrwl/devkit';
|
||||
import {
|
||||
detectWorkspaceScope,
|
||||
joinPathFragments,
|
||||
names,
|
||||
readJson,
|
||||
Tree,
|
||||
} from '@nrwl/devkit';
|
||||
import { GeneratorOptions } from '../schema';
|
||||
import { WorkspaceProjects } from './types';
|
||||
import type { GeneratorOptions } from '../schema';
|
||||
import type { WorkspaceProjects } from './types';
|
||||
|
||||
export function normalizeOptions(
|
||||
tree: Tree,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ProjectConfiguration } from '@nrwl/devkit';
|
||||
import type { ProjectConfiguration } from '@nrwl/devkit';
|
||||
|
||||
export type MigrationProjectConfiguration = {
|
||||
config: ProjectConfiguration;
|
||||
@ -10,6 +10,14 @@ export type WorkspaceProjects = {
|
||||
libs: MigrationProjectConfiguration[];
|
||||
};
|
||||
|
||||
export type ProjectMigrationInfo = {
|
||||
name: string;
|
||||
oldRoot: string;
|
||||
oldSourceRoot: string;
|
||||
newRoot: string;
|
||||
newSourceRoot: string;
|
||||
};
|
||||
|
||||
export type WorkspaceCapabilities = {
|
||||
karma: boolean;
|
||||
eslint: boolean;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as chalk from 'chalk';
|
||||
import { ProjectMigrator } from './project.migrator';
|
||||
import type { ProjectMigrator } from '../migrators';
|
||||
import { validateProjects } from './validate-projects';
|
||||
|
||||
describe('validateProjects', () => {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
// TODO(leo): this should probably move into a workspace-wide migrator
|
||||
import * as chalk from 'chalk';
|
||||
import { ProjectMigrator } from './project.migrator';
|
||||
import type { ProjectMigrator } from '../migrators';
|
||||
import { ValidationError } from './types';
|
||||
import { workspaceMigrationErrorHeading } from './validation-logging';
|
||||
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import type { NxJsonConfiguration, Tree } from '@nrwl/devkit';
|
||||
import {
|
||||
generateFiles,
|
||||
joinPathFragments,
|
||||
NxJsonConfiguration,
|
||||
readJson,
|
||||
readWorkspaceConfiguration,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateWorkspaceConfiguration,
|
||||
writeJson,
|
||||
@ -19,8 +18,8 @@ import { readFileSync } from 'fs';
|
||||
import { readModulePackageJson } from 'nx/src/utils/package-json';
|
||||
import { dirname, join } from 'path';
|
||||
import { angularDevkitVersion, nxVersion } from '../../../utils/versions';
|
||||
import { GeneratorOptions } from '../schema';
|
||||
import { WorkspaceCapabilities, WorkspaceProjects } from './types';
|
||||
import type { GeneratorOptions } from '../schema';
|
||||
import type { WorkspaceCapabilities, WorkspaceProjects } from './types';
|
||||
import { workspaceMigrationErrorHeading } from './validation-logging';
|
||||
|
||||
export function validateWorkspace(tree: Tree): void {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user