feat(core): support targets with colons in the name without quotes (#13938)
This commit is contained in:
parent
a04a2ea00b
commit
285dc39371
@ -1749,20 +1749,35 @@ Object the JSON content represents
|
||||
|
||||
▸ **parseTargetString**(`targetString`): [`Target`](../../devkit/documents/index#target)
|
||||
|
||||
**`deprecated(v17)`** A project graph should be passed to parseTargetString for best accuracy.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------------- | :------- |
|
||||
| `targetString` | `string` |
|
||||
|
||||
#### Returns
|
||||
|
||||
[`Target`](../../devkit/documents/index#target)
|
||||
|
||||
▸ **parseTargetString**(`targetString`, `projectGraph`): [`Target`](../../devkit/documents/index#target)
|
||||
|
||||
Parses a target string into {project, target, configuration}
|
||||
|
||||
Examples:
|
||||
|
||||
```typescript
|
||||
parseTargetString('proj:test'); // returns { project: "proj", target: "test" }
|
||||
parseTargetString('proj:test:production'); // returns { project: "proj", target: "test", configuration: "production" }
|
||||
parseTargetString('proj:test', graph); // returns { project: "proj", target: "test" }
|
||||
parseTargetString('proj:test:production', graph); // returns { project: "proj", target: "test", configuration: "production" }
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------------- | :------- | :--------------- |
|
||||
| `targetString` | `string` | target reference |
|
||||
| Name | Type | Description |
|
||||
| :------------- | :------------------------------------------------------------------ | :--------------- |
|
||||
| `targetString` | `string` | target reference |
|
||||
| `projectGraph` | [`ProjectGraph`](../../devkit/documents/index#projectgraph)<`any`\> | - |
|
||||
|
||||
#### Returns
|
||||
|
||||
|
||||
24
docs/generated/packages/devkit.json
Normal file
24
docs/generated/packages/devkit.json
Normal file
File diff suppressed because one or more lines are too long
@ -1749,20 +1749,35 @@ Object the JSON content represents
|
||||
|
||||
▸ **parseTargetString**(`targetString`): [`Target`](../../devkit/documents/index#target)
|
||||
|
||||
**`deprecated(v17)`** A project graph should be passed to parseTargetString for best accuracy.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------------- | :------- |
|
||||
| `targetString` | `string` |
|
||||
|
||||
#### Returns
|
||||
|
||||
[`Target`](../../devkit/documents/index#target)
|
||||
|
||||
▸ **parseTargetString**(`targetString`, `projectGraph`): [`Target`](../../devkit/documents/index#target)
|
||||
|
||||
Parses a target string into {project, target, configuration}
|
||||
|
||||
Examples:
|
||||
|
||||
```typescript
|
||||
parseTargetString('proj:test'); // returns { project: "proj", target: "test" }
|
||||
parseTargetString('proj:test:production'); // returns { project: "proj", target: "test", configuration: "production" }
|
||||
parseTargetString('proj:test', graph); // returns { project: "proj", target: "test" }
|
||||
parseTargetString('proj:test:production', graph); // returns { project: "proj", target: "test", configuration: "production" }
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------------- | :------- | :--------------- |
|
||||
| `targetString` | `string` | target reference |
|
||||
| Name | Type | Description |
|
||||
| :------------- | :------------------------------------------------------------------ | :--------------- |
|
||||
| `targetString` | `string` | target reference |
|
||||
| `projectGraph` | [`ProjectGraph`](../../devkit/documents/index#projectgraph)<`any`\> | - |
|
||||
|
||||
#### Returns
|
||||
|
||||
|
||||
@ -147,7 +147,10 @@ function getBuildableTarget(ctContext: ExecutorContext) {
|
||||
);
|
||||
}
|
||||
|
||||
return parseTargetString(cypressCtOptions.devServerTarget);
|
||||
return parseTargetString(
|
||||
cypressCtOptions.devServerTarget,
|
||||
ctContext.projectGraph
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeBuildTargetOptions(
|
||||
|
||||
@ -4,7 +4,11 @@ import {
|
||||
executeDevServerBuilder,
|
||||
} from '@angular-devkit/build-angular';
|
||||
import { JsonObject } from '@angular-devkit/core';
|
||||
import { joinPathFragments, parseTargetString } from '@nrwl/devkit';
|
||||
import {
|
||||
joinPathFragments,
|
||||
parseTargetString,
|
||||
readCachedProjectGraph,
|
||||
} from '@nrwl/devkit';
|
||||
import { WebpackNxBuildCoordinationPlugin } from '@nrwl/webpack/src/plugins/webpack-nx-build-coordination-plugin';
|
||||
import { DependentBuildableProjectNode } from '@nrwl/workspace/src/utilities/buildable-libs-utils';
|
||||
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';
|
||||
@ -26,7 +30,10 @@ export function executeWebpackDevServerBuilder(
|
||||
|
||||
const options = normalizeOptions(rawOptions);
|
||||
|
||||
const parsedBrowserTarget = parseTargetString(options.browserTarget);
|
||||
const parsedBrowserTarget = parseTargetString(
|
||||
options.browserTarget,
|
||||
readCachedProjectGraph()
|
||||
);
|
||||
const browserTargetProjectConfiguration = readCachedProjectConfiguration(
|
||||
parsedBrowserTarget.project
|
||||
);
|
||||
|
||||
@ -42,7 +42,7 @@ export async function* delegateBuildExecutor(
|
||||
}
|
||||
|
||||
const { buildTarget, ...targetOptions } = options;
|
||||
const delegateTarget = parseTargetString(buildTarget);
|
||||
const delegateTarget = parseTargetString(buildTarget, context.projectGraph);
|
||||
|
||||
yield* await runExecutor(delegateTarget, targetOptions, context);
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {
|
||||
createProjectGraphAsync,
|
||||
formatFiles,
|
||||
getProjects,
|
||||
parseTargetString,
|
||||
@ -21,14 +22,14 @@ export default async function convertWebpackBrowserBuildTargetToDelegateBuild(
|
||||
);
|
||||
for (const target of webpackBrowserTargets) {
|
||||
const configurationOptions = getTargetConfigurationOptions(target);
|
||||
const buildTargetName = getBuildTargetNameFromOptions(
|
||||
const buildTargetName = await getBuildTargetNameFromOptions(
|
||||
target.options,
|
||||
configurationOptions
|
||||
);
|
||||
if (buildTargetName) {
|
||||
target.executor = '@nrwl/angular:delegate-build';
|
||||
updateTargetsOptions(project, target, buildTargetName);
|
||||
updateTargetsConfigurations(
|
||||
await updateTargetsConfigurations(
|
||||
project,
|
||||
projectName,
|
||||
target,
|
||||
@ -52,14 +53,17 @@ function cleanupBuildTargetProperties(options: {
|
||||
delete options.outputPath;
|
||||
}
|
||||
|
||||
function extractConfigurationBuildTarget(
|
||||
async function extractConfigurationBuildTarget(
|
||||
project: string,
|
||||
target: string,
|
||||
configuration: string,
|
||||
buildTarget: string
|
||||
): Target {
|
||||
): Promise<Target> {
|
||||
if (buildTarget) {
|
||||
const buildTargetObj = parseTargetString(buildTarget);
|
||||
const buildTargetObj = parseTargetString(
|
||||
buildTarget,
|
||||
await createProjectGraphAsync()
|
||||
);
|
||||
return {
|
||||
...buildTargetObj,
|
||||
configuration: buildTargetObj.configuration ?? configuration,
|
||||
@ -73,16 +77,17 @@ function extractConfigurationBuildTarget(
|
||||
};
|
||||
}
|
||||
|
||||
function getBuildTargetNameFromOptions(
|
||||
async function getBuildTargetNameFromOptions(
|
||||
baseOptions: any,
|
||||
configurationOptions: Map<string, any>
|
||||
): string {
|
||||
): Promise<string> {
|
||||
const pg = await createProjectGraphAsync();
|
||||
if (baseOptions.buildTarget) {
|
||||
return parseTargetString(baseOptions.buildTarget).target;
|
||||
return parseTargetString(baseOptions.buildTarget, pg).target;
|
||||
}
|
||||
for (const [, options] of configurationOptions) {
|
||||
if (options.buildTarget) {
|
||||
return parseTargetString(options.buildTarget).target;
|
||||
return parseTargetString(options.buildTarget, pg).target;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,7 +107,7 @@ function getTargetConfigurationOptions(
|
||||
return targets;
|
||||
}
|
||||
|
||||
function updateTargetsConfigurations(
|
||||
async function updateTargetsConfigurations(
|
||||
project: ProjectConfiguration,
|
||||
projectName: string,
|
||||
target: TargetConfiguration,
|
||||
@ -113,7 +118,7 @@ function updateTargetsConfigurations(
|
||||
const { buildTarget, tsConfig, outputPath, ...delegateTargetOptions } =
|
||||
options;
|
||||
|
||||
const configurationBuildTarget = extractConfigurationBuildTarget(
|
||||
const configurationBuildTarget = await extractConfigurationBuildTarget(
|
||||
projectName,
|
||||
buildTargetName,
|
||||
configurationName,
|
||||
|
||||
@ -2,6 +2,7 @@ import { CypressExecutorOptions } from '../../executors/cypress/cypress.impl';
|
||||
import { CY_FILE_MATCHER } from '../../utils/ct-helpers';
|
||||
import { installedCypressVersion } from '../../utils/cypress-version';
|
||||
import {
|
||||
createProjectGraphAsync,
|
||||
formatFiles,
|
||||
getProjects,
|
||||
joinPathFragments,
|
||||
@ -23,6 +24,7 @@ export async function updateCyMountUsage(tree: Tree) {
|
||||
}
|
||||
|
||||
const projects = getProjects(tree);
|
||||
const graph = await createProjectGraphAsync();
|
||||
|
||||
forEachExecutorOptions<CypressExecutorOptions>(
|
||||
tree,
|
||||
@ -32,7 +34,7 @@ export async function updateCyMountUsage(tree: Tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parsed = parseTargetString(options.devServerTarget);
|
||||
const parsed = parseTargetString(options.devServerTarget, graph);
|
||||
if (!parsed?.project || !parsed?.target) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -26,7 +26,10 @@ export default async function* detoxTestExecutor(
|
||||
|
||||
try {
|
||||
if (options.buildTarget) {
|
||||
const buildTarget = parseTargetString(options.buildTarget);
|
||||
const buildTarget = parseTargetString(
|
||||
options.buildTarget,
|
||||
context.projectGraph
|
||||
);
|
||||
const buildOptions = readTargetOptions<DetoxBuildOptions>(
|
||||
buildTarget,
|
||||
context
|
||||
|
||||
@ -162,9 +162,6 @@ export { updateTsConfigsToJs } from './src/generators/update-ts-configs-to-js';
|
||||
*/
|
||||
export { visitNotIgnoredFiles } from './src/generators/visit-not-ignored-files';
|
||||
|
||||
/**
|
||||
* @category Executors
|
||||
*/
|
||||
export {
|
||||
parseTargetString,
|
||||
targetToTargetString,
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { parseTargetString, targetToTargetString } from './parse-target-string';
|
||||
|
||||
import * as splitTarget from 'nx/src/utils/split-target';
|
||||
|
||||
const cases = [
|
||||
{ input: 'one:two', expected: { project: 'one', target: 'two' } },
|
||||
{
|
||||
@ -14,7 +16,10 @@ const cases = [
|
||||
|
||||
describe('parseTargetString', () => {
|
||||
it.each(cases)('$input -> $expected', ({ input, expected }) => {
|
||||
expect(parseTargetString(input)).toEqual(expected);
|
||||
jest
|
||||
.spyOn(splitTarget, 'splitTarget')
|
||||
.mockReturnValueOnce(Object.values(expected) as [string]);
|
||||
expect(parseTargetString(input, null)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -1,19 +1,35 @@
|
||||
import type { Target } from 'nx/src/command-line/run';
|
||||
import { ProjectGraph } from 'nx/src/config/project-graph';
|
||||
import { readCachedProjectGraph } from 'nx/src/project-graph/project-graph';
|
||||
import { splitTarget } from 'nx/src/utils/split-target';
|
||||
|
||||
/**
|
||||
* @deprecated(v17) A project graph should be passed to parseTargetString for best accuracy.
|
||||
*/
|
||||
export function parseTargetString(targetString: string): Target;
|
||||
/**
|
||||
* Parses a target string into {project, target, configuration}
|
||||
*
|
||||
* Examples:
|
||||
* ```typescript
|
||||
* parseTargetString("proj:test") // returns { project: "proj", target: "test" }
|
||||
* parseTargetString("proj:test:production") // returns { project: "proj", target: "test", configuration: "production" }
|
||||
* parseTargetString("proj:test", graph) // returns { project: "proj", target: "test" }
|
||||
* parseTargetString("proj:test:production", graph) // returns { project: "proj", target: "test", configuration: "production" }
|
||||
* ```
|
||||
*
|
||||
* @param targetString - target reference
|
||||
*/
|
||||
export function parseTargetString(targetString: string): Target {
|
||||
const [project, target, configuration] = splitTarget(targetString);
|
||||
export function parseTargetString(
|
||||
targetString: string,
|
||||
projectGraph: ProjectGraph
|
||||
): Target;
|
||||
export function parseTargetString(
|
||||
targetString: string,
|
||||
projectGraph = readCachedProjectGraph()
|
||||
): Target {
|
||||
const [project, target, configuration] = splitTarget(
|
||||
targetString,
|
||||
projectGraph
|
||||
);
|
||||
if (!project || !target) {
|
||||
throw new Error(`Invalid Target String: ${targetString}`);
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ function calculateResolveMappings(
|
||||
context: ExecutorContext,
|
||||
options: NodeExecutorOptions
|
||||
) {
|
||||
const parsed = parseTargetString(options.buildTarget);
|
||||
const parsed = parseTargetString(options.buildTarget, context.projectGraph);
|
||||
const { dependencies } = calculateProjectDependencies(
|
||||
context.projectGraph,
|
||||
context.root,
|
||||
@ -198,7 +198,10 @@ async function* startBuild(
|
||||
options: NodeExecutorOptions,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const buildTarget = parseTargetString(options.buildTarget);
|
||||
const buildTarget = parseTargetString(
|
||||
options.buildTarget,
|
||||
context.projectGraph
|
||||
);
|
||||
|
||||
yield* await runExecutor<ExecutorEvent>(
|
||||
buildTarget,
|
||||
@ -216,7 +219,7 @@ function runWaitUntilTargets(
|
||||
): Promise<{ success: boolean }[]> {
|
||||
return Promise.all(
|
||||
options.waitUntilTargets.map(async (waitUntilTarget) => {
|
||||
const target = parseTargetString(waitUntilTarget);
|
||||
const target = parseTargetString(waitUntilTarget, context.projectGraph);
|
||||
const output = await runExecutor(target, {}, context);
|
||||
return new Promise<{ success: boolean }>(async (resolve) => {
|
||||
let event = await output.next();
|
||||
|
||||
@ -44,7 +44,7 @@ export default async function* serveExecutor(
|
||||
(process.env as any).PORT = options.port;
|
||||
|
||||
const buildOptions = readTargetOptions<NextBuildBuilderOptions>(
|
||||
parseTargetString(options.buildTarget),
|
||||
parseTargetString(options.buildTarget, context.projectGraph),
|
||||
context
|
||||
);
|
||||
const root = resolve(context.root, buildOptions.root);
|
||||
@ -155,7 +155,7 @@ async function* runCustomServer(
|
||||
const baseUrl = `http://${options.hostname || 'localhost'}:${options.port}`;
|
||||
|
||||
const customServerBuild = await runExecutor(
|
||||
parseTargetString(options.customServerTarget),
|
||||
parseTargetString(options.customServerTarget, context.projectGraph),
|
||||
{
|
||||
watch: true,
|
||||
},
|
||||
|
||||
@ -12,6 +12,7 @@ import { workspaceRoot } from '../utils/workspace-root';
|
||||
import { splitTarget } from '../utils/split-target';
|
||||
import { output } from '../utils/output';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
ProjectsConfigurations,
|
||||
TargetDependencyConfig,
|
||||
} from '../config/workspace-json-project-json';
|
||||
@ -35,10 +36,7 @@ export async function runOne(
|
||||
const nxJson = readNxJson();
|
||||
const projectGraph = await createProjectGraphAsync({ exitOnError: true });
|
||||
|
||||
const opts = parseRunOneOptions(cwd, args, {
|
||||
...readProjectsConfigurationFromProjectGraph(projectGraph),
|
||||
...nxJson,
|
||||
});
|
||||
const opts = parseRunOneOptions(cwd, args, projectGraph, nxJson);
|
||||
|
||||
const { nxArgs, overrides } = splitArgsIntoNxArgsAndOverrides(
|
||||
{
|
||||
@ -102,13 +100,13 @@ const targetAliases = {
|
||||
function parseRunOneOptions(
|
||||
cwd: string,
|
||||
parsedArgs: { [k: string]: any },
|
||||
workspaceConfiguration: ProjectsConfigurations & NxJsonConfiguration
|
||||
projectGraph: ProjectGraph<ProjectConfiguration>,
|
||||
nxJson: NxJsonConfiguration
|
||||
): { project; target; configuration; parsedArgs } {
|
||||
const defaultProjectName = calculateDefaultProjectName(
|
||||
cwd,
|
||||
workspaceRoot,
|
||||
workspaceConfiguration
|
||||
);
|
||||
const defaultProjectName = calculateDefaultProjectName(cwd, workspaceRoot, {
|
||||
...readProjectsConfigurationFromProjectGraph(projectGraph),
|
||||
...nxJson,
|
||||
});
|
||||
|
||||
let project;
|
||||
let target;
|
||||
@ -117,7 +115,8 @@ function parseRunOneOptions(
|
||||
if (parsedArgs['project:target:configuration'].indexOf(':') > -1) {
|
||||
// run case
|
||||
[project, target, configuration] = splitTarget(
|
||||
parsedArgs['project:target:configuration']
|
||||
parsedArgs['project:target:configuration'],
|
||||
projectGraph
|
||||
);
|
||||
// this is to account for "nx npmsript:dev"
|
||||
if (project && !target && defaultProjectName) {
|
||||
|
||||
@ -1,14 +1,56 @@
|
||||
import { ProjectGraph } from '../config/project-graph';
|
||||
import { ProjectGraphBuilder } from '../project-graph/project-graph-builder';
|
||||
import { splitTarget } from './split-target';
|
||||
|
||||
const cases = [
|
||||
{ input: 'one', expected: ['one'] },
|
||||
{ input: 'one:two', expected: ['one', 'two'] },
|
||||
{ input: 'one:two:three', expected: ['one', 'two', 'three'] },
|
||||
{ input: 'one:"two:two":three', expected: ['one', 'two:two', 'three'] },
|
||||
];
|
||||
let projectGraph: ProjectGraph;
|
||||
|
||||
describe('splitTarget', () => {
|
||||
it.each(cases)('$input -> $expected', ({ input, expected }) => {
|
||||
expect(splitTarget(input)).toEqual(expected);
|
||||
beforeAll(() => {
|
||||
let builder = new ProjectGraphBuilder();
|
||||
builder.addNode({
|
||||
name: 'project',
|
||||
data: {
|
||||
files: [],
|
||||
root: '',
|
||||
targets: {
|
||||
target: {},
|
||||
'target:target': {},
|
||||
},
|
||||
},
|
||||
type: 'app',
|
||||
});
|
||||
|
||||
projectGraph = builder.getUpdatedProjectGraph();
|
||||
});
|
||||
|
||||
it('should support only project', () => {
|
||||
expect(splitTarget('project', projectGraph)).toEqual(['project']);
|
||||
});
|
||||
|
||||
it('should project:target', () => {
|
||||
expect(splitTarget('project:target', projectGraph)).toEqual([
|
||||
'project',
|
||||
'target',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should project:target:configuration', () => {
|
||||
expect(splitTarget('project:target:configuration', projectGraph)).toEqual([
|
||||
'project',
|
||||
'target',
|
||||
'configuration',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should targets that contain colons when present in the graph', () => {
|
||||
expect(
|
||||
splitTarget('project:target:target:configuration', projectGraph)
|
||||
).toEqual(['project', 'target:target', 'configuration']);
|
||||
});
|
||||
|
||||
it('should targets that contain colons when not present in the graph but surrounded by quotes', () => {
|
||||
expect(
|
||||
splitTarget('project:"other:other":configuration', projectGraph)
|
||||
).toEqual(['project', 'other:other', 'configuration']);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,43 @@
|
||||
import { ProjectGraph } from '../config/project-graph';
|
||||
import { ProjectConfiguration } from '../config/workspace-json-project-json';
|
||||
|
||||
export function splitTarget(
|
||||
s: string
|
||||
s: string,
|
||||
projectGraph: ProjectGraph<ProjectConfiguration>
|
||||
): [project: string, target?: string, configuration?: string] {
|
||||
let [project, ...segments] = splitByColons(s);
|
||||
const validTargets = projectGraph.nodes[project]?.data?.targets;
|
||||
const validTargetNames = new Set(Object.keys(validTargets ?? {}));
|
||||
|
||||
return [project, ...groupJointSegments(segments, validTargetNames)] as [
|
||||
string,
|
||||
string?,
|
||||
string?
|
||||
];
|
||||
}
|
||||
|
||||
function groupJointSegments(segments: string[], validTargetNames: Set<string>) {
|
||||
for (
|
||||
let endingSegmentIdx = segments.length;
|
||||
endingSegmentIdx > 0;
|
||||
endingSegmentIdx--
|
||||
) {
|
||||
const potentialTargetName = segments.slice(0, endingSegmentIdx).join(':');
|
||||
if (validTargetNames.has(potentialTargetName)) {
|
||||
const configurationName =
|
||||
endingSegmentIdx < segments.length
|
||||
? segments.slice(endingSegmentIdx).join(':')
|
||||
: null;
|
||||
return configurationName
|
||||
? [potentialTargetName, configurationName]
|
||||
: [potentialTargetName];
|
||||
}
|
||||
}
|
||||
// If we can't find a segment match, keep older behaviour
|
||||
return segments;
|
||||
}
|
||||
|
||||
function splitByColons(s: string) {
|
||||
const parts = [] as string[];
|
||||
let currentPart = '';
|
||||
for (let i = 0; i < s.length; ++i) {
|
||||
@ -17,5 +54,5 @@ export function splitTarget(
|
||||
}
|
||||
}
|
||||
parts.push(currentPart);
|
||||
return parts as [string, string?, string?];
|
||||
return parts as [string, ...string[]];
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ function buildTargetWebpack(
|
||||
buildTarget: string,
|
||||
componentTestingProjectName: string
|
||||
) {
|
||||
const parsed = parseTargetString(buildTarget);
|
||||
const parsed = parseTargetString(buildTarget, graph);
|
||||
|
||||
const buildableProjectConfig = graph.nodes[parsed.project]?.data;
|
||||
const ctProjectConfig = graph.nodes[componentTestingProjectName]?.data;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import {
|
||||
createProjectGraphAsync,
|
||||
ensurePackage,
|
||||
generateFiles,
|
||||
joinPathFragments,
|
||||
logger,
|
||||
parseTargetString,
|
||||
ProjectConfiguration,
|
||||
readCachedProjectGraph,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
visitNotIgnoredFiles,
|
||||
@ -33,7 +35,7 @@ export async function addFiles(
|
||||
tree.delete(cypressConfigPath);
|
||||
}
|
||||
|
||||
const actualBundler = getBundler(found, tree);
|
||||
const actualBundler = await getBundler(found, tree);
|
||||
|
||||
if (options.bundler && options.bundler !== actualBundler) {
|
||||
logger.warn(
|
||||
@ -76,12 +78,18 @@ export async function addFiles(
|
||||
}
|
||||
}
|
||||
|
||||
function getBundler(found: FoundTarget, tree: Tree): 'vite' | 'webpack' {
|
||||
async function getBundler(
|
||||
found: FoundTarget,
|
||||
tree: Tree
|
||||
): Promise<'vite' | 'webpack'> {
|
||||
if (found.target && found.config?.executor) {
|
||||
return found.config.executor === '@nrwl/vite:build' ? 'vite' : 'webpack';
|
||||
}
|
||||
|
||||
const { target, project } = parseTargetString(found.target);
|
||||
const { target, project } = parseTargetString(
|
||||
found.target,
|
||||
await createProjectGraphAsync()
|
||||
);
|
||||
const projectConfig = readProjectConfiguration(tree, project);
|
||||
return projectConfig?.targets?.[target]?.executor === '@nrwl/vite:build'
|
||||
? 'vite'
|
||||
|
||||
@ -107,7 +107,7 @@ export async function configurationGenerator(
|
||||
);
|
||||
}
|
||||
|
||||
const e2eProject = getE2EProjectName(tree, schema.name);
|
||||
const e2eProject = await getE2EProjectName(tree, schema.name);
|
||||
if (schema.configureCypress && !e2eProject) {
|
||||
const cypressTask = await cypressProjectGenerator(tree, {
|
||||
name: schema.name,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {
|
||||
createProjectGraphAsync,
|
||||
generateFiles,
|
||||
getProjects,
|
||||
joinPathFragments,
|
||||
logger,
|
||||
offsetFromRoot,
|
||||
@ -537,11 +537,12 @@ export function rootFileIsTs(
|
||||
}
|
||||
}
|
||||
|
||||
export function getE2EProjectName(
|
||||
export async function getE2EProjectName(
|
||||
tree: Tree,
|
||||
mainProject: string
|
||||
): string | undefined {
|
||||
): Promise<string | undefined> {
|
||||
let e2eProject: string;
|
||||
const graph = await createProjectGraphAsync();
|
||||
forEachExecutorOptions(
|
||||
tree,
|
||||
'@nrwl/cypress:cypress',
|
||||
@ -551,7 +552,8 @@ export function getE2EProjectName(
|
||||
}
|
||||
if (options['devServerTarget']) {
|
||||
const { project, target } = parseTargetString(
|
||||
options['devServerTarget']
|
||||
options['devServerTarget'],
|
||||
graph
|
||||
);
|
||||
if (
|
||||
(project === mainProject && target === 'serve') ||
|
||||
|
||||
@ -97,7 +97,7 @@ export function getBuildTargetOptions(
|
||||
buildTarget: string,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const target = parseTargetString(buildTarget);
|
||||
const target = parseTargetString(buildTarget, context.projectGraph);
|
||||
return readTargetOptions(target, context);
|
||||
}
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ function getBuildTargetOutputPath(options: Schema, context: ExecutorContext) {
|
||||
|
||||
let buildOptions;
|
||||
try {
|
||||
const target = parseTargetString(options.buildTarget);
|
||||
const target = parseTargetString(options.buildTarget, context.projectGraph);
|
||||
buildOptions = readTargetOptions(target, context);
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid buildTarget: ${options.buildTarget}`);
|
||||
|
||||
@ -93,7 +93,7 @@ function getBuildOptions(
|
||||
options: WebDevServerOptions,
|
||||
context: ExecutorContext
|
||||
): WebpackExecutorOptions {
|
||||
const target = parseTargetString(options.buildTarget);
|
||||
const target = parseTargetString(options.buildTarget, context.projectGraph);
|
||||
|
||||
const overrides: Partial<WebpackExecutorOptions> = {
|
||||
watch: false,
|
||||
|
||||
@ -15,8 +15,14 @@ export async function* ssrDevServerExecutor(
|
||||
options: WebSsrDevServerOptions,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const browserTarget = parseTargetString(options.browserTarget);
|
||||
const serverTarget = parseTargetString(options.serverTarget);
|
||||
const browserTarget = parseTargetString(
|
||||
options.browserTarget,
|
||||
context.projectGraph
|
||||
);
|
||||
const serverTarget = parseTargetString(
|
||||
options.serverTarget,
|
||||
context.projectGraph
|
||||
);
|
||||
const browserOptions = readTargetOptions<WebpackExecutorOptions>(
|
||||
browserTarget,
|
||||
context
|
||||
|
||||
@ -65,9 +65,8 @@ describe('checkTargets', () => {
|
||||
});
|
||||
|
||||
it('should throw an error if another project targets', async () => {
|
||||
expect(() => {
|
||||
checkTargets(tree, schema);
|
||||
}).toThrowErrorMatchingInlineSnapshot(`
|
||||
await expect(checkTargets(tree, schema)).rejects
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"ng-app is still targeted by some projects:
|
||||
|
||||
\\"ng-app:serve\\" is used by \\"ng-app-e2e\\"
|
||||
@ -78,25 +77,19 @@ describe('checkTargets', () => {
|
||||
it('should NOT throw an error if no other project targets', async () => {
|
||||
schema.projectName = 'ng-app-e2e';
|
||||
|
||||
expect(() => {
|
||||
checkTargets(tree, schema);
|
||||
}).not.toThrow();
|
||||
await expect(checkTargets(tree, schema)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('should NOT throw an error if it is a nrwl package', async () => {
|
||||
schema.projectName = 'storybook';
|
||||
|
||||
expect(() => {
|
||||
checkTargets(tree, schema);
|
||||
}).not.toThrow();
|
||||
await expect(checkTargets(tree, schema)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not error if forceRemove is true', async () => {
|
||||
schema.forceRemove = true;
|
||||
|
||||
expect(() => {
|
||||
checkTargets(tree, schema);
|
||||
}).not.toThrow();
|
||||
await expect(checkTargets(tree, schema)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
describe('use project in other project target', () => {
|
||||
@ -122,9 +115,7 @@ describe('checkTargets', () => {
|
||||
it('should throw an error since it is used as a target in another project', async () => {
|
||||
schema.projectName = 'storybook';
|
||||
|
||||
expect(() => {
|
||||
checkTargets(tree, schema);
|
||||
}).toThrow();
|
||||
await expect(checkTargets(tree, schema)).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {
|
||||
createProjectGraphAsync,
|
||||
getProjects,
|
||||
parseTargetString,
|
||||
TargetConfiguration,
|
||||
@ -13,11 +14,12 @@ import { Schema } from '../schema';
|
||||
*
|
||||
* @param schema The options provided to the schematic
|
||||
*/
|
||||
export function checkTargets(tree: Tree, schema: Schema) {
|
||||
export async function checkTargets(tree: Tree, schema: Schema) {
|
||||
if (schema.forceRemove) {
|
||||
return;
|
||||
}
|
||||
|
||||
const graph = await createProjectGraphAsync();
|
||||
const errors: string[] = [];
|
||||
|
||||
getProjects(tree).forEach((projectConfig, projectName) => {
|
||||
@ -27,7 +29,7 @@ export function checkTargets(tree: Tree, schema: Schema) {
|
||||
Object.entries(projectConfig.targets || {}).forEach(([, targetConfig]) => {
|
||||
checkIfProjectIsUsed(targetConfig, (value) => {
|
||||
try {
|
||||
const { project } = parseTargetString(value);
|
||||
const { project } = parseTargetString(value, graph);
|
||||
if (project === schema.projectName) {
|
||||
errors.push(`"${value}" is used by "${projectName}"`);
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ import { updateJestConfig } from './lib/update-jest-config';
|
||||
export async function removeGenerator(tree: Tree, schema: Schema) {
|
||||
const project = readProjectConfiguration(tree, schema.projectName);
|
||||
await checkDependencies(tree, schema);
|
||||
checkTargets(tree, schema);
|
||||
await checkTargets(tree, schema);
|
||||
updateJestConfig(tree, schema, project);
|
||||
removeProjectConfig(tree, schema);
|
||||
removeProject(tree, project);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user