Skip to content

Commit

Permalink
feat(core): update create-nx-plugin to generate cli library
Browse files Browse the repository at this point in the history
  • Loading branch information
xiongemi committed Mar 31, 2023
1 parent 4d0bb6f commit d63ee15
Show file tree
Hide file tree
Showing 15 changed files with 244 additions and 90 deletions.
9 changes: 9 additions & 0 deletions e2e/nx-plugin/src/nx-plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,4 +426,13 @@ describe('Nx Plugin', () => {
`dist/libs/${createAppName}/bin/index.js`
);
});

it('should throw an error when run create-package for an invalid plugin ', async () => {
const plugin = uniq('plugin');
expect(() =>
runCLI(
`generate @nrwl/nx-plugin:create-package ${plugin} --project=invalid-plugin`
)
).toThrow();
});
});
9 changes: 6 additions & 3 deletions e2e/workspace-create/src/create-nx-plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ describe('create-nx-plugin', () => {

afterEach(() => cleanupProject());

// TODO: Re-enable to work with pnpm
xit('should be able to create a plugin repo and run plugin e2e', () => {
it('should be able to create a plugin repo and run plugin e2e', () => {
const wsName = uniq('ws-plugin');
const pluginName = uniq('plugin');

Expand All @@ -27,9 +26,13 @@ describe('create-nx-plugin', () => {
'package.json',
packageManagerLockFile[packageManager],
`packages/${pluginName}/package.json`,
`packages/${pluginName}/project.json`
`packages/${pluginName}/project.json`,
`packages/create-${pluginName}-package/package.json`,
`packages/create-${pluginName}-package/project.json`
);

expect(() => runCLI(`build ${pluginName}`)).not.toThrow();
expect(() => runCLI(`build create-${pluginName}-package`)).not.toThrow();
expect(() => runCLI(`e2e ${pluginName}-e2e`)).not.toThrow();
});
});
148 changes: 79 additions & 69 deletions packages/create-nx-plugin/bin/create-nx-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,18 @@ import {
detectInvokedPackageManager,
PackageManager,
} from './detect-invoked-package-manager';
import enquirer = require('enquirer');
import * as enquirer from 'enquirer';
import yargsParser = require('yargs-parser');

const nxVersion = require('../package.json').version;
const tsVersion = 'TYPESCRIPT_VERSION'; // This gets replaced with the typescript version in the root package.json during build
const prettierVersion = 'PRETTIER_VERSION'; // This gets replaced with the prettier version in the root package.json during build

const parsedArgs = yargsParser(process.argv, {
string: ['pluginName', 'packageManager', 'importPath'],
const parsedArgs: yargsParser.Arguments = yargsParser(process.argv, {
string: ['pluginName', 'packageManager', 'importPath', 'createPackageName'],
alias: {
importPath: 'import-path',
pluginName: 'plugin-name',
packageManager: 'pm',
createPackageName: 'create-package-name',
},
boolean: ['help'],
});
Expand All @@ -41,8 +40,6 @@ function createSandbox(packageManager: string) {
dependencies: {
'@nrwl/workspace': nxVersion,
nx: nxVersion,
typescript: tsVersion,
prettier: prettierVersion,
},
license: 'MIT',
});
Expand All @@ -55,7 +52,7 @@ function createSandbox(packageManager: string) {
return tmpDir;
}

function createWorkspace(
function createEmptyWorkspace(
tmpDir: string,
packageManager: PackageManager,
parsedArgs: any,
Expand Down Expand Up @@ -92,17 +89,25 @@ function createWorkspace(
}

function createNxPlugin(
workspaceName,
pluginName,
packageManager,
parsedArgs: any
workspaceName: string,
pluginName: string,
packageManager: PackageManager,
createPackageName: string,
parsedArgs: yargsParser.Arguments
) {
const pmc = getPackageManagerCommand(packageManager);

const importPath = parsedArgs.importPath ?? `@${workspaceName}/${pluginName}`;
const command = `nx generate @nrwl/nx-plugin:plugin ${pluginName} --importPath=${importPath}`;
console.log(command);
const generatePluginCommand = `nx generate @nrwl/nx-plugin:plugin ${pluginName} --importPath=${importPath}`;
console.log(generatePluginCommand);
execSync(`${pmc.exec} ${generatePluginCommand}`, {
cwd: workspaceName,
stdio: [0, 1, 2],
});

const pmc = getPackageManagerCommand(packageManager);
execSync(`${pmc.exec} ${command}`, {
const createPackageCommand = `nx generate @nrwl/nx-plugin:create-package ${createPackageName} --project=${pluginName}`;
console.log(createPackageCommand);
execSync(`${pmc.exec} ${createPackageCommand}`, {
cwd: workspaceName,
stdio: [0, 1, 2],
});
Expand All @@ -123,56 +128,52 @@ function updateWorkspace(workspaceName: string) {
rmSync(path.join(workspaceName, 'libs'), { recursive: true, force: true });
}

function determineWorkspaceName(parsedArgs: any): Promise<string> {
const workspaceName: string = parsedArgs._[2];
async function determineWorkspaceName(
parsedArgs: yargsParser.Arguments
): Promise<string> {
const workspaceName = parsedArgs._[2] as string;

if (workspaceName) {
return Promise.resolve(workspaceName);
}

return enquirer
.prompt([
{
name: 'WorkspaceName',
message: `Workspace name (e.g., org name) `,
type: 'input',
},
])
.then((a: { WorkspaceName: string }) => {
if (!a.WorkspaceName) {
output.error({
title: 'Invalid workspace name',
bodyLines: [`Workspace name cannot be empty`],
});
process.exit(1);
}
return a.WorkspaceName;
const results = await enquirer.prompt<{ workspaceName: string }>([
{
name: 'workspaceName',
message: `Workspace name (e.g., org name) `,
type: 'input',
},
]);
if (!results.workspaceName) {
output.error({
title: 'Invalid workspace name',
bodyLines: [`Workspace name cannot be empty`],
});
process.exit(1);
}
return results.workspaceName;
}

function determinePluginName(parsedArgs) {
async function determinePluginName(parsedArgs) {
if (parsedArgs.pluginName) {
return Promise.resolve(parsedArgs.pluginName);
}

return enquirer
.prompt([
{
name: 'PluginName',
message: `Plugin name `,
type: 'input',
},
])
.then((a: { PluginName: string }) => {
if (!a.PluginName) {
output.error({
title: 'Invalid name',
bodyLines: [`Name cannot be empty`],
});
process.exit(1);
}
return a.PluginName;
const results = await enquirer.prompt<{ pluginName: string }>([
{
name: 'pluginName',
message: `Plugin name `,
type: 'input',
},
]);
if (!results.pluginName) {
output.error({
title: 'Invalid name',
bodyLines: [`Name cannot be empty`],
});
process.exit(1);
}
return results.pluginName;
}

function showHelp() {
Expand All @@ -191,21 +192,30 @@ function showHelp() {
`);
}

if (parsedArgs.help) {
showHelp();
process.exit(0);
export async function main() {
if (parsedArgs.help) {
showHelp();
process.exit(0);
}

const packageManager: PackageManager =
parsedArgs.packageManager || detectInvokedPackageManager();
const workspaceName = await determineWorkspaceName(parsedArgs);
const pluginName = await determinePluginName(parsedArgs);
const createPackageName =
parsedArgs.createPackageName || `create-${pluginName}-package`;
const tmpDir = createSandbox(packageManager);
createEmptyWorkspace(tmpDir, packageManager, parsedArgs, workspaceName);
updateWorkspace(workspaceName);
createNxPlugin(
workspaceName,
pluginName,
packageManager,
createPackageName,
parsedArgs
);
await initializeGitRepo(workspaceName);
showNxWarning(workspaceName);
}

const packageManager: PackageManager =
parsedArgs.packageManager || detectInvokedPackageManager();
determineWorkspaceName(parsedArgs).then((workspaceName) => {
return determinePluginName(parsedArgs).then((pluginName) => {
const tmpDir = createSandbox(packageManager);
createWorkspace(tmpDir, packageManager, parsedArgs, workspaceName);
updateWorkspace(workspaceName);
createNxPlugin(workspaceName, pluginName, packageManager, parsedArgs);
return initializeGitRepo(workspaceName).then(() => {
showNxWarning(workspaceName);
});
});
});
main();
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface CreateWorkspaceOptions {
name: string; // Workspace name (e.g. org name)
packageManager: PackageManager; // Package manager to use
nxCloud: boolean; // Enable Nx Cloud
preset: string; // Preset to use
/**
* @description Enable interactive mode with presets
* @default true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@ import { isKnownPreset } from './preset';
/**
* This function is used to check if a preset is a third party preset.
* @param preset
* @returns null if the preset is a known Nx preset or preset does not exist, the normalized preset otherwise.
* @returns null if the preset is a known Nx preset or preset does not exist, the package name of preset otherwise.
*/
export async function getThirdPartyPreset(
preset?: string
): Promise<string | null> {
if (preset && !isKnownPreset(preset)) {
// extract the package name from the preset
const packageName = preset.match(/.+@/)
? preset[0] + preset.substring(1).split('@')[0]
: preset;
const validateResult = validateNpmPackage(packageName);
if (validateResult.validForNewPackages) {
return Promise.resolve(preset);
return Promise.resolve(packageName);
} else {
//! Error here
output.error({
Expand Down
Empty file removed packages/nx-plugin/index.ts
Empty file.
47 changes: 47 additions & 0 deletions packages/nx-plugin/src/generators/create-package/create-package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,19 @@ export async function createPackageGenerator(
);

await createCliPackage(host, options, pluginPackageName);
addTestsToE2eProject(host, options, pluginPackageName);

await formatFiles(host);

return installTask;
}

/**
* Add a preset generator to the plugin if it doesn't exist
* @param host
* @param schema
* @returns package name of the plugin
*/
async function addPresetGenerator(
host: Tree,
schema: NormalizedSchema
Expand Down Expand Up @@ -80,6 +87,11 @@ async function createCliPackage(
packageJson.bin = {
[options.name]: './bin/index.js',
};
packageJson.dependencies = {
'create-nx-workspace': nxVersion,
enquirer: enquirerVersion,
yargs: yargsVersion,
};
host.write(packageJsonPath, JSON.stringify(packageJson));

// update project build target to use the bin entry
Expand All @@ -92,6 +104,8 @@ async function createCliPackage(
options.projectRoot,
'bin/index.ts'
);
projectConfiguration.targets.build.options.buildableProjectDepsInPackageJsonType =
'dependencies';
updateProjectConfiguration(host, options.projectName, projectConfiguration);

// Add bin files to tsconfg.lib.json
Expand All @@ -112,6 +126,39 @@ async function createCliPackage(
);
}

/**
* Add a test file to plugin e2e project
* @param host
* @param options
* @returns
*/
function addTestsToE2eProject(
host: Tree,
options: NormalizedSchema,
pluginPackageName: string
) {
try {
const pluginE2eProjectName = `${options.project}-e2e`;
const projectConfiguration = readProjectConfiguration(
host,
pluginE2eProjectName
);
generateFiles(
host,
join(__dirname, './files/e2e'),
projectConfiguration.sourceRoot,
{
...options,
preset: pluginPackageName,
tmpl: '',
}
);
} catch (e) {
// if e2e project does not exist, do not add tests
return;
}
}

export default createPackageGenerator;
export const createPackageSchematic = convertNxGenerator(
createPackageGenerator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ export const commandsObject: yargs.Argv<Options> = yargs
.command(
// this is the default and only command
'$0 [name] [options]',
'Create a new Nx workspace',
'Create a new <%= preset %> workspace',
(yargs) =>
yargs
.options('preset', {
describe: 'Preset to use',
type: 'string',
})
.option('name', {
describe: 'What is the name of your workspace?',
type: 'string',
Expand Down Expand Up @@ -85,7 +89,10 @@ async function normalizeArgsMiddleware(argv: yargs.Arguments<Options>) {
}

async function main(options: Options) {
await createWorkspace<Options>('<%= preset %>', options);
// Update below to customize the workspace
await createWorkspace<Options>(options.preset ?? '<%= preset %>', options);

console.log(`Successfully created the <%= preset %> workspace: ${options.name}.`);
console.log(
`Successfully created the <%= preset %> workspace: ${options.name}.`
);
}
Loading

0 comments on commit d63ee15

Please sign in to comment.