Skip to content

Commit

Permalink
feat(core): outputs should be able to interpolate project properties
Browse files Browse the repository at this point in the history
  • Loading branch information
vsavkin committed Jun 3, 2022
1 parent 7094280 commit 876d4d8
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 22 deletions.
6 changes: 6 additions & 0 deletions packages/nx/migrations.json
Expand Up @@ -17,6 +17,12 @@
"version": "14.2.0-beta.0",
"description": "Remove default collection from configuration to switch to prompts for collection",
"factory": "./src/migrations/update-14-2-0/remove-default-collection"
},
"14-2-0-replace-relative-outputs-with-absolute": {
"cli": "nx",
"version": "14.2.0-beta.5",
"description": "Replace all ./ and ../ in outputs with absolute paths",
"factory": "./src/migrations/update-14-2-0/replace-all-relative-outputs-with-absolute"
}
}
}
6 changes: 4 additions & 2 deletions packages/nx/src/command-line/run-many.ts
Expand Up @@ -50,12 +50,14 @@ function projectsToRun(
const allProjects = Object.values(projectGraph.nodes);
const excludedProjects = new Set(nxArgs.exclude ?? []);
if (nxArgs.all) {
return runnableForTarget(allProjects, nxArgs.target).filter(
const res = runnableForTarget(allProjects, nxArgs.target).filter(
(proj) => !excludedProjects.has(proj.name)
);
res.sort((a, b) => a.name.localeCompare(b.name));
return res;
}
checkForInvalidProjects(nxArgs, allProjects);
let selectedProjects = nxArgs.projects.map((name) =>
const selectedProjects = nxArgs.projects.map((name) =>
allProjects.find((project) => project.name === name)
);
return runnableForTarget(selectedProjects, nxArgs.target, true).filter(
Expand Down
@@ -0,0 +1,20 @@
import { Tree } from '../../generators/tree';
import {
getProjects,
updateProjectConfiguration,
} from '../../generators/utils/project-configuration';
import { isRelativePath } from 'nx/src/utils/fileutils';
import { joinPathFragments } from 'nx/src/utils/path';

export default async function (tree: Tree) {
for (const [name, value] of getProjects(tree).entries()) {
for (const t of Object.values(value.targets)) {
if (t.outputs) {
t.outputs = t.outputs.map((o) =>
isRelativePath(o) ? joinPathFragments(value.root, o) : o
);
}
}
updateProjectConfiguration(tree, name, value);
}
}
22 changes: 6 additions & 16 deletions packages/nx/src/tasks-runner/create-task-graph.ts
@@ -1,6 +1,6 @@
import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph';
import { TargetDependencyConfig } from '../config/workspace-json-project-json';
import { getDependencyConfigs } from './utils';
import { getDependencyConfigs, interpolate } from './utils';
import {
projectHasTarget,
projectHasTargetAndConfiguration,
Expand Down Expand Up @@ -34,7 +34,6 @@ export class ProcessTasks {
configuration
);
const id = this.getId(projectName, target, resolvedConfiguration);
debugger;
const task = this.createTask(
id,
this.projectGraph.nodes[projectName],
Expand Down Expand Up @@ -219,23 +218,14 @@ export function createTaskGraph(
function interpolateOverrides<T = any>(
args: T,
projectName: string,
projectMetadata: any
project: any
): T {
const interpolatedArgs: T = { ...args };
Object.entries(interpolatedArgs).forEach(([name, value]) => {
if (typeof value === 'string') {
const regex = /{project\.([^}]+)}/g;
interpolatedArgs[name] = value.replace(regex, (_, group: string) => {
if (group.includes('.')) {
throw new Error('Only top-level properties can be interpolated');
}

if (group === 'name') {
return projectName;
}
return projectMetadata[group];
});
}
interpolatedArgs[name] =
typeof value === 'string'
? interpolate(value, { project: { ...project, name: projectName } })
: value;
});
return interpolatedArgs;
}
40 changes: 40 additions & 0 deletions packages/nx/src/tasks-runner/utils.spec.ts
Expand Up @@ -17,6 +17,7 @@ describe('utils', () => {
name: 'myapp',
type: 'app',
data: {
root: '/myapp',
targets: {
build: { ...build, executor: '' },
},
Expand All @@ -37,6 +38,17 @@ describe('utils', () => {
).toEqual(['one', 'two']);
});

it('should return them', () => {
expect(
getOutputsForTargetAndConfiguration(
task,
getNode({
outputs: ['one', 'two'],
})
)
).toEqual(['one', 'two']);
});

it('should support interpolation based on options', () => {
expect(
getOutputsForTargetAndConfiguration(
Expand All @@ -51,6 +63,34 @@ describe('utils', () => {
).toEqual(['path/one', 'two']);
});

it('should support interpolating root', () => {
expect(
getOutputsForTargetAndConfiguration(
task,
getNode({
outputs: ['{project.root}/sub', 'two'],
options: {
myVar: 'one',
},
})
)
).toEqual(['/myapp/sub', 'two']);
});

it('should support relative paths', () => {
expect(
getOutputsForTargetAndConfiguration(
task,
getNode({
outputs: ['./sub', 'two'],
options: {
myVar: 'one',
},
})
)
).toEqual(['/myapp/sub', 'two']);
});

it('should support nested interpolation based on options', () => {
expect(
getOutputsForTargetAndConfiguration(
Expand Down
17 changes: 13 additions & 4 deletions packages/nx/src/tasks-runner/utils.ts
Expand Up @@ -13,6 +13,8 @@ import { getPackageManagerCommand } from '../utils/package-manager';
import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph';
import { TargetDependencyConfig } from '../config/workspace-json-project-json';
import { workspaceRoot } from '../utils/workspace-root';
import { isRelativePath } from 'nx/src/utils/fileutils';
import { joinPathFragments } from 'nx/src/utils/path';

export function getCommandAsString(task: Task) {
const execCommand = getPackageManagerCommand().exec;
Expand Down Expand Up @@ -88,7 +90,15 @@ export function getOutputsForTargetAndConfiguration(

if (targets?.outputs) {
return targets.outputs
.map((output: string) => interpolateOutputs(output, options))
.map((output: string) => {
const interpolated = interpolate(output, {
options,
project: { ...node.data, name: node.name },
});
return isRelativePath(interpolated)
? joinPathFragments(node.data.root, interpolated)
: interpolated;
})
.filter((output) => !!output);
}

Expand Down Expand Up @@ -150,17 +160,16 @@ function stringShouldBeWrappedIntoQuotes(str: string) {
return str.includes(' ') || str.includes('{') || str.includes('"');
}

function interpolateOutputs(template: string, data: any): string {
export function interpolate(template: string, data: any): string {
return template.replace(/{([\s\S]+?)}/g, (match: string) => {
let value = data;
let path = match.slice(1, -1).trim().split('.').slice(1);
let path = match.slice(1, -1).trim().split('.');
for (let idx = 0; idx < path.length; idx++) {
if (!value[path[idx]]) {
return;
}
value = value[path[idx]];
}

return value;
});
}
Expand Down

1 comment on commit 876d4d8

@vercel
Copy link

@vercel vercel bot commented on 876d4d8 Jun 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx.dev
nx-five.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx-dev-nrwl.vercel.app

Please sign in to comment.