Skip to content

Commit

Permalink
fix(core): custom generators help should print relevant information (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
meeroslav committed Oct 11, 2022
1 parent 0907ba2 commit f9e57e2
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 29 deletions.
20 changes: 14 additions & 6 deletions e2e/nx-misc/src/workspace.test.ts
Expand Up @@ -24,9 +24,7 @@ describe('Workspace Tests', () => {
proj = newProject();
});

afterAll(() => {
cleanupProject();
});
afterAll(() => cleanupProject());

describe('@nrwl/workspace:library', () => {
it('should create a library that can be tested and linted', async () => {
Expand Down Expand Up @@ -195,6 +193,10 @@ describe('Workspace Tests', () => {
type: 'boolean',
description: 'skip changes to tsconfig',
};
json.properties['inlineprop'] = json.properties['name'];
json.required = ['inlineprop'];
delete json.properties['name'];

updateFile(
`tools/generators/${custom}/schema.json`,
JSON.stringify(json)
Expand All @@ -205,10 +207,17 @@ describe('Workspace Tests', () => {
`tools/generators/${custom}/index.ts`,
indexFile.replace(
'name: schema.name',
'name: schema.name, directory: schema.directory, skipTsConfig: schema.skipTsConfig'
'name: schema.inlineprop, directory: schema.directory, skipTsConfig: schema.skipTsConfig'
)
);

const helpOutput = runCLI(`workspace-generator ${custom} --help`);
expect(helpOutput).toContain(
`workspace-generator ${custom} [inlineprop] (options)`
);
expect(helpOutput).toContain(`--directory`);
expect(helpOutput).toContain(`--skipTsConfig`);

const workspace = uniq('workspace');
const dryRunOutput = runCLI(
`workspace-generator ${custom} ${workspace} --no-interactive --directory=dir --skipTsConfig=true -d`
Expand All @@ -218,11 +227,10 @@ describe('Workspace Tests', () => {
`CREATE libs/dir/${workspace}/src/index.ts`
);

const output = runCLI(
runCLI(
`workspace-generator ${custom} ${workspace} --no-interactive --directory=dir`
);
checkFilesExist(`libs/dir/${workspace}/src/index.ts`);
expect(output).not.toContain('UPDATE nx.json');

const jsonFailing = readJson(`tools/generators/${failing}/schema.json`);
jsonFailing.properties = {};
Expand Down
144 changes: 121 additions & 23 deletions packages/nx/src/command-line/nx-commands.ts
Expand Up @@ -256,15 +256,10 @@ export const commandsObject = yargs
aliases: ['workspace-schematic [name]'],
builder: async (yargs) =>
linkToNxDevAndExamples(
await withWorkspaceGeneratorOptions(yargs),
await withWorkspaceGeneratorOptions(yargs, process.argv.slice(3)),
'workspace-generator'
),
handler: async () => {
await (
await import('./workspace-generators')
).workspaceGenerators(process.argv.slice(3));
process.exit(0);
},
handler: workspaceGeneratorHandler,
})
.command({
command: 'migrate [packageAndVersion]',
Expand Down Expand Up @@ -749,27 +744,130 @@ function withRunOneOptions(yargs: yargs.Argv) {
}
}

async function withWorkspaceGeneratorOptions(yargs: yargs.Argv) {
yargs
.option('list-generators', {
describe: 'List the available workspace-generators',
type: 'boolean',
})
.positional('name', {
type: 'string',
describe: 'The name of your generator',
});
type WorkspaceGeneratorProperties = {
[name: string]:
| {
type: yargs.Options['type'];
description?: string;
default?: any;
enum?: yargs.Options['type'][];
}
| {
type: yargs.PositionalOptionsType;
description?: string;
default?: any;
enum?: yargs.PositionalOptionsType[];
$default: {
$source: 'argv';
index: number;
};
};
};

function isPositionalProperty(
property: WorkspaceGeneratorProperties[keyof WorkspaceGeneratorProperties]
): property is { type: yargs.PositionalOptionsType } {
return property['$default']?.['$source'] === 'argv';
}

/**
* Don't require `name` if only listing available
* schematics
*/
if ((await yargs.argv).listGenerators !== true) {
yargs.demandOption('name');
async function withWorkspaceGeneratorOptions(
yargs: yargs.Argv,
args: string[]
) {
// filter out only positional arguments
args = args.filter((a) => !a.startsWith('-'));
if (args.length) {
// this is an actual workspace generator
return withCustomGeneratorOptions(yargs, args[0]);
} else {
yargs
.option('list-generators', {
describe: 'List the available workspace-generators',
type: 'boolean',
})
.positional('name', {
type: 'string',
describe: 'The name of your generator',
});
/**
* Don't require `name` if only listing available
* schematics
*/
if ((await yargs.argv).listGenerators !== true) {
yargs.demandOption('name');
}
return yargs;
}
}

async function withCustomGeneratorOptions(
yargs: yargs.Argv,
generatorName: string
) {
const schema = (
await import('./workspace-generators')
).workspaceGeneratorSchema(generatorName);
const options = [];
const positionals = [];

Object.entries(schema.properties as WorkspaceGeneratorProperties).forEach(
([name, prop]) => {
options.push({
name,
definition: {
describe: prop.description,
type: prop.type,
default: prop.default,
choices: prop.enum,
},
});
if (isPositionalProperty(prop)) {
positionals.push({
name,
definition: {
describe: prop.description,
type: prop.type,
choices: prop.enum,
},
});
}
}
);

let command = generatorName;
positionals.forEach(({ name }) => {
command += ` [${name}]`;
});
if (options.length) {
command += ' (options)';
}

yargs.command({
// this is the default and only command
command,
describe: schema.description || '',
builder: (y) => {
options.forEach(({ name, definition }) => {
y.option(name, definition);
});
positionals.forEach(({ name, definition }) => {
y.positional(name, definition);
});
return linkToNxDevAndExamples(y, 'workspace-generator');
},
handler: workspaceGeneratorHandler,
});

return yargs;
}

async function workspaceGeneratorHandler() {
await (
await import('./workspace-generators')
).workspaceGenerators(process.argv.slice(3));
process.exit(0);
}

function withMigrationOptions(yargs: yargs.Argv) {
const defaultCommitPrefix = 'chore: [nx migration] ';

Expand Down
11 changes: 11 additions & 0 deletions packages/nx/src/command-line/workspace-generators.ts
Expand Up @@ -40,6 +40,17 @@ export async function workspaceGenerators(args: string[]) {
}
}

export function workspaceGeneratorSchema(name: string) {
const schemaFile = path.join(generatorsDir, name, 'schema.json');

if (fileExists(schemaFile)) {
return readJsonFile(schemaFile);
} else {
logger.error(`Cannot find schema for ${name}. Does the generator exist?`);
process.exit(1);
}
}

// compile tools
function compileTools() {
const toolsOutDir = getToolsOutDir();
Expand Down

1 comment on commit f9e57e2

@vercel
Copy link

@vercel vercel bot commented on f9e57e2 Oct 11, 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-nrwl.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx.dev
nx-five.vercel.app

Please sign in to comment.