feat(core): allow dependsOn to accept a single project dependency (#16100)

This commit is contained in:
Craigory Coppola 2023-04-10 13:12:16 -04:00 committed by GitHub
parent 7989facc85
commit f2f6e356a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 491 additions and 126 deletions

View File

@ -276,6 +276,9 @@ result in `mylib`'s dependencies being built as well.
You can also express the same configuration using: You can also express the same configuration using:
{% tabs %}
{% tab label="Version < 16" %}
```json ```json
"build": { "build": {
"dependsOn": [{ "projects": "dependencies", "target": "build" }] "dependsOn": [{ "projects": "dependencies", "target": "build" }]
@ -285,8 +288,26 @@ You can also express the same configuration using:
} }
``` ```
{% /tab %}
{% tab label="Version 16+" %}
```json
"build": {
"dependsOn": [{ "projects": "{dependencies}", "target": "build" }]
},
"test": {
"dependsOn": [{ "projects": "{self}", "target": "build" }]
}
```
{% /tab %}
{% /tabs %}
With the expanded syntax, you also have a third option available to configure how to handle the params passed to the target. You can either forward them or you can ignore them (default). With the expanded syntax, you also have a third option available to configure how to handle the params passed to the target. You can either forward them or you can ignore them (default).
{% tabs %}
{% tab label="Version < 16" %}
```json ```json
"build": { "build": {
// forward params passed to this target to the dependency targets // forward params passed to this target to the dependency targets
@ -302,8 +323,32 @@ With the expanded syntax, you also have a third option available to configure ho
} }
``` ```
{% /tab %}
{% tab label="Version 16+" %}
```json
"build": {
// forward params passed to this target to the dependency targets
"dependsOn": [{ "projects": "{dependencies}", "target": "build", "params": "forward" }]
},
"test": {
// ignore params passed to this target, won't be forwarded to the dependency targets
"dependsOn": [{ "projects": "{dependencies}", "target": "build", "params": "ignore" }]
}
"lint": {
// ignore params passed to this target, won't be forwarded to the dependency targets
"dependsOn": [{ "projects": "{dependencies}", "target": "build" }]
}
```
{% /tab %}
{% /tabs %}
Obviously this also works when defining a relation for the target of the project itself using `"projects": "self"`: Obviously this also works when defining a relation for the target of the project itself using `"projects": "self"`:
{% tabs %}
{% tab label="Version < 16" %}
```json ```json
"build": { "build": {
// forward params passed to this target to the project target // forward params passed to this target to the project target
@ -311,6 +356,28 @@ Obviously this also works when defining a relation for the target of the project
} }
``` ```
{% /tab %}
{% tab label="Version 16+" %}
```json
"build": {
// forward params passed to this target to the project target
"dependsOn": [{ "projects": "{self}", "target": "pre-build", "params": "forward" }]
}
```
{% /tab %}
{% /tabs %}
Additionally, when using the expanded object syntax, you can specify individual projects in version 16 or greater.
```json
"build": {
// Run is-even:pre-build and is-odd:pre-build before this target
"dependsOn": [{ "projects": ["is-even", "is-odd"], "target": "pre-build" }]
}
```
This configuration is usually not needed. Nx comes with reasonable defaults (imported in `nx.json`) which implement the This configuration is usually not needed. Nx comes with reasonable defaults (imported in `nx.json`) which implement the
configuration above. configuration above.

View File

@ -59,6 +59,12 @@
"version": "16.0.0-beta.0", "version": "16.0.0-beta.0",
"description": "Remove @nrwl/cli.", "description": "Remove @nrwl/cli.",
"implementation": "./src/migrations/update-16-0-0/remove-nrwl-cli" "implementation": "./src/migrations/update-16-0-0/remove-nrwl-cli"
},
"16.0.0-tokens-for-depends-on": {
"cli": "nx",
"version": "16.0.0-beta.0",
"description": "Replace `dependsOn.projects` with {self} or {dependencies} tokens so that it matches the new expected formatting.",
"implementation": "./src/migrations/update-16-0-0/update-depends-on-to-tokens"
} }
} }
} }

View File

@ -247,9 +247,19 @@
"type": "object", "type": "object",
"properties": { "properties": {
"projects": { "projects": {
"type": "string", "oneOf": [
"description": "The projects that the targets belong to.", {
"enum": ["self", "dependencies"] "type": "string",
"description": "{self}, {dependencies}, or a project name."
},
{
"type": "array",
"description": "An array of project specifiers: {self}, {dependencies}, or a project name.",
"items": {
"type": "string"
}
}
]
}, },
"target": { "target": {
"type": "string", "type": "string",

View File

@ -55,9 +55,19 @@
"type": "object", "type": "object",
"properties": { "properties": {
"projects": { "projects": {
"type": "string", "oneOf": [
"description": "The projects that the targets belong to.", {
"enum": ["self", "dependencies"] "type": "string",
"description": "{self}, {dependencies}, or a project name."
},
{
"type": "array",
"description": "An array of project specifiers: {self}, {dependencies}, or a project name.",
"items": {
"type": "string"
}
}
]
}, },
"target": { "target": {
"type": "string", "type": "string",

View File

@ -65,9 +65,19 @@
"type": "object", "type": "object",
"properties": { "properties": {
"projects": { "projects": {
"type": "string", "oneOf": [
"description": "The projects that the targets belong to.", {
"enum": ["self", "dependencies"] "type": "string",
"description": "{self}, {dependencies}, or a project name."
},
{
"type": "array",
"description": "An array of project specifiers: {self}, {dependencies}, or a project name.",
"items": {
"type": "string"
}
}
]
}, },
"target": { "target": {
"type": "string", "type": "string",

View File

@ -102,12 +102,15 @@ export interface ProjectConfiguration {
export interface TargetDependencyConfig { export interface TargetDependencyConfig {
/** /**
* This the projects that the targets belong to * A list of projects that have `target`. Supports project names or two special values:
* *
* 'self': This target depends on another target of the same project * - '{self}': This target depends on another target of the same project
* 'deps': This target depends on targets of the projects of it's deps. * - '{dependencies}': This target depends on targets of the projects of it's deps.
*
* The special values {self}/{dependencies} should be preferred - they prevent cases where a project
* that needs to be built is missed.
*/ */
projects: 'self' | 'dependencies'; projects: string[] | string;
/** /**
* The name of the target * The name of the target

View File

@ -0,0 +1,104 @@
import {
addProjectConfiguration,
getProjects,
readNxJson,
readProjectConfiguration,
} from '../../generators/utils/project-configuration';
import { Tree } from '../../generators/tree';
import update from './update-depends-on-to-tokens';
import { updateJson, writeJson } from 'nx/src/devkit-exports';
import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace';
describe('update-depends-on-to-tokens', () => {
it('should update nx.json', async () => {
const tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'nx.json', (json) => {
json.targetDefaults = {
build: {
dependsOn: [
{
projects: 'self',
},
],
},
test: {
dependsOn: [
{
projects: 'dependencies',
},
],
},
other: {
dependsOn: ['^deps'],
},
};
return json;
});
await update(tree);
const nxJson = readNxJson(tree);
const build = nxJson.targetDefaults.build.dependsOn[0] as any;
const test = nxJson.targetDefaults.test.dependsOn[0] as any;
expect(build.projects).toEqual('{self}');
expect(test.projects).toEqual('{dependencies}');
expect(nxJson.targetDefaults.other.dependsOn).toEqual(['^deps']);
});
it('should update project configurations', async () => {
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'proj1', {
root: 'proj1',
targets: {
build: {
dependsOn: [
{
projects: 'self',
target: 'build',
},
],
},
test: {
dependsOn: [
{
projects: 'dependencies',
target: 'test',
},
],
},
other: {
dependsOn: ['^deps'],
},
},
});
await update(tree);
const project = readProjectConfiguration(tree, 'proj1');
const build = project.targets.build.dependsOn[0] as any;
const test = project.targets.test.dependsOn[0] as any;
expect(build.projects).toEqual('{self}');
expect(test.projects).toEqual('{dependencies}');
expect(project.targets.other.dependsOn).toEqual(['^deps']);
});
it('should not throw on nulls', async () => {
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'proj1', {
root: 'proj1',
});
addProjectConfiguration(tree, 'proj2', {
root: 'proj2',
targets: {
build: {},
},
});
writeJson(tree, 'nx.json', {});
let promise = update(tree);
await expect(promise).resolves.toBeUndefined();
writeJson(tree, 'nx.json', {
targetDefaults: {
build: {},
},
});
promise = update(tree);
await expect(promise).resolves.toBeUndefined();
});
});

View File

@ -0,0 +1,56 @@
import {
getProjects,
readNxJson,
updateNxJson,
updateProjectConfiguration,
} from '../../generators/utils/project-configuration';
import { Tree } from '../../generators/tree';
export default async function (tree: Tree) {
updateDependsOnInsideNxJson(tree);
const projectsConfigurations = getProjects(tree);
for (const [projectName, projectConfiguration] of projectsConfigurations) {
let projectChanged = false;
for (const [targetName, targetConfiguration] of Object.entries(
projectConfiguration.targets ?? {}
)) {
for (const dependency of targetConfiguration.dependsOn ?? []) {
if (typeof dependency !== 'string') {
if (dependency.projects === 'self') {
dependency.projects = '{self}';
projectChanged = true;
} else if (dependency.projects === 'dependencies') {
dependency.projects = '{dependencies}';
projectChanged = true;
}
}
}
}
if (projectChanged) {
updateProjectConfiguration(tree, projectName, projectConfiguration);
}
}
}
function updateDependsOnInsideNxJson(tree: Tree) {
const nxJson = readNxJson(tree);
let nxJsonChanged = false;
for (const [target, defaults] of Object.entries(
nxJson?.targetDefaults ?? {}
)) {
for (const dependency of defaults.dependsOn ?? []) {
if (typeof dependency !== 'string') {
if (dependency.projects === 'self') {
dependency.projects = '{self}';
nxJsonChanged = true;
} else if (dependency.projects === 'dependencies') {
dependency.projects = '{dependencies}';
nxJsonChanged = true;
}
}
}
}
if (nxJsonChanged) {
updateNxJson(tree, nxJson);
}
}

View File

@ -17,17 +17,24 @@ describe('createTaskGraph', () => {
prebuild: { prebuild: {
executor: 'nx:run-commands', executor: 'nx:run-commands',
}, },
prebuild2: {
executor: 'nx:run-commands',
},
build: { build: {
executor: 'nx:run-commands', executor: 'nx:run-commands',
dependsOn: [ dependsOn: [
{ {
projects: 'dependencies', projects: '{dependencies}',
target: 'build', target: 'build',
}, },
{ {
projects: 'self', projects: '{self}',
target: 'prebuild', target: 'prebuild',
}, },
{
projects: 'app1',
target: 'prebuild2',
},
], ],
}, },
test: { test: {
@ -166,7 +173,7 @@ describe('createTaskGraph', () => {
}, },
dependsOn: [ dependsOn: [
{ {
projects: 'dependencies', projects: '{dependencies}',
target: 'build', target: 'build',
}, },
], ],
@ -189,7 +196,7 @@ describe('createTaskGraph', () => {
defaultConfiguration: 'libDefault', defaultConfiguration: 'libDefault',
dependsOn: [ dependsOn: [
{ {
projects: 'dependencies', projects: '{dependencies}',
target: 'build', target: 'build',
}, },
], ],
@ -330,7 +337,7 @@ describe('createTaskGraph', () => {
executor: 'my-executor', executor: 'my-executor',
dependsOn: [ dependsOn: [
{ {
projects: 'dependencies', projects: '{dependencies}',
target: 'build', target: 'build',
}, },
], ],
@ -501,11 +508,11 @@ describe('createTaskGraph', () => {
executor: 'nx:run-commands', executor: 'nx:run-commands',
dependsOn: [ dependsOn: [
{ {
projects: 'dependencies', projects: '{dependencies}',
target: 'build', target: 'build',
params: 'forward', params: 'forward',
}, },
{ projects: 'self', target: 'prebuild', params: 'forward' }, { projects: '{self}', target: 'prebuild', params: 'forward' },
], ],
}, },
test: { test: {
@ -528,7 +535,7 @@ describe('createTaskGraph', () => {
executor: 'nx:run-commands', executor: 'nx:run-commands',
dependsOn: [ dependsOn: [
{ {
projects: 'dependencies', projects: '{dependencies}',
target: 'build', target: 'build',
params: 'ignore', params: 'ignore',
}, },
@ -640,7 +647,7 @@ describe('createTaskGraph', () => {
); );
// prebuild should also be in here // prebuild should also be in here
expect(taskGraph).toEqual({ expect(taskGraph).toEqual({
roots: ['lib1:build', 'app1:prebuild'], roots: ['lib1:build', 'app1:prebuild', 'app1:prebuild2'],
tasks: { tasks: {
'app1:build': { 'app1:build': {
id: 'app1:build', id: 'app1:build',
@ -664,6 +671,17 @@ describe('createTaskGraph', () => {
}, },
projectRoot: 'app1-root', projectRoot: 'app1-root',
}, },
'app1:prebuild2': {
id: 'app1:prebuild2',
target: {
project: 'app1',
target: 'prebuild2',
},
overrides: {
__overrides_unparsed__: [],
},
projectRoot: 'app1-root',
},
'lib1:build': { 'lib1:build': {
id: 'lib1:build', id: 'lib1:build',
target: { target: {
@ -677,8 +695,9 @@ describe('createTaskGraph', () => {
}, },
}, },
dependencies: { dependencies: {
'app1:build': ['lib1:build', 'app1:prebuild'], 'app1:build': ['lib1:build', 'app1:prebuild', 'app1:prebuild2'],
'app1:prebuild': [], 'app1:prebuild': [],
'app1:prebuild2': [],
'lib1:build': [], 'lib1:build': [],
}, },
}); });
@ -697,7 +716,7 @@ describe('createTaskGraph', () => {
); );
// prebuild should also be in here // prebuild should also be in here
expect(taskGraph).toEqual({ expect(taskGraph).toEqual({
roots: ['app1:prebuild', 'lib1:build'], roots: ['app1:prebuild', 'lib1:build', 'app1:prebuild2'],
tasks: { tasks: {
'app1:build': { 'app1:build': {
id: 'app1:build', id: 'app1:build',
@ -721,6 +740,17 @@ describe('createTaskGraph', () => {
}, },
projectRoot: 'app1-root', projectRoot: 'app1-root',
}, },
'app1:prebuild2': {
id: 'app1:prebuild2',
target: {
project: 'app1',
target: 'prebuild2',
},
overrides: {
__overrides_unparsed__: [],
},
projectRoot: 'app1-root',
},
'lib1:build': { 'lib1:build': {
id: 'lib1:build', id: 'lib1:build',
target: { target: {
@ -734,8 +764,9 @@ describe('createTaskGraph', () => {
}, },
}, },
dependencies: { dependencies: {
'app1:build': ['lib1:build', 'app1:prebuild'], 'app1:build': ['lib1:build', 'app1:prebuild', 'app1:prebuild2'],
'app1:prebuild': [], 'app1:prebuild': [],
'app1:prebuild2': [],
'lib1:build': [], 'lib1:build': [],
}, },
}); });
@ -813,7 +844,7 @@ describe('createTaskGraph', () => {
{ {
build: [ build: [
{ {
projects: 'dependencies', projects: '{dependencies}',
target: 'build', target: 'build',
}, },
], ],
@ -974,9 +1005,9 @@ describe('createTaskGraph', () => {
{ {
build: ['^build'], build: ['^build'],
apply: [ apply: [
{ projects: 'dependencies', target: 'build' }, { projects: '{dependencies}', target: 'build' },
{ {
projects: 'dependencies', projects: '{dependencies}',
target: 'apply', target: 'apply',
params: 'forward', params: 'forward',
}, },
@ -1052,11 +1083,11 @@ describe('createTaskGraph', () => {
targets: { targets: {
build: { build: {
executor: 'nx:run-commands', executor: 'nx:run-commands',
dependsOn: [{ target: 'test', projects: 'self' }], dependsOn: [{ target: 'test', projects: '{self}' }],
}, },
test: { test: {
executor: 'nx:run-commands', executor: 'nx:run-commands',
dependsOn: [{ target: 'build', projects: 'self' }], dependsOn: [{ target: 'build', projects: '{self}' }],
}, },
}, },
}, },
@ -1161,7 +1192,7 @@ describe('createTaskGraph', () => {
const taskGraph = createTaskGraph( const taskGraph = createTaskGraph(
projectGraph, projectGraph,
{ {
build: [{ target: 'build', projects: 'dependencies' }], build: [{ target: 'build', projects: '{dependencies}' }],
}, },
['app1'], ['app1'],
['build'], ['build'],
@ -1252,7 +1283,7 @@ describe('createTaskGraph', () => {
const taskGraph = createTaskGraph( const taskGraph = createTaskGraph(
projectGraph, projectGraph,
{ {
build: [{ target: 'build', projects: 'dependencies' }], build: [{ target: 'build', projects: '{dependencies}' }],
}, },
['app1'], ['app1'],
['build'], ['build'],
@ -1307,8 +1338,8 @@ describe('createTaskGraph', () => {
build: { build: {
executor: 'nx:run-commands', executor: 'nx:run-commands',
dependsOn: [ dependsOn: [
{ target: 'prebuild', projects: 'self' }, { target: 'prebuild', projects: '{self}' },
{ target: 'build', projects: 'dependencies' }, { target: 'build', projects: '{dependencies}' },
], ],
}, },
prebuild: { prebuild: {

View File

@ -6,6 +6,7 @@ import {
} from '../utils/project-graph-utils'; } from '../utils/project-graph-utils';
import { Task, TaskGraph } from '../config/task-graph'; import { Task, TaskGraph } from '../config/task-graph';
import { TargetDependencies } from '../config/nx-json'; import { TargetDependencies } from '../config/nx-json';
import { TargetDependencyConfig } from '../devkit-exports';
export class ProcessTasks { export class ProcessTasks {
private readonly seen = new Set<string>(); private readonly seen = new Set<string>();
@ -104,92 +105,150 @@ export class ProcessTasks {
dependencyConfig.params === 'forward' dependencyConfig.params === 'forward'
? overrides ? overrides
: { __overrides_unparsed__: [] }; : { __overrides_unparsed__: [] };
const targetProjectSpecifiers =
typeof dependencyConfig.projects === 'string'
? [dependencyConfig.projects]
: dependencyConfig.projects;
for (const projectSpecifier of targetProjectSpecifiers) {
// Lerna uses `dependencies` in `prepNxOptions`, so we need to maintain
// support for it until lerna can be updated to use the new tokens.
// TODO(@agentender): Remove this part in v17
if (
projectSpecifier === '{dependencies}' ||
(projectSpecifier === 'dependencies' &&
!this.projectGraph.nodes[projectSpecifier])
) {
this.processTasksForDependencies(
projectUsedToDeriveDependencies,
dependencyConfig,
configuration,
task,
taskOverrides,
overrides
);
} else {
// Since we need to maintain support for dependencies, it is more coherent
// that we also support self.
// TODO(@agentender): Remove this part in v17
const projectName =
projectSpecifier === '{self}' ||
(projectSpecifier === 'self' &&
!this.projectGraph.nodes[projectSpecifier])
? task.target.project
: projectSpecifier;
if (dependencyConfig.projects === 'dependencies') { this.processTasksForSingleProject(
for (const dep of this.projectGraph.dependencies[ task,
projectUsedToDeriveDependencies projectName,
]) { dependencyConfig,
const depProject = this.projectGraph.nodes[ configuration,
dep.target taskOverrides,
] as ProjectGraphProjectNode; overrides
);
}
}
}
}
// this is to handle external dependencies private processTasksForSingleProject(
if (!depProject) continue; task: Task,
projectName: string,
dependencyConfig: TargetDependencyConfig,
configuration: string,
taskOverrides: Object | { __overrides_unparsed__: any[] },
overrides: Object
) {
const selfProject = this.projectGraph.nodes[
projectName
] as ProjectGraphProjectNode;
if (projectHasTarget(depProject, dependencyConfig.target)) { if (projectHasTarget(selfProject, dependencyConfig.target)) {
const resolvedConfiguration = this.resolveConfiguration( const resolvedConfiguration = this.resolveConfiguration(
depProject, selfProject,
dependencyConfig.target, dependencyConfig.target,
configuration configuration
); );
const depTargetId = this.getId( const selfTaskId = this.getId(
depProject.name, selfProject.name,
dependencyConfig.target, dependencyConfig.target,
resolvedConfiguration resolvedConfiguration
); );
if (task.id !== selfTaskId) {
this.dependencies[task.id].push(selfTaskId);
}
if (!this.tasks[selfTaskId]) {
const newTask = this.createTask(
selfTaskId,
selfProject,
dependencyConfig.target,
resolvedConfiguration,
taskOverrides
);
this.tasks[selfTaskId] = newTask;
this.dependencies[selfTaskId] = [];
this.processTask(
newTask,
newTask.target.project,
configuration,
overrides
);
}
}
}
if (task.id !== depTargetId) { private processTasksForDependencies(
this.dependencies[task.id].push(depTargetId); projectUsedToDeriveDependencies: string,
} dependencyConfig: TargetDependencyConfig,
if (!this.tasks[depTargetId]) { configuration: string,
const newTask = this.createTask( task: Task,
depTargetId, taskOverrides: Object | { __overrides_unparsed__: any[] },
depProject, overrides: Object
dependencyConfig.target, ) {
resolvedConfiguration, for (const dep of this.projectGraph.dependencies[
taskOverrides projectUsedToDeriveDependencies
); ]) {
this.tasks[depTargetId] = newTask; const depProject = this.projectGraph.nodes[
this.dependencies[depTargetId] = []; dep.target
] as ProjectGraphProjectNode;
this.processTask( // this is to handle external dependencies
newTask, if (!depProject) continue;
newTask.target.project,
configuration, if (projectHasTarget(depProject, dependencyConfig.target)) {
overrides const resolvedConfiguration = this.resolveConfiguration(
); depProject,
} dependencyConfig.target,
} else { configuration
this.processTask(task, depProject.name, configuration, overrides); );
} const depTargetId = this.getId(
depProject.name,
dependencyConfig.target,
resolvedConfiguration
);
if (task.id !== depTargetId) {
this.dependencies[task.id].push(depTargetId);
}
if (!this.tasks[depTargetId]) {
const newTask = this.createTask(
depTargetId,
depProject,
dependencyConfig.target,
resolvedConfiguration,
taskOverrides
);
this.tasks[depTargetId] = newTask;
this.dependencies[depTargetId] = [];
this.processTask(
newTask,
newTask.target.project,
configuration,
overrides
);
} }
} else { } else {
const selfProject = this.projectGraph.nodes[ this.processTask(task, depProject.name, configuration, overrides);
task.target.project
] as ProjectGraphProjectNode;
if (projectHasTarget(selfProject, dependencyConfig.target)) {
const resolvedConfiguration = this.resolveConfiguration(
selfProject,
dependencyConfig.target,
configuration
);
const selfTaskId = this.getId(
selfProject.name,
dependencyConfig.target,
resolvedConfiguration
);
if (task.id !== selfTaskId) {
this.dependencies[task.id].push(selfTaskId);
}
if (!this.tasks[selfTaskId]) {
const newTask = this.createTask(
selfTaskId,
selfProject,
dependencyConfig.target,
resolvedConfiguration,
taskOverrides
);
this.tasks[selfTaskId] = newTask;
this.dependencies[selfTaskId] = [];
this.processTask(
newTask,
newTask.target.project,
configuration,
overrides
);
}
}
} }
} }
} }

View File

@ -32,17 +32,26 @@ export function getDependencyConfigs(
[] []
); );
for (const dependencyConfig of dependencyConfigs) { for (const dependencyConfig of dependencyConfigs) {
if ( const specifiers =
dependencyConfig.projects !== 'dependencies' && typeof dependencyConfig.projects === 'string'
dependencyConfig.projects !== 'self' ? [dependencyConfig.projects]
) { : dependencyConfig.projects;
output.error({ for (const specifier of specifiers) {
title: `dependsOn is improperly configured for ${project}:${target}`, if (
bodyLines: [ !(specifier in projectGraph.nodes) &&
`dependsOn.projects is "${dependencyConfig.projects}" but should be "self" or "dependencies"`, // Todo(@agentender): Remove the non-token forms of these for v17
], !['{self}', '{dependencies}', 'self', 'dependencies'].includes(
}); specifier
process.exit(1); )
) {
output.error({
title: `dependsOn is improperly configured for ${project}:${target}`,
bodyLines: [
`${specifier} in dependsOn.projects is invalid. It should be "{self}", "{dependencies}", or a project name.`,
],
});
process.exit(1);
}
} }
} }
return dependencyConfigs; return dependencyConfigs;
@ -54,9 +63,9 @@ function expandDependencyConfigSyntaxSugar(
return deps.map((d) => { return deps.map((d) => {
if (typeof d === 'string') { if (typeof d === 'string') {
if (d.startsWith('^')) { if (d.startsWith('^')) {
return { projects: 'dependencies', target: d.substring(1) }; return { projects: '{dependencies}', target: d.substring(1) };
} else { } else {
return { projects: 'self', target: d }; return { projects: '{self}', target: d };
} }
} else { } else {
return d; return d;