feat(nx-plugin): reuse utilities from create-nx-workspace for create-nx-plugin (#15743)
This commit is contained in:
parent
39646cfa9a
commit
6e7234c1aa
@ -8,7 +8,8 @@
|
||||
"plugins": ["@typescript-eslint", "@nrwl/nx"],
|
||||
"extends": [],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off"
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"no-restricted-imports": ["error", "create-nx-workspace"]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
|
||||
@ -5512,6 +5512,14 @@
|
||||
"children": [],
|
||||
"isExternal": false,
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"id": "preset",
|
||||
"path": "/packages/nx-plugin/generators/preset",
|
||||
"name": "preset",
|
||||
"children": [],
|
||||
"isExternal": false,
|
||||
"disableCollapsible": false
|
||||
}
|
||||
],
|
||||
"isExternal": false,
|
||||
|
||||
@ -1964,6 +1964,15 @@
|
||||
"originalFilePath": "/packages/nx-plugin/src/generators/lint-checks/schema.json",
|
||||
"path": "/packages/nx-plugin/generators/plugin-lint-checks",
|
||||
"type": "generator"
|
||||
},
|
||||
"/packages/nx-plugin/generators/preset": {
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-workspace --preset @nrwl/nx-plugin`.",
|
||||
"file": "generated/packages/nx-plugin/generators/preset.json",
|
||||
"hidden": true,
|
||||
"name": "preset",
|
||||
"originalFilePath": "/packages/nx-plugin/src/generators/preset/schema.json",
|
||||
"path": "/packages/nx-plugin/generators/preset",
|
||||
"type": "generator"
|
||||
}
|
||||
},
|
||||
"path": "/packages/nx-plugin"
|
||||
|
||||
@ -1939,6 +1939,15 @@
|
||||
"originalFilePath": "/packages/nx-plugin/src/generators/lint-checks/schema.json",
|
||||
"path": "nx-plugin/generators/plugin-lint-checks",
|
||||
"type": "generator"
|
||||
},
|
||||
{
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-workspace --preset @nrwl/nx-plugin`.",
|
||||
"file": "generated/packages/nx-plugin/generators/preset.json",
|
||||
"hidden": true,
|
||||
"name": "preset",
|
||||
"originalFilePath": "/packages/nx-plugin/src/generators/preset/schema.json",
|
||||
"path": "nx-plugin/generators/preset",
|
||||
"type": "generator"
|
||||
}
|
||||
],
|
||||
"githubRoot": "https://github.com/nrwl/nx/blob/master",
|
||||
|
||||
28
docs/generated/packages/nx-plugin/generators/preset.json
Normal file
28
docs/generated/packages/nx-plugin/generators/preset.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "preset",
|
||||
"factory": "./src/generators/preset/generator",
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"cli": "nx",
|
||||
"$id": "NxPluginPreset",
|
||||
"title": "Generator ran by create-nx-plugin",
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-plugin` or `create-nx-workspace --preset @nrwl/nx-plugin`.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pluginName": {
|
||||
"type": "string",
|
||||
"description": "Plugin name",
|
||||
"aliases": ["name"]
|
||||
}
|
||||
},
|
||||
"required": ["pluginName"],
|
||||
"presets": []
|
||||
},
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-workspace --preset @nrwl/nx-plugin`.",
|
||||
"hidden": true,
|
||||
"x-use-standalone-layout": true,
|
||||
"implementation": "/packages/nx-plugin/src/generators/preset/generator.ts",
|
||||
"aliases": [],
|
||||
"path": "/packages/nx-plugin/src/generators/preset/schema.json",
|
||||
"type": "generator"
|
||||
}
|
||||
@ -235,7 +235,7 @@ export function runCreatePlugin(
|
||||
} create-nx-plugin@${getPublishedVersion()} ${name}`;
|
||||
|
||||
if (pluginName) {
|
||||
command += ` --pluginName=${pluginName}`;
|
||||
command += ` --pluginName=${pluginName} --no-nxCloud`;
|
||||
}
|
||||
|
||||
if (packageManager && !useDetectedPm) {
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
uniq,
|
||||
runCreatePlugin,
|
||||
cleanupProject,
|
||||
tmpProjPath,
|
||||
} from '@nrwl/e2e/utils';
|
||||
|
||||
describe('create-nx-plugin', () => {
|
||||
@ -13,8 +14,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');
|
||||
|
||||
@ -26,10 +26,11 @@ describe('create-nx-plugin', () => {
|
||||
checkFilesExist(
|
||||
'package.json',
|
||||
packageManagerLockFile[packageManager],
|
||||
`packages/${pluginName}/package.json`,
|
||||
`packages/${pluginName}/project.json`
|
||||
`project.json`,
|
||||
`generators.json`,
|
||||
`executors.json`
|
||||
);
|
||||
|
||||
expect(() => runCLI(`e2e ${pluginName}-e2e`)).not.toThrow();
|
||||
expect(() => runCLI(`e2e e2e`)).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,16 @@
|
||||
{
|
||||
"extends": "../../.eslintrc",
|
||||
"rules": {},
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
"@nrwl/workspace",
|
||||
"@angular-devkit/core",
|
||||
"@angular-devkit/architect",
|
||||
"@angular-devkit/schematics",
|
||||
"nx",
|
||||
"@nrwl/devkit"
|
||||
]
|
||||
},
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
|
||||
@ -1,156 +1,43 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// we can't import from '@nrwl/workspace' because it will require typescript
|
||||
import {
|
||||
getPackageManagerCommand,
|
||||
NxJsonConfiguration,
|
||||
readJsonFile,
|
||||
writeJsonFile,
|
||||
output,
|
||||
} from '@nrwl/devkit';
|
||||
import { execSync } from 'child_process';
|
||||
import { rmSync } from 'fs';
|
||||
import * as path from 'path';
|
||||
import { dirSync } from 'tmp';
|
||||
import { initializeGitRepo, showNxWarning } from './shared';
|
||||
import {
|
||||
detectInvokedPackageManager,
|
||||
PackageManager,
|
||||
} from './detect-invoked-package-manager';
|
||||
import chalk = require('chalk');
|
||||
import enquirer = require('enquirer');
|
||||
import yargsParser = require('yargs-parser');
|
||||
import yargs = require('yargs');
|
||||
|
||||
import {
|
||||
determineCI,
|
||||
determineDefaultBase,
|
||||
determineNxCloud,
|
||||
determinePackageManager,
|
||||
} from 'create-nx-workspace/src/internal-utils/prompts';
|
||||
import {
|
||||
withAllPrompts,
|
||||
withCI,
|
||||
withGitOptions,
|
||||
withNxCloud,
|
||||
withOptions,
|
||||
withPackageManager,
|
||||
} from 'create-nx-workspace/src/internal-utils/yargs-options';
|
||||
import { createWorkspace, CreateWorkspaceOptions } from 'create-nx-workspace';
|
||||
import { output } from 'create-nx-workspace/src/utils/output';
|
||||
import { CI } from 'create-nx-workspace/src/utils/ci/ci-list';
|
||||
import type { PackageManager } from 'create-nx-workspace/src/utils/package-manager';
|
||||
|
||||
export const yargsDecorator = {
|
||||
'Options:': `${chalk.green`Options`}:`,
|
||||
'Examples:': `${chalk.green`Examples`}:`,
|
||||
boolean: `${chalk.blue`boolean`}`,
|
||||
count: `${chalk.blue`count`}`,
|
||||
string: `${chalk.blue`string`}`,
|
||||
array: `${chalk.blue`array`}`,
|
||||
required: `${chalk.blue`required`}`,
|
||||
'default:': `${chalk.blue`default`}:`,
|
||||
'choices:': `${chalk.blue`choices`}:`,
|
||||
'aliases:': `${chalk.blue`aliases`}:`,
|
||||
};
|
||||
|
||||
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'],
|
||||
alias: {
|
||||
importPath: 'import-path',
|
||||
pluginName: 'plugin-name',
|
||||
packageManager: 'pm',
|
||||
},
|
||||
boolean: ['help'],
|
||||
});
|
||||
|
||||
function createSandbox(packageManager: string) {
|
||||
console.log(`Creating a sandbox with Nx...`);
|
||||
const tmpDir = dirSync().name;
|
||||
writeJsonFile(path.join(tmpDir, 'package.json'), {
|
||||
dependencies: {
|
||||
'@nrwl/workspace': nxVersion,
|
||||
nx: nxVersion,
|
||||
typescript: tsVersion,
|
||||
prettier: prettierVersion,
|
||||
},
|
||||
license: 'MIT',
|
||||
});
|
||||
|
||||
execSync(`${packageManager} install --silent --ignore-scripts`, {
|
||||
cwd: tmpDir,
|
||||
stdio: [0, 1, 2],
|
||||
});
|
||||
|
||||
return tmpDir;
|
||||
}
|
||||
|
||||
function createWorkspace(
|
||||
tmpDir: string,
|
||||
packageManager: PackageManager,
|
||||
parsedArgs: any,
|
||||
name: string
|
||||
) {
|
||||
// Ensure to use packageManager for args
|
||||
// if it's not already passed in from previous process
|
||||
if (!parsedArgs.packageManager) {
|
||||
parsedArgs.packageManager = packageManager;
|
||||
}
|
||||
|
||||
const args = [
|
||||
name,
|
||||
...process.argv.slice(parsedArgs._[2] ? 3 : 2).map((a) => `"${a}"`),
|
||||
].join(' ');
|
||||
|
||||
const command = `new ${args} --preset=empty --collection=@nrwl/workspace`;
|
||||
console.log(command);
|
||||
|
||||
const pmc = getPackageManagerCommand(packageManager);
|
||||
execSync(
|
||||
`${
|
||||
pmc.exec
|
||||
} nx ${command}/generators.json --nxWorkspaceRoot="${process.cwd()}"`,
|
||||
{
|
||||
stdio: [0, 1, 2],
|
||||
cwd: tmpDir,
|
||||
}
|
||||
);
|
||||
execSync(`${packageManager} add -D @nrwl/nx-plugin@${nxVersion}`, {
|
||||
cwd: name,
|
||||
stdio: [0, 1, 2],
|
||||
});
|
||||
}
|
||||
|
||||
function createNxPlugin(
|
||||
workspaceName,
|
||||
pluginName,
|
||||
packageManager,
|
||||
parsedArgs: any
|
||||
) {
|
||||
const importPath = parsedArgs.importPath ?? `@${workspaceName}/${pluginName}`;
|
||||
const command = `nx generate @nrwl/nx-plugin:plugin ${pluginName} --importPath=${importPath}`;
|
||||
console.log(command);
|
||||
|
||||
const pmc = getPackageManagerCommand(packageManager);
|
||||
execSync(`${pmc.exec} ${command}`, {
|
||||
cwd: workspaceName,
|
||||
stdio: [0, 1, 2],
|
||||
});
|
||||
}
|
||||
|
||||
function updateWorkspace(workspaceName: string) {
|
||||
const nxJsonPath = path.join(workspaceName, 'nx.json');
|
||||
const nxJson = readJsonFile<NxJsonConfiguration>(nxJsonPath);
|
||||
|
||||
nxJson.workspaceLayout = {
|
||||
appsDir: 'e2e',
|
||||
libsDir: 'packages',
|
||||
};
|
||||
|
||||
writeJsonFile(nxJsonPath, nxJson);
|
||||
|
||||
rmSync(path.join(workspaceName, 'apps'), { recursive: true, force: true });
|
||||
rmSync(path.join(workspaceName, 'libs'), { recursive: true, force: true });
|
||||
}
|
||||
|
||||
function determineWorkspaceName(parsedArgs: any): Promise<string> {
|
||||
const workspaceName: string = parsedArgs._[2];
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
function determinePluginName(parsedArgs) {
|
||||
function determinePluginName(parsedArgs: CreateNxPluginArguments) {
|
||||
if (parsedArgs.pluginName) {
|
||||
return Promise.resolve(parsedArgs.pluginName);
|
||||
}
|
||||
@ -158,54 +45,112 @@ function determinePluginName(parsedArgs) {
|
||||
return enquirer
|
||||
.prompt([
|
||||
{
|
||||
name: 'PluginName',
|
||||
name: 'pluginName',
|
||||
message: `Plugin name `,
|
||||
type: 'input',
|
||||
validate: (s) => (s.length ? true : 'Name cannot be empty'),
|
||||
},
|
||||
])
|
||||
.then((a: { PluginName: string }) => {
|
||||
if (!a.PluginName) {
|
||||
.then((a: { pluginName: string }) => {
|
||||
if (!a.pluginName) {
|
||||
output.error({
|
||||
title: 'Invalid name',
|
||||
bodyLines: [`Name cannot be empty`],
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
return a.PluginName;
|
||||
return a.pluginName;
|
||||
});
|
||||
}
|
||||
|
||||
function showHelp() {
|
||||
console.log(`
|
||||
Usage: <name> [options]
|
||||
|
||||
Create a new Nx workspace
|
||||
|
||||
Args:
|
||||
|
||||
name workspace name (e.g., org name)
|
||||
|
||||
Options:
|
||||
|
||||
pluginName the name of the plugin to be created
|
||||
`);
|
||||
interface CreateNxPluginArguments {
|
||||
pluginName: string;
|
||||
packageManager: PackageManager;
|
||||
ci: CI;
|
||||
allPrompts: boolean;
|
||||
nxCloud: boolean;
|
||||
}
|
||||
|
||||
if (parsedArgs.help) {
|
||||
showHelp();
|
||||
process.exit(0);
|
||||
export const commandsObject: yargs.Argv<CreateNxPluginArguments> = yargs
|
||||
.wrap(yargs.terminalWidth())
|
||||
.parserConfiguration({
|
||||
'strip-dashed': true,
|
||||
'dot-notation': true,
|
||||
})
|
||||
.command(
|
||||
// this is the default and only command
|
||||
'$0 [name] [options]',
|
||||
'Create a new Nx plugin workspace',
|
||||
(yargs) =>
|
||||
withOptions(
|
||||
yargs.positional('pluginName', {
|
||||
describe: chalk.dim`Plugin name`,
|
||||
type: 'string',
|
||||
alias: ['name'],
|
||||
}),
|
||||
withNxCloud,
|
||||
withCI,
|
||||
withAllPrompts,
|
||||
withPackageManager,
|
||||
withGitOptions
|
||||
),
|
||||
async (argv: yargs.ArgumentsCamelCase<CreateNxPluginArguments>) => {
|
||||
await main(argv).catch((error) => {
|
||||
const { version } = require('../package.json');
|
||||
output.error({
|
||||
title: `Something went wrong! v${version}`,
|
||||
});
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
[normalizeArgsMiddleware]
|
||||
)
|
||||
.help('help', chalk.dim`Show help`)
|
||||
.updateLocale(yargsDecorator)
|
||||
.version(
|
||||
'version',
|
||||
chalk.dim`Show version`,
|
||||
nxVersion
|
||||
) as yargs.Argv<CreateNxPluginArguments>;
|
||||
|
||||
async function main(parsedArgs: yargs.Arguments<CreateNxPluginArguments>) {
|
||||
const populatedArguments: CreateNxPluginArguments & CreateWorkspaceOptions = {
|
||||
...parsedArgs,
|
||||
name: parsedArgs.pluginName.includes('/')
|
||||
? parsedArgs.pluginName.split('/')[1]
|
||||
: parsedArgs.pluginName,
|
||||
};
|
||||
await createWorkspace('@nrwl/nx-plugin', populatedArguments);
|
||||
}
|
||||
|
||||
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);
|
||||
/**
|
||||
* This function is used to normalize the arguments passed to the command.
|
||||
* It would:
|
||||
* - normalize the preset.
|
||||
* @param argv user arguments
|
||||
*/
|
||||
async function normalizeArgsMiddleware(
|
||||
argv: yargs.Arguments<CreateNxPluginArguments>
|
||||
): Promise<void> {
|
||||
try {
|
||||
const name = await determinePluginName(argv);
|
||||
const packageManager = await determinePackageManager(argv);
|
||||
const defaultBase = await determineDefaultBase(argv);
|
||||
const nxCloud = await determineNxCloud(argv);
|
||||
const ci = await determineCI(argv, nxCloud);
|
||||
|
||||
Object.assign(argv, {
|
||||
name,
|
||||
nxCloud,
|
||||
packageManager,
|
||||
defaultBase,
|
||||
ci,
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger Yargs
|
||||
commandsObject.argv;
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
const packageManagerList = ['pnpm', 'yarn', 'npm'] as const;
|
||||
|
||||
export type PackageManager = typeof packageManagerList[number];
|
||||
|
||||
/**
|
||||
* Detects which package manager was used to invoke create-nx-{plugin|workspace} command
|
||||
* based on the main Module process that invokes the command
|
||||
* - npx returns 'npm'
|
||||
* - pnpx returns 'pnpm'
|
||||
* - yarn create returns 'yarn'
|
||||
*
|
||||
* Default to 'npm'
|
||||
*/
|
||||
export function detectInvokedPackageManager(): PackageManager {
|
||||
let detectedPackageManager: PackageManager = 'npm';
|
||||
// mainModule is deprecated since Node 14, fallback for older versions
|
||||
const invoker = require.main || process['mainModule'];
|
||||
|
||||
// default to `npm`
|
||||
if (!invoker) {
|
||||
return detectedPackageManager;
|
||||
}
|
||||
|
||||
for (const pkgManager of packageManagerList) {
|
||||
if (invoker.path.includes(pkgManager)) {
|
||||
detectedPackageManager = pkgManager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return detectedPackageManager;
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
import * as path from 'path';
|
||||
import { execSync, spawn, SpawnOptions } from 'child_process';
|
||||
import { output } from '@nrwl/devkit';
|
||||
|
||||
export function showNxWarning(workspaceName: string) {
|
||||
try {
|
||||
const pathToRunNxCommand = path.resolve(process.cwd(), workspaceName);
|
||||
execSync('nx --version', {
|
||||
cwd: pathToRunNxCommand,
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
});
|
||||
} catch {
|
||||
// no nx found
|
||||
output.addVerticalSeparator();
|
||||
output.note({
|
||||
title: `Nx CLI is not installed globally.`,
|
||||
bodyLines: [
|
||||
`This means that you might have to use "yarn nx" or "npx nx" to execute commands in the workspace.`,
|
||||
`Run "yarn global add nx" or "npm install -g nx" to be able to execute command directly.`,
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Because we don't want to depend on @nrwl/workspace
|
||||
* we duplicate the helper functions from @nrwl/workspace in this file.
|
||||
*/
|
||||
export function deduceDefaultBase(): string {
|
||||
const nxDefaultBase = 'main';
|
||||
try {
|
||||
return (
|
||||
execSync('git config --get init.defaultBranch').toString().trim() ||
|
||||
nxDefaultBase
|
||||
);
|
||||
} catch {
|
||||
return nxDefaultBase;
|
||||
}
|
||||
}
|
||||
|
||||
function checkGitVersion(): string | null {
|
||||
try {
|
||||
let gitVersionOutput = execSync('git --version').toString().trim();
|
||||
return gitVersionOutput.match(/[0-9]+\.[0-9]+\.+[0-9]+/)[0];
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Because we don't want to depend on create-nx-workspace
|
||||
* we duplicate the helper functions from create-nx-workspace in this file.
|
||||
*/
|
||||
export async function initializeGitRepo(directory: string) {
|
||||
const execute = (args: ReadonlyArray<string>, ignoreErrorStream = false) => {
|
||||
const errorStream = ignoreErrorStream ? 'ignore' : process.stderr;
|
||||
const spawnOptions: SpawnOptions = {
|
||||
stdio: [process.stdin, 'ignore', errorStream],
|
||||
shell: true,
|
||||
cwd: directory,
|
||||
env: process.env,
|
||||
};
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
spawn('git', args, spawnOptions).on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(code);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
const gitVersion = checkGitVersion();
|
||||
if (!gitVersion) {
|
||||
return;
|
||||
}
|
||||
const insideRepo = await execute(
|
||||
['rev-parse', '--is-inside-work-tree'],
|
||||
true
|
||||
).then(
|
||||
() => true,
|
||||
() => false
|
||||
);
|
||||
if (insideRepo) {
|
||||
output.log({
|
||||
title:
|
||||
'Directory is already under version control. Skipping initialization of git.',
|
||||
});
|
||||
return;
|
||||
}
|
||||
const defaultBase = deduceDefaultBase();
|
||||
const [gitMajor, gitMinor] = gitVersion.split('.');
|
||||
|
||||
if (+gitMajor > 2 || (+gitMajor === 2 && +gitMinor >= 28)) {
|
||||
await execute(['init', '-b', defaultBase]);
|
||||
} else {
|
||||
await execute(['init']);
|
||||
await execute(['checkout', '-b', defaultBase]); // Git < 2.28 doesn't support -b on git init.
|
||||
}
|
||||
await execute(['add', '.']);
|
||||
const message = 'Initial commit';
|
||||
await execute(['commit', `-m "${message}"`]);
|
||||
output.log({
|
||||
title: 'Successfully initialized git.',
|
||||
});
|
||||
}
|
||||
@ -29,11 +29,10 @@
|
||||
},
|
||||
"homepage": "https://nx.dev",
|
||||
"dependencies": {
|
||||
"@nrwl/devkit": "file:../devkit",
|
||||
"create-nx-workspace": "file:../create-nx-workspace",
|
||||
"chalk": "^4.1.0",
|
||||
"enquirer": "~2.3.6",
|
||||
"nx": "file:../nx",
|
||||
"tmp": "~0.2.1",
|
||||
"yargs-parser": "21.1.1"
|
||||
"yargs": "^17.6.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@ -2,20 +2,11 @@ import * as enquirer from 'enquirer';
|
||||
import * as yargs from 'yargs';
|
||||
import * as chalk from 'chalk';
|
||||
|
||||
import { ciList } from '../src/utils/ci/ci-list';
|
||||
import { CreateWorkspaceOptions } from '../src/create-workspace-options';
|
||||
import { createWorkspace } from '../src/create-workspace';
|
||||
import { isKnownPreset, Preset } from '../src/utils/preset/preset';
|
||||
import { presetOptions } from '../src/utils/preset/preset-options';
|
||||
import { messages } from '../src/utils/nx/ab-testing';
|
||||
import { output } from '../src/utils/output';
|
||||
import { deduceDefaultBase } from '../src/utils/git/default-base';
|
||||
import { stringifyCollection } from '../src/utils/string-utils';
|
||||
import {
|
||||
detectInvokedPackageManager,
|
||||
PackageManager,
|
||||
packageManagerList,
|
||||
} from '../src/utils/package-manager';
|
||||
import { nxVersion } from '../src/utils/nx/nx-version';
|
||||
import { pointToTutorialAndCourse } from '../src/utils/preset/point-to-tutorial-and-course';
|
||||
|
||||
@ -23,6 +14,20 @@ import { yargsDecorator } from './decorator';
|
||||
import { getThirdPartyPreset } from '../src/utils/preset/get-third-party-preset';
|
||||
import { Framework, frameworkList } from './types/framework-list';
|
||||
import { Bundler, bundlerList } from './types/bundler-list';
|
||||
import {
|
||||
determineCI,
|
||||
determineDefaultBase,
|
||||
determineNxCloud,
|
||||
determinePackageManager,
|
||||
} from '../src/internal-utils/prompts';
|
||||
import {
|
||||
withAllPrompts,
|
||||
withCI,
|
||||
withGitOptions,
|
||||
withNxCloud,
|
||||
withOptions,
|
||||
withPackageManager,
|
||||
} from '../src/internal-utils/yargs-options';
|
||||
|
||||
interface Arguments extends CreateWorkspaceOptions {
|
||||
preset: string;
|
||||
@ -46,103 +51,64 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
|
||||
'$0 [name] [options]',
|
||||
'Create a new Nx workspace',
|
||||
(yargs) =>
|
||||
yargs
|
||||
.option('name', {
|
||||
describe: chalk.dim`Workspace name (e.g. org name)`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('preset', {
|
||||
describe: chalk.dim`Customizes the initial content of your workspace. Default presets include: [${Object.values(
|
||||
Preset
|
||||
)
|
||||
.map((p) => `"${p}"`)
|
||||
.join(
|
||||
', '
|
||||
)}]. To build your own see https://nx.dev/packages/nx-plugin#preset`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('appName', {
|
||||
describe: chalk.dim`The name of the application when a preset with pregenerated app is selected`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('interactive', {
|
||||
describe: chalk.dim`Enable interactive mode with presets`,
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
})
|
||||
.option('style', {
|
||||
describe: chalk.dim`Style option to be used when a preset with pregenerated app is selected`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('standaloneApi', {
|
||||
describe: chalk.dim`Use Standalone Components if generating an Angular app`,
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('routing', {
|
||||
describe: chalk.dim`Add a routing setup when a preset with pregenerated app is selected`,
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('bundler', {
|
||||
describe: chalk.dim`Bundler to be used to build the application`,
|
||||
choices: bundlerList,
|
||||
type: 'string',
|
||||
})
|
||||
.option('framework', {
|
||||
describe: chalk.dim`Framework option to be used when the node-server preset is selected`,
|
||||
choices: frameworkList,
|
||||
type: 'string',
|
||||
})
|
||||
.option('docker', {
|
||||
describe: chalk.dim`Generate a Dockerfile with your node-server`,
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('nxCloud', {
|
||||
describe: chalk.dim(messages.getPromptMessage('nxCloudCreation')),
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('ci', {
|
||||
describe: chalk.dim`Generate a CI workflow file`,
|
||||
choices: ciList,
|
||||
defaultDescription: '',
|
||||
type: 'string',
|
||||
})
|
||||
.option('allPrompts', {
|
||||
alias: 'a',
|
||||
describe: chalk.dim`Show all prompts`,
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
})
|
||||
.option('packageManager', {
|
||||
alias: 'pm',
|
||||
describe: chalk.dim`Package manager to use`,
|
||||
choices: [...packageManagerList].sort(),
|
||||
defaultDescription: 'npm',
|
||||
type: 'string',
|
||||
})
|
||||
.option('defaultBase', {
|
||||
defaultDescription: 'main',
|
||||
describe: chalk.dim`Default base to use for new projects`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('skipGit', {
|
||||
describe: chalk.dim`Skip initializing a git repository`,
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
alias: 'g',
|
||||
})
|
||||
.option('commit.name', {
|
||||
describe: chalk.dim`Name of the committer`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('commit.email', {
|
||||
describe: chalk.dim`E-mail of the committer`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('commit.message', {
|
||||
describe: chalk.dim`Commit message`,
|
||||
type: 'string',
|
||||
default: 'Initial commit',
|
||||
}),
|
||||
withOptions(
|
||||
yargs
|
||||
.option('name', {
|
||||
describe: chalk.dim`Workspace name (e.g. org name)`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('preset', {
|
||||
describe: chalk.dim`Customizes the initial content of your workspace. Default presets include: [${Object.values(
|
||||
Preset
|
||||
)
|
||||
.map((p) => `"${p}"`)
|
||||
.join(
|
||||
', '
|
||||
)}]. To build your own see https://nx.dev/packages/nx-plugin#preset`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('appName', {
|
||||
describe: chalk.dim`The name of the application when a preset with pregenerated app is selected`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('interactive', {
|
||||
describe: chalk.dim`Enable interactive mode with presets`,
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
})
|
||||
.option('style', {
|
||||
describe: chalk.dim`Style option to be used when a preset with pregenerated app is selected`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('standaloneApi', {
|
||||
describe: chalk.dim`Use Standalone Components if generating an Angular app`,
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('routing', {
|
||||
describe: chalk.dim`Add a routing setup when a preset with pregenerated app is selected`,
|
||||
type: 'boolean',
|
||||
})
|
||||
.option('bundler', {
|
||||
describe: chalk.dim`Bundler to be used to build the application`,
|
||||
choices: bundlerList,
|
||||
type: 'string',
|
||||
})
|
||||
.option('framework', {
|
||||
describe: chalk.dim`Framework option to be used when the node-server preset is selected`,
|
||||
choices: frameworkList,
|
||||
type: 'string',
|
||||
})
|
||||
.option('docker', {
|
||||
describe: chalk.dim`Generate a Dockerfile with your node-server`,
|
||||
type: 'boolean',
|
||||
}),
|
||||
withNxCloud,
|
||||
withCI,
|
||||
withAllPrompts,
|
||||
withPackageManager,
|
||||
withGitOptions
|
||||
),
|
||||
|
||||
async (argv: yargs.ArgumentsCamelCase<Arguments>) => {
|
||||
await main(argv).catch((error) => {
|
||||
const { version } = require('../package.json');
|
||||
@ -404,77 +370,6 @@ async function determineMonorepoStyle(): Promise<string> {
|
||||
return a.MonorepoStyle;
|
||||
}
|
||||
|
||||
async function determinePackageManager(
|
||||
parsedArgs: yargs.Arguments<Arguments>
|
||||
): Promise<PackageManager> {
|
||||
const packageManager: string = parsedArgs.packageManager;
|
||||
|
||||
if (packageManager) {
|
||||
if (packageManagerList.includes(packageManager as PackageManager)) {
|
||||
return Promise.resolve(packageManager as PackageManager);
|
||||
}
|
||||
output.error({
|
||||
title: 'Invalid package manager',
|
||||
bodyLines: [
|
||||
`Package manager must be one of ${stringifyCollection([
|
||||
...packageManagerList,
|
||||
])}`,
|
||||
],
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (parsedArgs.allPrompts) {
|
||||
return enquirer
|
||||
.prompt<{ packageManager: PackageManager }>([
|
||||
{
|
||||
name: 'packageManager',
|
||||
message: `Which package manager to use `,
|
||||
initial: 'npm' as any,
|
||||
type: 'autocomplete',
|
||||
choices: [
|
||||
{ name: 'npm', message: 'NPM' },
|
||||
{ name: 'yarn', message: 'Yarn' },
|
||||
{ name: 'pnpm', message: 'PNPM' },
|
||||
],
|
||||
},
|
||||
])
|
||||
.then((a) => a.packageManager);
|
||||
}
|
||||
|
||||
return Promise.resolve(detectInvokedPackageManager());
|
||||
}
|
||||
|
||||
async function determineDefaultBase(
|
||||
parsedArgs: yargs.Arguments<Arguments>
|
||||
): Promise<string> {
|
||||
if (parsedArgs.defaultBase) {
|
||||
return Promise.resolve(parsedArgs.defaultBase);
|
||||
}
|
||||
if (parsedArgs.allPrompts) {
|
||||
return enquirer
|
||||
.prompt<{ DefaultBase: string }>([
|
||||
{
|
||||
name: 'DefaultBase',
|
||||
message: `Main branch name `,
|
||||
initial: `main`,
|
||||
type: 'input',
|
||||
},
|
||||
])
|
||||
.then((a) => {
|
||||
if (!a.DefaultBase) {
|
||||
output.error({
|
||||
title: 'Invalid branch name',
|
||||
bodyLines: [`Branch name cannot be empty`],
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
return a.DefaultBase;
|
||||
});
|
||||
}
|
||||
return Promise.resolve(deduceDefaultBase());
|
||||
}
|
||||
|
||||
async function determinePreset(parsedArgs: any): Promise<Preset> {
|
||||
if (parsedArgs.preset) {
|
||||
if (Object.values(Preset).indexOf(parsedArgs.preset) === -1) {
|
||||
@ -832,79 +727,3 @@ async function determineBundler(
|
||||
|
||||
return Promise.resolve(parsedArgs.bundler);
|
||||
}
|
||||
|
||||
async function determineNxCloud(
|
||||
parsedArgs: yargs.Arguments<Arguments>
|
||||
): Promise<boolean> {
|
||||
if (parsedArgs.nxCloud === undefined) {
|
||||
return enquirer
|
||||
.prompt<{ NxCloud: 'Yes' | 'No' }>([
|
||||
{
|
||||
name: 'NxCloud',
|
||||
message: messages.getPromptMessage('nxCloudCreation'),
|
||||
type: 'autocomplete',
|
||||
choices: [
|
||||
{
|
||||
name: 'Yes',
|
||||
hint: 'I want faster builds',
|
||||
},
|
||||
|
||||
{
|
||||
name: 'No',
|
||||
},
|
||||
],
|
||||
initial: 'Yes' as any,
|
||||
},
|
||||
])
|
||||
.then((a) => a.NxCloud === 'Yes');
|
||||
} else {
|
||||
return parsedArgs.nxCloud;
|
||||
}
|
||||
}
|
||||
|
||||
async function determineCI(
|
||||
parsedArgs: yargs.Arguments<Arguments>,
|
||||
nxCloud: boolean
|
||||
): Promise<string> {
|
||||
if (!nxCloud) {
|
||||
if (parsedArgs.ci) {
|
||||
output.warn({
|
||||
title: 'Invalid CI value',
|
||||
bodyLines: [
|
||||
`CI option only works when Nx Cloud is enabled.`,
|
||||
`The value provided will be ignored.`,
|
||||
],
|
||||
});
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
if (parsedArgs.ci) {
|
||||
return parsedArgs.ci;
|
||||
}
|
||||
|
||||
if (parsedArgs.allPrompts) {
|
||||
return (
|
||||
enquirer
|
||||
.prompt<{ CI: string }>([
|
||||
{
|
||||
name: 'CI',
|
||||
message: `CI workflow file to generate? `,
|
||||
type: 'autocomplete',
|
||||
initial: '' as any,
|
||||
choices: [
|
||||
{ message: 'none', name: '' },
|
||||
{ message: 'GitHub Actions', name: 'github' },
|
||||
{ message: 'Circle CI', name: 'circleci' },
|
||||
{ message: 'Azure DevOps', name: 'azure' },
|
||||
],
|
||||
},
|
||||
])
|
||||
// enquirer ignores name and value if they are falsy and takes
|
||||
// first field that has a truthy value, so wee need to explicitly
|
||||
// check for none
|
||||
.then((a: { CI: string }) => (a.CI !== 'none' ? a.CI : ''))
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -1 +1,2 @@
|
||||
export * from './src/create-workspace';
|
||||
export type { CreateWorkspaceOptions } from './src/create-workspace-options';
|
||||
|
||||
@ -36,11 +36,12 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
|
||||
|
||||
const tmpDir = await createSandbox(packageManager);
|
||||
|
||||
// nx new requires preset currently. We should probably make it optional.
|
||||
const directory = await createEmptyWorkspace<T>(
|
||||
tmpDir,
|
||||
name,
|
||||
packageManager,
|
||||
options
|
||||
{ ...options, preset }
|
||||
);
|
||||
|
||||
// If the preset is a third-party preset, we need to call createPreset to install it
|
||||
|
||||
159
packages/create-nx-workspace/src/internal-utils/prompts.ts
Normal file
159
packages/create-nx-workspace/src/internal-utils/prompts.ts
Normal file
@ -0,0 +1,159 @@
|
||||
import * as yargs from 'yargs';
|
||||
import { messages } from '../utils/nx/ab-testing';
|
||||
import enquirer = require('enquirer');
|
||||
import { CI } from '../utils/ci/ci-list';
|
||||
import { output } from '../utils/output';
|
||||
import { deduceDefaultBase } from '../utils/git/default-base';
|
||||
import {
|
||||
detectInvokedPackageManager,
|
||||
PackageManager,
|
||||
packageManagerList,
|
||||
} from '../utils/package-manager';
|
||||
import { stringifyCollection } from '../utils/string-utils';
|
||||
|
||||
export async function determineNxCloud(
|
||||
parsedArgs: yargs.Arguments<{ nxCloud: boolean }>
|
||||
): Promise<boolean> {
|
||||
if (parsedArgs.nxCloud === undefined) {
|
||||
return enquirer
|
||||
.prompt<{ NxCloud: 'Yes' | 'No' }>([
|
||||
{
|
||||
name: 'NxCloud',
|
||||
message: messages.getPromptMessage('nxCloudCreation'),
|
||||
type: 'autocomplete',
|
||||
choices: [
|
||||
{
|
||||
name: 'Yes',
|
||||
hint: 'I want faster builds',
|
||||
},
|
||||
|
||||
{
|
||||
name: 'No',
|
||||
},
|
||||
],
|
||||
initial: 'Yes' as any,
|
||||
},
|
||||
])
|
||||
.then((a) => a.NxCloud === 'Yes');
|
||||
} else {
|
||||
return parsedArgs.nxCloud;
|
||||
}
|
||||
}
|
||||
|
||||
export async function determineCI(
|
||||
parsedArgs: yargs.Arguments<{ ci?: CI; allPrompts?: boolean }>,
|
||||
nxCloud: boolean
|
||||
): Promise<string> {
|
||||
if (!nxCloud) {
|
||||
if (parsedArgs.ci) {
|
||||
output.warn({
|
||||
title: 'Invalid CI value',
|
||||
bodyLines: [
|
||||
`CI option only works when Nx Cloud is enabled.`,
|
||||
`The value provided will be ignored.`,
|
||||
],
|
||||
});
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
if (parsedArgs.ci) {
|
||||
return parsedArgs.ci;
|
||||
}
|
||||
|
||||
if (parsedArgs.allPrompts) {
|
||||
return (
|
||||
enquirer
|
||||
.prompt<{ CI: string }>([
|
||||
{
|
||||
name: 'CI',
|
||||
message: `CI workflow file to generate? `,
|
||||
type: 'autocomplete',
|
||||
initial: '' as any,
|
||||
choices: [
|
||||
{ message: 'none', name: '' },
|
||||
{ message: 'GitHub Actions', name: 'github' },
|
||||
{ message: 'Circle CI', name: 'circleci' },
|
||||
{ message: 'Azure DevOps', name: 'azure' },
|
||||
],
|
||||
},
|
||||
])
|
||||
// enquirer ignores name and value if they are falsy and takes
|
||||
// first field that has a truthy value, so wee need to explicitly
|
||||
// check for none
|
||||
.then((a: { CI: string }) => (a.CI !== 'none' ? a.CI : ''))
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export async function determineDefaultBase(
|
||||
parsedArgs: yargs.Arguments<{ defaultBase?: string }>
|
||||
): Promise<string> {
|
||||
if (parsedArgs.defaultBase) {
|
||||
return Promise.resolve(parsedArgs.defaultBase);
|
||||
}
|
||||
if (parsedArgs.allPrompts) {
|
||||
return enquirer
|
||||
.prompt<{ DefaultBase: string }>([
|
||||
{
|
||||
name: 'DefaultBase',
|
||||
message: `Main branch name `,
|
||||
initial: `main`,
|
||||
type: 'input',
|
||||
},
|
||||
])
|
||||
.then((a) => {
|
||||
if (!a.DefaultBase) {
|
||||
output.error({
|
||||
title: 'Invalid branch name',
|
||||
bodyLines: [`Branch name cannot be empty`],
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
return a.DefaultBase;
|
||||
});
|
||||
}
|
||||
return Promise.resolve(deduceDefaultBase());
|
||||
}
|
||||
|
||||
export async function determinePackageManager(
|
||||
parsedArgs: yargs.Arguments<{ packageManager: string }>
|
||||
): Promise<PackageManager> {
|
||||
const packageManager: string = parsedArgs.packageManager;
|
||||
|
||||
if (packageManager) {
|
||||
if (packageManagerList.includes(packageManager as PackageManager)) {
|
||||
return Promise.resolve(packageManager as PackageManager);
|
||||
}
|
||||
output.error({
|
||||
title: 'Invalid package manager',
|
||||
bodyLines: [
|
||||
`Package manager must be one of ${stringifyCollection([
|
||||
...packageManagerList,
|
||||
])}`,
|
||||
],
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (parsedArgs.allPrompts) {
|
||||
return enquirer
|
||||
.prompt<{ packageManager: PackageManager }>([
|
||||
{
|
||||
name: 'packageManager',
|
||||
message: `Which package manager to use `,
|
||||
initial: 'npm' as any,
|
||||
type: 'autocomplete',
|
||||
choices: [
|
||||
{ name: 'npm', message: 'NPM' },
|
||||
{ name: 'yarn', message: 'Yarn' },
|
||||
{ name: 'pnpm', message: 'PNPM' },
|
||||
],
|
||||
},
|
||||
])
|
||||
.then((a) => a.packageManager);
|
||||
}
|
||||
|
||||
return Promise.resolve(detectInvokedPackageManager());
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
import chalk = require('chalk');
|
||||
import yargs = require('yargs');
|
||||
import { CreateWorkspaceOptions } from '../create-workspace-options';
|
||||
import { ciList } from '../utils/ci/ci-list';
|
||||
import { messages } from '../utils/nx/ab-testing';
|
||||
import { packageManagerList } from '../utils/package-manager';
|
||||
|
||||
export function withNxCloud<T = unknown>(argv: yargs.Argv<T>) {
|
||||
const result = argv.option('nxCloud', {
|
||||
describe: chalk.dim(messages.getPromptMessage('nxCloudCreation')),
|
||||
type: 'boolean',
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export function withCI<T = unknown>(argv: yargs.Argv<T>) {
|
||||
return argv.option('ci', {
|
||||
describe: chalk.dim`Generate a CI workflow file`,
|
||||
choices: ciList,
|
||||
defaultDescription: '',
|
||||
type: 'string',
|
||||
});
|
||||
}
|
||||
|
||||
export function withAllPrompts<T = unknown>(argv: yargs.Argv<T>) {
|
||||
return argv.option('allPrompts', {
|
||||
alias: 'a',
|
||||
describe: chalk.dim`Show all prompts`,
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
});
|
||||
}
|
||||
|
||||
export function withPackageManager<T = unknown>(argv: yargs.Argv<T>) {
|
||||
return argv.option('packageManager', {
|
||||
alias: 'pm',
|
||||
describe: chalk.dim`Package manager to use`,
|
||||
choices: [...packageManagerList].sort(),
|
||||
defaultDescription: 'npm',
|
||||
type: 'string',
|
||||
});
|
||||
}
|
||||
|
||||
export function withGitOptions<T = unknown>(argv: yargs.Argv<T>) {
|
||||
return argv
|
||||
.option('defaultBase', {
|
||||
defaultDescription: 'main',
|
||||
describe: chalk.dim`Default base to use for new projects`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('skipGit', {
|
||||
describe: chalk.dim`Skip initializing a git repository`,
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
alias: 'g',
|
||||
})
|
||||
.option('commit.name', {
|
||||
describe: chalk.dim`Name of the committer`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('commit.email', {
|
||||
describe: chalk.dim`E-mail of the committer`,
|
||||
type: 'string',
|
||||
})
|
||||
.option('commit.message', {
|
||||
describe: chalk.dim`Commit message`,
|
||||
type: 'string',
|
||||
default: 'Initial commit',
|
||||
});
|
||||
}
|
||||
|
||||
export function withOptions<T>(
|
||||
argv: yargs.Argv<T>,
|
||||
...options: ((argv: yargs.Argv<T>) => yargs.Argv<T>)[]
|
||||
): any {
|
||||
// Reversing the options keeps the execution order correct.
|
||||
// e.g. [withCI, withGIT] should transform into withGIT(withCI) so withCI resolves first.
|
||||
return options.reverse().reduce((argv, option) => option(argv), argv);
|
||||
}
|
||||
@ -141,19 +141,21 @@ function normalizeOptions(
|
||||
options: Options[0]
|
||||
): Options[0] {
|
||||
const base = { ...DEFAULT_OPTIONS, ...options };
|
||||
const pathPrefix =
|
||||
sourceProject.data.root !== '.' ? `${sourceProject.data.root}/` : '';
|
||||
return {
|
||||
...base,
|
||||
executorsJson: base.executorsJson
|
||||
? `${sourceProject.data.root}/${base.executorsJson}`
|
||||
? `${pathPrefix}${base.executorsJson}`
|
||||
: undefined,
|
||||
generatorsJson: base.generatorsJson
|
||||
? `${sourceProject.data.root}/${base.generatorsJson}`
|
||||
? `${pathPrefix}${base.generatorsJson}`
|
||||
: undefined,
|
||||
migrationsJson: base.migrationsJson
|
||||
? `${sourceProject.data.root}/${base.migrationsJson}`
|
||||
? `${pathPrefix}${base.migrationsJson}`
|
||||
: undefined,
|
||||
packageJson: base.packageJson
|
||||
? `${sourceProject.data.root}/${base.packageJson}`
|
||||
? `${pathPrefix}${base.packageJson}`
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "<%= importPath %>",
|
||||
"version": "0.0.1",
|
||||
"type": "commonjs"
|
||||
}
|
||||
@ -35,6 +35,7 @@ import {
|
||||
typesNodeVersion,
|
||||
} from '../../utils/versions';
|
||||
import jsInitGenerator from '../init/init';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
export async function libraryGenerator(
|
||||
tree: Tree,
|
||||
@ -44,7 +45,9 @@ export async function libraryGenerator(
|
||||
schema.directory
|
||||
);
|
||||
schema.directory = projectDirectory;
|
||||
const libsDir = layoutDirectory ?? getWorkspaceLayout(tree).libsDir;
|
||||
const libsDir = schema.rootProject
|
||||
? '.'
|
||||
: layoutDirectory ?? getWorkspaceLayout(tree).libsDir;
|
||||
return projectGenerator(tree, schema, libsDir, join(__dirname, './files'));
|
||||
}
|
||||
|
||||
@ -235,6 +238,7 @@ export async function addLint(
|
||||
`${options.projectRoot}/**/*.${options.js ? 'js' : 'ts'}`,
|
||||
],
|
||||
setParserOptionsProject: options.setParserOptionsProject,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
}
|
||||
|
||||
@ -308,7 +312,25 @@ function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) {
|
||||
toJS(tree);
|
||||
}
|
||||
|
||||
const packageJsonPath = join(options.projectRoot, 'package.json');
|
||||
const packageJsonPath = joinPathFragments(
|
||||
options.projectRoot,
|
||||
'package.json'
|
||||
);
|
||||
if (tree.exists(packageJsonPath)) {
|
||||
updateJson(tree, packageJsonPath, (json) => {
|
||||
json.name = options.importPath;
|
||||
json.version = '0.0.1';
|
||||
json.type = 'commonjs';
|
||||
return json;
|
||||
});
|
||||
} else {
|
||||
writeJson<PackageJson>(tree, packageJsonPath, {
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
type: 'commonjs',
|
||||
});
|
||||
}
|
||||
|
||||
if (options.config === 'npm-scripts') {
|
||||
updateJson(tree, packageJsonPath, (json) => {
|
||||
json.scripts = {
|
||||
@ -317,11 +339,14 @@ function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) {
|
||||
};
|
||||
return json;
|
||||
});
|
||||
} else if (!options.bundler || options.bundler === 'none') {
|
||||
} else if (
|
||||
(!options.bundler || options.bundler === 'none') &&
|
||||
!(options.projectRoot === '.')
|
||||
) {
|
||||
tree.delete(packageJsonPath);
|
||||
}
|
||||
|
||||
if (options.minimal) {
|
||||
if (options.minimal && !(options.projectRoot === '.')) {
|
||||
tree.delete(join(options.projectRoot, 'README.md'));
|
||||
}
|
||||
|
||||
@ -437,6 +462,8 @@ function normalizeOptions(
|
||||
const name = names(options.name).fileName;
|
||||
const projectDirectory = options.directory
|
||||
? `${names(options.directory).fileName}/${name}`
|
||||
: options.rootProject
|
||||
? '.'
|
||||
: name;
|
||||
|
||||
if (!options.unitTestRunner && options.bundler === 'vite') {
|
||||
@ -449,7 +476,9 @@ function normalizeOptions(
|
||||
options.linter = Linter.EsLint;
|
||||
}
|
||||
|
||||
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
const projectName = options.rootProject
|
||||
? name
|
||||
: projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
const fileName = getCaseAwareFileName({
|
||||
fileName: options.simpleModuleName ? name : projectName,
|
||||
pascalCaseFiles: options.pascalCaseFiles,
|
||||
|
||||
1
packages/js/src/utils/schema.d.ts
vendored
1
packages/js/src/utils/schema.d.ts
vendored
@ -32,6 +32,7 @@ export interface LibraryGeneratorSchema {
|
||||
bundler?: Bundler;
|
||||
skipTypeCheck?: boolean;
|
||||
minimal?: boolean;
|
||||
rootProject?: boolean;
|
||||
}
|
||||
|
||||
export interface ExecutorOptions {
|
||||
|
||||
@ -33,6 +33,13 @@
|
||||
"factory": "./src/generators/lint-checks/generator",
|
||||
"schema": "./src/generators/lint-checks/schema.json",
|
||||
"description": "Adds linting configuration to validate common json files for nx plugins."
|
||||
},
|
||||
"preset": {
|
||||
"factory": "./src/generators/preset/generator",
|
||||
"schema": "./src/generators/preset/schema.json",
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-workspace --preset @nrwl/nx-plugin`.",
|
||||
"hidden": true,
|
||||
"x-use-standalone-layout": true
|
||||
}
|
||||
},
|
||||
"schematics": {
|
||||
|
||||
@ -35,10 +35,13 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
||||
const { npmScope, appsDir: defaultAppsDir } = getWorkspaceLayout(host);
|
||||
const appsDir = layoutDirectory ?? defaultAppsDir;
|
||||
|
||||
const projectName = `${options.pluginName}-e2e`;
|
||||
const projectRoot = projectDirectory
|
||||
? joinPathFragments(appsDir, `${projectDirectory}-e2e`)
|
||||
: joinPathFragments(appsDir, projectName);
|
||||
const projectName = options.rootProject ? 'e2e' : `${options.pluginName}-e2e`;
|
||||
const projectRoot =
|
||||
projectDirectory && !options.rootProject
|
||||
? joinPathFragments(appsDir, `${projectDirectory}-e2e`)
|
||||
: options.rootProject
|
||||
? projectName
|
||||
: joinPathFragments(appsDir, projectName);
|
||||
const pluginPropertyName = names(options.pluginName).propertyName;
|
||||
|
||||
return {
|
||||
|
||||
@ -9,4 +9,5 @@ export interface Schema {
|
||||
minimal?: boolean;
|
||||
linter?: Linter;
|
||||
skipFormat?: boolean;
|
||||
rootProject?: boolean;
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ describe('NxPlugin Executor Generator', () => {
|
||||
|
||||
expect(() => tree.exists(`${libConfig.root}/executors.json`)).not.toThrow();
|
||||
expect(readJson(tree, `${libConfig.root}/package.json`).executors).toBe(
|
||||
'executors.json'
|
||||
'./executors.json'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@ -75,7 +75,7 @@ function createExecutorsJson(host: Tree, options: NormalizedSchema) {
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
(json) => {
|
||||
json.executors ??= 'executors.json';
|
||||
json.executors ??= './executors.json';
|
||||
return json;
|
||||
}
|
||||
);
|
||||
|
||||
@ -111,7 +111,7 @@ describe('NxPlugin Generator Generator', () => {
|
||||
tree.exists(`${libConfig.root}/generators.json`)
|
||||
).not.toThrow();
|
||||
expect(readJson(tree, `${libConfig.root}/package.json`).generators).toBe(
|
||||
'generators.json'
|
||||
'./generators.json'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ function createGeneratorsJson(host: Tree, options: NormalizedSchema) {
|
||||
host,
|
||||
joinPathFragments(options.projectRoot, 'package.json'),
|
||||
(json) => {
|
||||
json.generators ??= 'generators.json';
|
||||
json.generators ??= './generators.json';
|
||||
return json;
|
||||
}
|
||||
);
|
||||
|
||||
@ -15,7 +15,12 @@ import type { Schema } from './schema';
|
||||
import * as path from 'path';
|
||||
import { addMigrationJsonChecks } from '../lint-checks/generator';
|
||||
import type { Linter as EsLint } from 'eslint';
|
||||
import { PackageJson, readNxMigrateConfig } from 'nx/src/utils/package-json';
|
||||
import {
|
||||
NxMigrationsConfiguration,
|
||||
PackageJson,
|
||||
PackageJsonTargetConfiguration,
|
||||
readNxMigrateConfig,
|
||||
} from 'nx/src/utils/package-json';
|
||||
interface NormalizedSchema extends Schema {
|
||||
projectRoot: string;
|
||||
projectSourceRoot: string;
|
||||
@ -98,19 +103,25 @@ function updateMigrationsJson(host: Tree, options: NormalizedSchema) {
|
||||
}
|
||||
|
||||
function updatePackageJson(host: Tree, options: NormalizedSchema) {
|
||||
updateJson(host, path.join(options.projectRoot, 'package.json'), (json) => {
|
||||
if (!json['nx-migrations'] || !json['nx-migrations'].migrations) {
|
||||
if (json['nx-migrations']) {
|
||||
json['nx-migrations'].migrations = './migrations.json';
|
||||
} else {
|
||||
json['nx-migrations'] = {
|
||||
updateJson<PackageJson>(
|
||||
host,
|
||||
path.join(options.projectRoot, 'package.json'),
|
||||
(json) => {
|
||||
const migrationKey = json['ng-update'] ? 'ng-update' : 'nx-migrations';
|
||||
const preexistingValue = json[migrationKey];
|
||||
if (typeof preexistingValue === 'string') {
|
||||
return json;
|
||||
} else if (!json[migrationKey]) {
|
||||
json[migrationKey] = {
|
||||
migrations: './migrations.json',
|
||||
};
|
||||
} else if (preexistingValue.migrations) {
|
||||
preexistingValue.migrations = './migrations.json';
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
});
|
||||
return json;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function updateWorkspaceJson(host: Tree, options: NormalizedSchema) {
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"executors": {}
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"name": "<%= name %>",
|
||||
"version": "0.0.1",
|
||||
"generators": {}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "<%= npmPackageName %>",
|
||||
"version": "0.0.1",
|
||||
"main": "src/index.js",
|
||||
"generators": "./generators.json",
|
||||
"executors": "./executors.json"
|
||||
}
|
||||
@ -138,11 +138,7 @@ describe('NxPlugin Plugin Generator', () => {
|
||||
it('should not create generator and executor files for minimal setups', async () => {
|
||||
await pluginGenerator(tree, getSchema({ name: 'myPlugin', minimal: true }));
|
||||
|
||||
[
|
||||
'libs/my-plugin/project.json',
|
||||
'libs/my-plugin/generators.json',
|
||||
'libs/my-plugin/executors.json',
|
||||
].forEach((path) => expect(tree.exists(path)).toBeTruthy());
|
||||
expect(tree.exists('libs/my-plugin/project.json')).toBeTruthy();
|
||||
|
||||
[
|
||||
'libs/my-plugin/src/generators/my-plugin/schema.d.ts',
|
||||
@ -156,25 +152,6 @@ describe('NxPlugin Plugin Generator', () => {
|
||||
'libs/my-plugin/src/executors/build/schema.json',
|
||||
'libs/my-plugin/src/executors/build/schema.d.ts',
|
||||
].forEach((path) => expect(tree.exists(path)).toBeFalsy());
|
||||
|
||||
expect(tree.read('libs/my-plugin/generators.json', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"{
|
||||
\\"$schema\\": \\"http://json-schema.org/schema\\",
|
||||
\\"name\\": \\"my-plugin\\",
|
||||
\\"version\\": \\"0.0.1\\",
|
||||
\\"generators\\": {}
|
||||
}
|
||||
"
|
||||
`);
|
||||
expect(tree.read('libs/my-plugin/executors.json', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"{
|
||||
\\"$schema\\": \\"http://json-schema.org/schema\\",
|
||||
\\"executors\\": {}
|
||||
}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
describe('--unitTestRunner', () => {
|
||||
|
||||
@ -53,7 +53,7 @@ async function addFiles(host: Tree, options: NormalizedSchema) {
|
||||
});
|
||||
}
|
||||
|
||||
function updateWorkspaceJson(host: Tree, options: NormalizedSchema) {
|
||||
function updatePluginConfig(host: Tree, options: NormalizedSchema) {
|
||||
const project = readProjectConfiguration(host, options.name);
|
||||
|
||||
if (project.targets.build) {
|
||||
@ -100,13 +100,14 @@ export async function pluginGenerator(host: Tree, schema: Schema) {
|
||||
|
||||
addDependenciesToPackageJson(
|
||||
host,
|
||||
{},
|
||||
{
|
||||
'@nrwl/devkit': nxVersion,
|
||||
tslib: tsLibVersion,
|
||||
},
|
||||
{
|
||||
'@nrwl/jest': nxVersion,
|
||||
'@nrwl/js': nxVersion,
|
||||
'@swc-node/register': swcNodeVersion,
|
||||
tslib: tsLibVersion,
|
||||
}
|
||||
);
|
||||
|
||||
@ -115,7 +116,7 @@ export async function pluginGenerator(host: Tree, schema: Schema) {
|
||||
addSwcDependencies(host);
|
||||
|
||||
await addFiles(host, options);
|
||||
updateWorkspaceJson(host, options);
|
||||
updatePluginConfig(host, options);
|
||||
|
||||
if (options.e2eTestRunner !== 'none') {
|
||||
await e2eProjectGenerator(host, {
|
||||
@ -125,6 +126,7 @@ export async function pluginGenerator(host: Tree, schema: Schema) {
|
||||
npmPackageName: options.npmPackageName,
|
||||
minimal: options.minimal ?? false,
|
||||
skipFormat: true,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -14,4 +14,5 @@ export interface Schema {
|
||||
setParserOptionsProject?: boolean;
|
||||
compiler: 'swc' | 'tsc';
|
||||
minimal?: boolean;
|
||||
rootProject?: boolean;
|
||||
}
|
||||
|
||||
@ -31,9 +31,13 @@ export function normalizeOptions(
|
||||
const name = names(options.name).fileName;
|
||||
const fullProjectDirectory = projectDirectory
|
||||
? `${names(projectDirectory).fileName}/${name}`
|
||||
: options.rootProject
|
||||
? '.'
|
||||
: name;
|
||||
|
||||
const projectName = fullProjectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
const projectName = options.rootProject
|
||||
? name
|
||||
: fullProjectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
const fileName = projectName;
|
||||
const projectRoot = joinPathFragments(libsDir, fullProjectDirectory);
|
||||
|
||||
|
||||
30
packages/nx-plugin/src/generators/preset/generator.spec.ts
Normal file
30
packages/nx-plugin/src/generators/preset/generator.spec.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import {
|
||||
Tree,
|
||||
readProjectConfiguration,
|
||||
readJson,
|
||||
readNxJson,
|
||||
} from '@nrwl/devkit';
|
||||
|
||||
import generator from './generator';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
|
||||
describe('preset generator', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
});
|
||||
|
||||
it('should create a plugin', async () => {
|
||||
await generator(tree, {
|
||||
pluginName: 'my-plugin',
|
||||
});
|
||||
const config = readProjectConfiguration(tree, 'my-plugin');
|
||||
expect(config).toBeDefined();
|
||||
const packageJson = readJson<PackageJson>(tree, 'package.json');
|
||||
expect(packageJson.generators).toEqual('./generators.json');
|
||||
expect(packageJson.executors).toEqual('./executors.json');
|
||||
expect(readNxJson(tree).npmScope).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
45
packages/nx-plugin/src/generators/preset/generator.ts
Normal file
45
packages/nx-plugin/src/generators/preset/generator.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import {
|
||||
Tree,
|
||||
readJson,
|
||||
joinPathFragments,
|
||||
updateJson,
|
||||
updateNxJson,
|
||||
readNxJson,
|
||||
} from '@nrwl/devkit';
|
||||
import { Linter } from '@nrwl/linter';
|
||||
import { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { pluginGenerator } from '../plugin/plugin';
|
||||
import { PresetGeneratorSchema } from './schema';
|
||||
|
||||
export default async function (tree: Tree, options: PresetGeneratorSchema) {
|
||||
const task = await pluginGenerator(tree, {
|
||||
compiler: 'tsc',
|
||||
linter: Linter.EsLint,
|
||||
name: options.pluginName.includes('/')
|
||||
? options.pluginName.split('/')[1]
|
||||
: options.pluginName,
|
||||
skipFormat: false,
|
||||
skipLintChecks: false,
|
||||
skipTsConfig: false,
|
||||
unitTestRunner: 'jest',
|
||||
importPath: options.pluginName,
|
||||
rootProject: true,
|
||||
});
|
||||
|
||||
removeNpmScope(tree);
|
||||
moveNxPluginToDevDeps(tree);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
function removeNpmScope(tree: Tree) {
|
||||
updateNxJson(tree, { ...readNxJson(tree), npmScope: undefined });
|
||||
}
|
||||
function moveNxPluginToDevDeps(tree: Tree) {
|
||||
updateJson<PackageJson>(tree, 'package.json', (json) => {
|
||||
const nxPluginEntry = json.dependencies['@nrwl/nx-plugin'];
|
||||
delete json.dependencies['@nrwl/nx-plugin'];
|
||||
json.devDependencies['@nrwl/nx-plugin'] = nxPluginEntry;
|
||||
return json;
|
||||
});
|
||||
}
|
||||
3
packages/nx-plugin/src/generators/preset/schema.d.ts
vendored
Normal file
3
packages/nx-plugin/src/generators/preset/schema.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export interface PresetGeneratorSchema {
|
||||
pluginName: string;
|
||||
}
|
||||
16
packages/nx-plugin/src/generators/preset/schema.json
Normal file
16
packages/nx-plugin/src/generators/preset/schema.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"cli": "nx",
|
||||
"$id": "NxPluginPreset",
|
||||
"title": "Generator ran by create-nx-plugin",
|
||||
"description": "Initializes a workspace with an nx-plugin inside of it. Use as: `create-nx-plugin` or `create-nx-workspace --preset @nrwl/nx-plugin`.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pluginName": {
|
||||
"type": "string",
|
||||
"description": "Plugin name",
|
||||
"aliases": ["name"]
|
||||
}
|
||||
},
|
||||
"required": ["pluginName"]
|
||||
}
|
||||
@ -13,31 +13,34 @@ function removeSpecialFlags(generatorOptions: { [p: string]: any }): void {
|
||||
export async function newWorkspace(cwd: string, args: { [k: string]: any }) {
|
||||
const ws = new Workspaces(null);
|
||||
|
||||
return handleErrors(false, async () => {
|
||||
const isInteractive = args.interactive;
|
||||
const { normalizedGeneratorName, schema, implementationFactory } =
|
||||
ws.readGenerator('@nrwl/workspace/generators.json', 'new');
|
||||
removeSpecialFlags(args);
|
||||
const combinedOpts = await combineOptionsForGenerator(
|
||||
args,
|
||||
'@nrwl/workspace/generators.json',
|
||||
normalizedGeneratorName,
|
||||
null,
|
||||
null,
|
||||
schema,
|
||||
isInteractive,
|
||||
null,
|
||||
null,
|
||||
false
|
||||
);
|
||||
return handleErrors(
|
||||
process.env.NX_VERBOSE_LOGGING === 'true' || args.verbose,
|
||||
async () => {
|
||||
const isInteractive = args.interactive;
|
||||
const { normalizedGeneratorName, schema, implementationFactory } =
|
||||
ws.readGenerator('@nrwl/workspace/generators.json', 'new');
|
||||
removeSpecialFlags(args);
|
||||
const combinedOpts = await combineOptionsForGenerator(
|
||||
args,
|
||||
'@nrwl/workspace/generators.json',
|
||||
normalizedGeneratorName,
|
||||
null,
|
||||
null,
|
||||
schema,
|
||||
isInteractive,
|
||||
null,
|
||||
null,
|
||||
false
|
||||
);
|
||||
|
||||
const host = new FsTree(cwd, false);
|
||||
const implementation = implementationFactory();
|
||||
const task = await implementation(host, combinedOpts);
|
||||
flushChanges(cwd, host.listChanges());
|
||||
host.lock();
|
||||
if (task) {
|
||||
await task();
|
||||
const host = new FsTree(cwd, false);
|
||||
const implementation = implementationFactory();
|
||||
const task = await implementation(host, combinedOpts);
|
||||
flushChanges(cwd, host.listChanges());
|
||||
host.lock();
|
||||
if (task) {
|
||||
await task();
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
@ -77,10 +77,16 @@ export function createPackageJson(
|
||||
);
|
||||
// for standalone projects we don't want to include all the root dependencies
|
||||
if (graph.nodes[projectName].data.root === '.') {
|
||||
packageJson = {
|
||||
name: packageJson.name,
|
||||
version: packageJson.version,
|
||||
};
|
||||
// TODO: We should probably think more on this - Nx can't always
|
||||
// detect all external dependencies, and there's not a way currently
|
||||
// to tell Nx that we need one of these deps. For non-standalone projects
|
||||
// we tell people to add it to the package.json of the project, and we
|
||||
// merge it. For standalone, this pattern doesn't work because of this piece of code.
|
||||
// It breaks expectations, but also, I don't know another way around it currently.
|
||||
// If Nx doesn't pick up a dep, say some css lib that is only imported in a .scss file,
|
||||
// we need to be able to tell it to keep that dep in the generated package.json.
|
||||
delete packageJson.dependencies;
|
||||
delete packageJson.devDependencies;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
@ -107,6 +107,8 @@
|
||||
"@nrwl/workspace": ["packages/workspace"],
|
||||
"@nrwl/workspace/*": ["packages/workspace/*"],
|
||||
"@nrwl/workspace/testing": ["packages/workspace/testing"],
|
||||
"create-nx-workspace": ["packages/create-nx-workspace/index.ts"],
|
||||
"create-nx-workspace/*": ["packages/create-nx-workspace/*"],
|
||||
"nx": ["packages/nx"],
|
||||
"nx-dev/ui-primitives": ["nx-dev/ui-primitives/src/index.ts"],
|
||||
"nx/*": ["packages/nx/*"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user