Skip to content

Commit

Permalink
feat(core): add metagenerator for convert-to-inferred
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKless committed Aug 28, 2024
1 parent 2c0a50c commit 097b85d
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 9 deletions.
8 changes: 8 additions & 0 deletions docs/generated/manifests/menus.json
Original file line number Diff line number Diff line change
Expand Up @@ -10239,6 +10239,14 @@
"children": [],
"isExternal": false,
"disableCollapsible": false
},
{
"id": "convert-to-inferred",
"path": "/nx-api/workspace/generators/convert-to-inferred",
"name": "convert-to-inferred",
"children": [],
"isExternal": false,
"disableCollapsible": false
}
],
"isExternal": false,
Expand Down
9 changes: 9 additions & 0 deletions docs/generated/manifests/nx-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -3423,6 +3423,15 @@
"originalFilePath": "/packages/workspace/src/generators/ci-workflow/schema.json",
"path": "/nx-api/workspace/generators/ci-workflow",
"type": "generator"
},
"/nx-api/workspace/generators/convert-to-inferred": {
"description": "convert-to-inferred generator",
"file": "generated/packages/workspace/generators/convert-to-inferred.json",
"hidden": false,
"name": "convert-to-inferred",
"originalFilePath": "/packages/workspace/src/generators/convert-to-inferred/schema.json",
"path": "/nx-api/workspace/generators/convert-to-inferred",
"type": "generator"
}
},
"path": "/nx-api/workspace"
Expand Down
9 changes: 9 additions & 0 deletions docs/generated/packages-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -3387,6 +3387,15 @@
"originalFilePath": "/packages/workspace/src/generators/ci-workflow/schema.json",
"path": "workspace/generators/ci-workflow",
"type": "generator"
},
{
"description": "convert-to-inferred generator",
"file": "generated/packages/workspace/generators/convert-to-inferred.json",
"hidden": false,
"name": "convert-to-inferred",
"originalFilePath": "/packages/workspace/src/generators/convert-to-inferred/schema.json",
"path": "workspace/generators/convert-to-inferred",
"type": "generator"
}
],
"githubRoot": "https://github.com/nrwl/nx/blob/master",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "convert-to-inferred",
"factory": "./src/generators/convert-to-inferred/generator",
"schema": {
"$schema": "https://json-schema.org/schema",
"$id": "ConvertToInferred",
"title": "",
"type": "object",
"properties": {
"project": {
"type": "string",
"description": "The project to convert to use inferred targets.",
"x-priority": "important"
},
"exclude": {
"type": "array",
"description": "List of plugins whose convert-to-inferred generators should not be run.",
"items": { "type": "string" }
},
"skipFormat": {
"type": "boolean",
"description": "Whether to format files.",
"default": false
}
},
"presets": []
},
"description": "convert-to-inferred generator",
"implementation": "/packages/workspace/src/generators/convert-to-inferred/generator.ts",
"aliases": [],
"hidden": false,
"path": "/packages/workspace/src/generators/convert-to-inferred/schema.json",
"type": "generator"
}
1 change: 1 addition & 0 deletions docs/shared/reference/sitemap.md
Original file line number Diff line number Diff line change
Expand Up @@ -743,3 +743,4 @@
- [fix-configuration](/nx-api/workspace/generators/fix-configuration)
- [npm-package](/nx-api/workspace/generators/npm-package)
- [ci-workflow](/nx-api/workspace/generators/ci-workflow)
- [convert-to-inferred](/nx-api/workspace/generators/convert-to-inferred)
4 changes: 2 additions & 2 deletions packages/devkit/src/generators/project-name-and-root-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ async function determineFormat(
}

const result = await prompt<{ format: ProjectNameAndRootFormat }>({
type: 'select',
type: 'array',
name: 'format',
message:
'What should be the project name and where should it be generated?',
Expand All @@ -171,7 +171,7 @@ async function determineFormat(
},
],
initial: 0,
}).then(({ format }) =>
} as any).then(({ format }) =>
format === asProvidedSelectedValue ? 'as-provided' : 'derived'
);

Expand Down
16 changes: 9 additions & 7 deletions packages/nx/src/command-line/generate/generator-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,22 @@ import {
import { readJsonFile } from '../../utils/fileutils';
import { readPluginPackageJson } from '../../project-graph/plugins';

export function getGeneratorInformation(
collectionName: string,
generatorName: string,
root: string | null,
projects: Record<string, ProjectConfiguration>
): {
export type GeneratorInformation = {
resolvedCollectionName: string;
normalizedGeneratorName: string;
schema: any;
implementationFactory: () => Generator<unknown>;
isNgCompat: boolean;
isNxGenerator: boolean;
generatorConfiguration: GeneratorsJsonEntry;
} {
};

export function getGeneratorInformation(
collectionName: string,
generatorName: string,
root: string | null,
projects: Record<string, ProjectConfiguration>
): GeneratorInformation {
try {
const {
generatorsFilePath,
Expand Down
5 changes: 5 additions & 0 deletions packages/workspace/generators.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
"factory": "./src/generators/ci-workflow/ci-workflow#ciWorkflowGenerator",
"schema": "./src/generators/ci-workflow/schema.json",
"description": "Generate a CI workflow."
},
"convert-to-inferred": {
"factory": "./src/generators/convert-to-inferred/generator",
"schema": "./src/generators/convert-to-inferred/schema.json",
"description": "convert-to-inferred generator"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const variable = "<%= name %>";
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Tree, readProjectConfiguration } from '@nx/devkit';

import { convertToInferredGenerator } from './generator';
import { ConvertToInferredGeneratorSchema } from './schema';

describe('convert-to-inferred generator', () => {
let tree: Tree;
const options: ConvertToInferredGeneratorSchema = { name: 'test' };

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});

it('should run successfully', async () => {
await convertToInferredGenerator(tree, options);
const config = readProjectConfiguration(tree, 'test');
expect(config).toBeDefined();
});
});
159 changes: 159 additions & 0 deletions packages/workspace/src/generators/convert-to-inferred/generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import {
createProjectGraphAsync,
output,
readNxJson,
readProjectsConfigurationFromProjectGraph,
Tree,
workspaceRoot,
} from '@nx/devkit';
import { prompt } from 'enquirer';
import {
GeneratorInformation,
getGeneratorInformation,
} from 'nx/src/command-line/generate/generator-utils';
import { findInstalledPlugins } from 'nx/src/utils/plugins/installed-plugins';

interface Schema {
project?: string;
skipFormat?: boolean;
exclude?: string[];
}

export async function convertToInferredGenerator(tree: Tree, options: Schema) {
const generatorChoices = await getPossibleConvertToInferredGenerators(
options
);

const result = (
await prompt<{ generatorsToRun: string[] }>({
type: 'multiselect',
name: 'generatorsToRun',
message: 'Which convert-to-inferred generators should be run?',
choices: Array.from(generatorChoices.keys()),
initial: getInitialGeneratorChoices(generatorChoices, tree, options),
validate: (result: string[]) => {
if (result.length === 0) {
return 'Please select at least one convert-to-inferred generator to run';
}
return true;
},
} as any)
).generatorsToRun;

if (result.length === 0) {
output.error({
title: 'Please select at least one convert-to-inferred generator to run',
});
return;
}

for (const generatorName of result) {
output.log({
title: `Running ${generatorName}`,
});
try {
const generator = generatorChoices.get(generatorName);
if (generator) {
const generatorFactory = generator.implementationFactory();
await generatorFactory(tree, {
project: options.project,
skipFormat: options.skipFormat,
});
}
} catch (e) {
const collection =
generatorChoices.get(generatorName)?.resolvedCollectionName;
output.error({
title: `Failed to run ${generatorName}`,
bodyLines: [
e,
`To rerun this generator without the ${generatorName} generator, use nx g @nx/workspace:convert-to-inferred ${
options.project ? `--project=${options.project}` : ''
} --exclude=${
options.exclude
? [...options.exclude, collection].join(', ')
: collection
}`,
],
});
return;
}
}
}

async function getPossibleConvertToInferredGenerators(options: Schema) {
const installedCollections = Array.from(
new Set(findInstalledPlugins().map((x) => x.name))
);

const projectGraph = await createProjectGraphAsync();
const projectsConfigurations =
readProjectsConfigurationFromProjectGraph(projectGraph);

const choices = new Map<string, GeneratorInformation>();

for (const collectionName of installedCollections) {
try {
const generator = getGeneratorInformation(
collectionName,
'convert-to-inferred',
workspaceRoot,
projectsConfigurations.projects
);
if (
generator.generatorConfiguration.hidden ||
generator.generatorConfiguration['x-deprecated'] ||
options.exclude?.includes(generator.resolvedCollectionName)
) {
continue;
}
const generatorName = `${generator.resolvedCollectionName}:${generator.normalizedGeneratorName}`;
if (generatorName === '@nx/workspace:convert-to-inferred') {
continue;
}
choices.set(generatorName, generator);
} catch {
// this just means that no convert-to-inferred generator exists for a given collection, ignore
}
}

return choices;
}

function getInitialGeneratorChoices(
choices: Map<string, GeneratorInformation>,
tree: Tree,
options: Schema
) {
// if a project is specified, we assume the user wants fine-grained contorl over which generators to run
// in this case we won't include any generators by default
if (options.project) {
return [];
}
// we want to exclude generators from the default if they already have a plugin registered in nx.json
// in that case, they're probably already using inferred targets
const nxJson = readNxJson(tree);

const collectionsWithRegisteredPlugins: Set<string> = new Set();

for (const plugin of nxJson.plugins ?? []) {
if (typeof plugin === 'object') {
collectionsWithRegisteredPlugins.add(
plugin.plugin.replace('/plugin', '')
);
}
}

const initialChoices = new Set();
for (const [generatorName, generator] of choices) {
if (
!collectionsWithRegisteredPlugins.has(generator.resolvedCollectionName)
) {
initialChoices.add(generatorName);
}
}

return Array.from(initialChoices);
}

export default convertToInferredGenerator;
25 changes: 25 additions & 0 deletions packages/workspace/src/generators/convert-to-inferred/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$schema": "https://json-schema.org/schema",
"$id": "ConvertToInferred",
"title": "",
"type": "object",
"properties": {
"project": {
"type": "string",
"description": "The project to convert to use inferred targets.",
"x-priority": "important"
},
"exclude": {
"type": "array",
"description": "List of plugins whose convert-to-inferred generators should not be run.",
"items": {
"type": "string"
}
},
"skipFormat": {
"type": "boolean",
"description": "Whether to format files.",
"default": false
}
}
}

0 comments on commit 097b85d

Please sign in to comment.