@nx/devkit
Version:
155 lines (154 loc) • 6.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.deleteMatchingProperties = deleteMatchingProperties;
exports.processTargetOutputs = processTargetOutputs;
exports.toProjectRelativePath = toProjectRelativePath;
const posix_1 = require("node:path/posix");
const devkit_exports_1 = require("nx/src/devkit-exports");
const devkit_internals_1 = require("nx/src/devkit-internals");
/**
* Iterate through the current target in the project.json and its options comparing it to the target created by the Plugin itself
* Delete matching properties from current target.
*
* _Note: Deletes by reference_
*
* @example
* // Run the plugin to get all the projects
* const { projects } = await createNodes[1](
* playwrightConfigPath,
* { targetName, ciTargetName: 'e2e-ci' },
* { workspaceRoot: tree.root, nxJsonConfiguration, configFiles }
* );
*
* // Find the project that matches the one that is being migrated
* const createdProject = Object.entries(projects ?? {}).find(
* ([root]) => root === projectFromGraph.data.root
* )[1];
*
* // Get the created TargetConfiguration for the target being migrated
* const createdTarget: TargetConfiguration<RunCommandsOptions> =
* createdProject.targets[targetName];
*
* // Delete specific run-commands options
* delete createdTarget.command;
* delete createdTarget.options?.cwd;
*
* // Get the TargetConfiguration for the target being migrated from project.json
* const projectConfig = readProjectConfiguration(tree, projectName);
* let targetToMigrate = projectConfig.targets[targetName];
*
* // Merge the target defaults for the executor to the target being migrated
* target = mergeTargetConfigurations(targetToMigrate, targetDefaultsForExecutor);
*
* // Delete executor and any additional options that are no longer necessary
* delete target.executor;
* delete target.options?.config;
*
* // Run deleteMatchingProperties to delete further options that match what the plugin creates
* deleteMatchingProperties(target, createdTarget);
*
* // Delete the target if it is now empty, otherwise, set it to the updated TargetConfiguration
* if (Object.keys(target).length > 0) {
* projectConfig.targets[targetName] = target;
* } else {
* delete projectConfig.targets[targetName];
* }
*
* updateProjectConfiguration(tree, projectName, projectConfig);
*
* @param targetToMigrate The target from project.json
* @param createdTarget The target created by the Plugin
*/
function deleteMatchingProperties(targetToMigrate, createdTarget) {
for (const key in targetToMigrate) {
if (Array.isArray(targetToMigrate[key])) {
if (targetToMigrate[key].every((v) => createdTarget[key]?.includes(v)) &&
targetToMigrate[key].length === createdTarget[key]?.length) {
delete targetToMigrate[key];
}
}
else if (typeof targetToMigrate[key] === 'object' &&
typeof createdTarget[key] === 'object') {
deleteMatchingProperties(targetToMigrate[key], createdTarget[key]);
}
else if (targetToMigrate[key] === createdTarget[key]) {
delete targetToMigrate[key];
}
if (typeof targetToMigrate[key] === 'object' &&
Object.keys(targetToMigrate[key]).length === 0) {
delete targetToMigrate[key];
}
}
}
function processTargetOutputs(target, renamedOutputOptions, inferredTarget, projectDetails) {
const interpolatedInferredOutputs = (inferredTarget.outputs ?? []).map((output) => (0, devkit_internals_1.interpolate)(output, {
workspaceRoot: '',
projectRoot: projectDetails.projectRoot,
projectName: projectDetails.projectName,
}));
const targetOutputs = (target.outputs ?? []).map((output) => updateOutput(output, renamedOutputOptions));
const interpolatedOutputs = targetOutputs.map((output) => (0, devkit_internals_1.interpolate)(output, {
workspaceRoot: '',
projectRoot: projectDetails.projectRoot,
projectName: projectDetails.projectName,
}));
const shouldDelete = interpolatedOutputs.every((output) => interpolatedInferredOutputs.includes(output));
if (shouldDelete) {
// all existing outputs are already inferred
delete target.outputs;
return;
}
// move extra inferred outputs to the target outputs
for (let i = 0; i < interpolatedInferredOutputs.length; i++) {
if (!interpolatedOutputs.includes(interpolatedInferredOutputs[i])) {
targetOutputs.push(inferredTarget.outputs[i]);
interpolatedOutputs.push(interpolatedInferredOutputs[i]);
}
}
target.outputs = targetOutputs;
}
function toProjectRelativePath(path, projectRoot) {
if (projectRoot === '.') {
// workspace and project root are the same, we add a leading './' which is
// required by some tools (e.g. Jest)
return path.startsWith('.') ? path : `./${path}`;
}
const relativePath = (0, posix_1.relative)((0, posix_1.resolve)(devkit_exports_1.workspaceRoot, projectRoot), (0, posix_1.resolve)(devkit_exports_1.workspaceRoot, path));
return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
}
function updateOutputRenamingOption(output, option, previousName) {
const newOptionToken = `{options.${option}}`;
const oldOptionToken = `{options.${previousName}}`;
if (!output.startsWith('{workspaceRoot}') &&
!output.startsWith('{projectRoot}')) {
return `{projectRoot}/${output.replace(oldOptionToken, newOptionToken)}`;
}
if (output.startsWith('{workspaceRoot}') &&
!output.startsWith('{workspaceRoot}/{projectRoot}')) {
return output
.replace('{workspaceRoot}', '{projectRoot}')
.replace(oldOptionToken, newOptionToken);
}
return output.replace(oldOptionToken, newOptionToken);
}
function updateOutput(output, renamedOutputOptions) {
if (!/{options\..*}/.test(output)) {
// output does not contain any option tokens
return output;
}
for (const { newName, oldName } of renamedOutputOptions) {
const optionToken = `{options.${oldName}}`;
if (output.includes(optionToken)) {
return updateOutputRenamingOption(output, newName, oldName);
}
}
if (!output.startsWith('{workspaceRoot}') &&
!output.startsWith('{projectRoot}')) {
return `{projectRoot}/${output}`;
}
if (output.startsWith('{workspaceRoot}') &&
!output.startsWith('{workspaceRoot}/{projectRoot}')) {
return output.replace('{workspaceRoot}', '{projectRoot}');
}
return output;
}
;