feat(core): update create-nx-plugin to generate cli library (#15994)
This commit is contained in:
parent
16e4061b5d
commit
840048480f
@ -5579,6 +5579,14 @@
|
|||||||
"isExternal": false,
|
"isExternal": false,
|
||||||
"disableCollapsible": false
|
"disableCollapsible": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "create-package",
|
||||||
|
"path": "/packages/nx-plugin/generators/create-package",
|
||||||
|
"name": "create-package",
|
||||||
|
"children": [],
|
||||||
|
"isExternal": false,
|
||||||
|
"disableCollapsible": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "e2e-project",
|
"id": "e2e-project",
|
||||||
"path": "/packages/nx-plugin/generators/e2e-project",
|
"path": "/packages/nx-plugin/generators/e2e-project",
|
||||||
|
|||||||
@ -1810,6 +1810,15 @@
|
|||||||
"path": "/packages/nx-plugin/generators/plugin",
|
"path": "/packages/nx-plugin/generators/plugin",
|
||||||
"type": "generator"
|
"type": "generator"
|
||||||
},
|
},
|
||||||
|
"/packages/nx-plugin/generators/create-package": {
|
||||||
|
"description": "Create a package which can be used by npx to create a new workspace",
|
||||||
|
"file": "generated/packages/nx-plugin/generators/create-package.json",
|
||||||
|
"hidden": false,
|
||||||
|
"name": "create-package",
|
||||||
|
"originalFilePath": "/packages/nx-plugin/src/generators/create-package/schema.json",
|
||||||
|
"path": "/packages/nx-plugin/generators/create-package",
|
||||||
|
"type": "generator"
|
||||||
|
},
|
||||||
"/packages/nx-plugin/generators/e2e-project": {
|
"/packages/nx-plugin/generators/e2e-project": {
|
||||||
"description": "Create a E2E application for a Nx Plugin.",
|
"description": "Create a E2E application for a Nx Plugin.",
|
||||||
"file": "generated/packages/nx-plugin/generators/e2e-project.json",
|
"file": "generated/packages/nx-plugin/generators/e2e-project.json",
|
||||||
|
|||||||
@ -1788,6 +1788,15 @@
|
|||||||
"path": "nx-plugin/generators/plugin",
|
"path": "nx-plugin/generators/plugin",
|
||||||
"type": "generator"
|
"type": "generator"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Create a package which can be used by npx to create a new workspace",
|
||||||
|
"file": "generated/packages/nx-plugin/generators/create-package.json",
|
||||||
|
"hidden": false,
|
||||||
|
"name": "create-package",
|
||||||
|
"originalFilePath": "/packages/nx-plugin/src/generators/create-package/schema.json",
|
||||||
|
"path": "nx-plugin/generators/create-package",
|
||||||
|
"type": "generator"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Create a E2E application for a Nx Plugin.",
|
"description": "Create a E2E application for a Nx Plugin.",
|
||||||
"file": "generated/packages/nx-plugin/generators/e2e-project.json",
|
"file": "generated/packages/nx-plugin/generators/e2e-project.json",
|
||||||
|
|||||||
@ -117,7 +117,8 @@
|
|||||||
"runInBand": {
|
"runInBand": {
|
||||||
"alias": "i",
|
"alias": "i",
|
||||||
"description": "Run all tests serially in the current process (rather than creating a worker pool of child processes that run tests). This is sometimes useful for debugging, but such use cases are pretty rare. Useful for CI. (https://jestjs.io/docs/cli#--runinband)",
|
"description": "Run all tests serially in the current process (rather than creating a worker pool of child processes that run tests). This is sometimes useful for debugging, but such use cases are pretty rare. Useful for CI. (https://jestjs.io/docs/cli#--runinband)",
|
||||||
"type": "boolean"
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
},
|
},
|
||||||
"showConfig": {
|
"showConfig": {
|
||||||
"description": "Print your Jest config and then exits. (https://jestjs.io/docs/en/cli#--showconfig)",
|
"description": "Print your Jest config and then exits. (https://jestjs.io/docs/en/cli#--showconfig)",
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"name": "create-package",
|
||||||
|
"factory": "./src/generators/create-package/create-package",
|
||||||
|
"schema": {
|
||||||
|
"$schema": "http://json-schema.org/schema",
|
||||||
|
"cli": "nx",
|
||||||
|
"$id": "NxPluginCreatePackage",
|
||||||
|
"title": "Create a framework package",
|
||||||
|
"description": "Create a framework package that uses Nx CLI.",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The package name of cli, e.g. `create-framework-package`. Note this must be a valid NPM name to be published.",
|
||||||
|
"$default": { "$source": "argv", "index": 0 },
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the generator project.",
|
||||||
|
"alias": "p",
|
||||||
|
"$default": { "$source": "projectName" },
|
||||||
|
"x-prompt": "What is the name of the project for the generator?",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
|
"unitTestRunner": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["jest", "none"],
|
||||||
|
"description": "Test runner to use for unit tests.",
|
||||||
|
"default": "jest"
|
||||||
|
},
|
||||||
|
"directory": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A directory where the app is placed."
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint"],
|
||||||
|
"default": "eslint"
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Add tags to the library (used for linting).",
|
||||||
|
"alias": "t"
|
||||||
|
},
|
||||||
|
"skipFormat": {
|
||||||
|
"description": "Skip formatting files.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"x-priority": "internal"
|
||||||
|
},
|
||||||
|
"compiler": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["tsc", "swc"],
|
||||||
|
"default": "tsc",
|
||||||
|
"description": "The compiler used by the build and test targets."
|
||||||
|
},
|
||||||
|
"e2eTestRunner": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["jest", "none"],
|
||||||
|
"description": "Test runner to use for end to end (E2E) tests.",
|
||||||
|
"default": "jest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["name", "project"],
|
||||||
|
"presets": []
|
||||||
|
},
|
||||||
|
"description": "Create a package which can be used by npx to create a new workspace",
|
||||||
|
"implementation": "/packages/nx-plugin/src/generators/create-package/create-package.ts",
|
||||||
|
"aliases": [],
|
||||||
|
"hidden": false,
|
||||||
|
"path": "/packages/nx-plugin/src/generators/create-package/schema.json",
|
||||||
|
"type": "generator"
|
||||||
|
}
|
||||||
@ -49,6 +49,12 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add an eslint configuration for plugin json files."
|
"description": "Do not add an eslint configuration for plugin json files."
|
||||||
|
},
|
||||||
|
"skipFormat": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Skip formatting files.",
|
||||||
|
"default": false,
|
||||||
|
"x-priority": "internal"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["project", "name"],
|
"required": ["project", "name"],
|
||||||
|
|||||||
@ -13,6 +13,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Plugin name",
|
"description": "Plugin name",
|
||||||
"aliases": ["name"]
|
"aliases": ["name"]
|
||||||
|
},
|
||||||
|
"createPackageName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of package which creates a workspace"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["pluginName"],
|
"required": ["pluginName"],
|
||||||
|
|||||||
@ -92,6 +92,7 @@
|
|||||||
"enum": ["cypress", "jest", "detox", "none"]
|
"enum": ["cypress", "jest", "detox", "none"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"required": ["preset", "name"],
|
||||||
"presets": []
|
"presets": []
|
||||||
},
|
},
|
||||||
"description": "Create application in an empty workspace.",
|
"description": "Create application in an empty workspace.",
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import {
|
|||||||
createFile,
|
createFile,
|
||||||
expectTestsPass,
|
expectTestsPass,
|
||||||
getPackageManagerCommand,
|
getPackageManagerCommand,
|
||||||
killPorts,
|
|
||||||
newProject,
|
newProject,
|
||||||
readJson,
|
readJson,
|
||||||
readProjectConfig,
|
readProjectConfig,
|
||||||
@ -410,4 +409,31 @@ describe('Nx Plugin', () => {
|
|||||||
expect(pluginProject.tags).toEqual(['e2etag', 'e2ePackage']);
|
expect(pluginProject.tags).toEqual(['e2etag', 'e2ePackage']);
|
||||||
}, 90000);
|
}, 90000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be able to generate a create-package plugin ', async () => {
|
||||||
|
const plugin = uniq('plugin');
|
||||||
|
const createAppName = `create-${plugin}-app`;
|
||||||
|
runCLI(`generate @nrwl/nx-plugin:plugin ${plugin}`);
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/nx-plugin:create-package ${createAppName} --project=${plugin}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const buildResults = runCLI(`build ${createAppName}`);
|
||||||
|
expect(buildResults).toContain('Done compiling TypeScript files');
|
||||||
|
|
||||||
|
checkFilesExist(
|
||||||
|
`libs/${plugin}/src/generators/preset`,
|
||||||
|
`libs/${createAppName}`,
|
||||||
|
`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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -21,6 +21,7 @@ describe('create-nx-plugin', () => {
|
|||||||
|
|
||||||
runCreatePlugin(pluginName, {
|
runCreatePlugin(pluginName, {
|
||||||
packageManager,
|
packageManager,
|
||||||
|
extraArgs: `--createPackageName='false'`,
|
||||||
});
|
});
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
@ -31,7 +32,7 @@ describe('create-nx-plugin', () => {
|
|||||||
|
|
||||||
runCLI(`build ${pluginName}`);
|
runCLI(`build ${pluginName}`);
|
||||||
|
|
||||||
checkFilesExist(`dist/package.json`);
|
checkFilesExist(`dist/package.json`, `dist/src/index.js`);
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/nx-plugin:generator ${generatorName} --project=${pluginName}`
|
`generate @nrwl/nx-plugin:generator ${generatorName} --project=${pluginName}`
|
||||||
@ -48,4 +49,22 @@ describe('create-nx-plugin', () => {
|
|||||||
`dist/executors.json`
|
`dist/executors.json`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be able to create a repo with create workspace cli', () => {
|
||||||
|
const pluginName = uniq('plugin');
|
||||||
|
|
||||||
|
runCreatePlugin(pluginName, {
|
||||||
|
packageManager,
|
||||||
|
extraArgs: `--createPackageName=create-${pluginName}-package`,
|
||||||
|
});
|
||||||
|
|
||||||
|
runCLI(`build ${pluginName}`);
|
||||||
|
checkFilesExist(`dist/package.json`, `dist/generators.json`);
|
||||||
|
|
||||||
|
runCLI(`build create-${pluginName}-package`);
|
||||||
|
checkFilesExist(`dist/create-${pluginName}-package/bin/index.js`);
|
||||||
|
|
||||||
|
expect(() => runCLI(`e2e e2e`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`e2e create-${pluginName}-package-e2e`)).not.toThrow();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -43,34 +43,44 @@ export const yargsDecorator = {
|
|||||||
|
|
||||||
const nxVersion = require('../package.json').version;
|
const nxVersion = require('../package.json').version;
|
||||||
|
|
||||||
function determinePluginName(parsedArgs: CreateNxPluginArguments) {
|
async function determinePluginName(
|
||||||
|
parsedArgs: CreateNxPluginArguments
|
||||||
|
): Promise<string> {
|
||||||
if (parsedArgs.pluginName) {
|
if (parsedArgs.pluginName) {
|
||||||
return Promise.resolve(parsedArgs.pluginName);
|
return parsedArgs.pluginName;
|
||||||
}
|
}
|
||||||
|
|
||||||
return enquirer
|
const results = await enquirer.prompt<{ pluginName: string }>([
|
||||||
.prompt([
|
{
|
||||||
{
|
name: 'pluginName',
|
||||||
name: 'pluginName',
|
message: `Plugin name `,
|
||||||
message: `Plugin name `,
|
type: 'input',
|
||||||
type: 'input',
|
validate: (s_1) => (s_1.length ? true : 'Plugin name cannot be empty'),
|
||||||
validate: (s) => (s.length ? true : 'Name cannot be empty'),
|
},
|
||||||
},
|
]);
|
||||||
])
|
return results.pluginName;
|
||||||
.then((a: { pluginName: string }) => {
|
}
|
||||||
if (!a.pluginName) {
|
|
||||||
output.error({
|
async function determineCreatePackageName(
|
||||||
title: 'Invalid name',
|
parsedArgs: CreateNxPluginArguments
|
||||||
bodyLines: [`Name cannot be empty`],
|
): Promise<string> {
|
||||||
});
|
if (parsedArgs.createPackageName) {
|
||||||
process.exit(1);
|
return parsedArgs.createPackageName;
|
||||||
}
|
}
|
||||||
return a.pluginName;
|
|
||||||
});
|
const results = await enquirer.prompt<{ createPackageName: string }>([
|
||||||
|
{
|
||||||
|
name: 'createPackageName',
|
||||||
|
message: `Create a package which can be used by npx to create a new workspace (Leave blank to not create this package)`,
|
||||||
|
type: 'input',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return results.createPackageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateNxPluginArguments {
|
interface CreateNxPluginArguments {
|
||||||
pluginName: string;
|
pluginName: string;
|
||||||
|
createPackageName?: string;
|
||||||
packageManager: PackageManager;
|
packageManager: PackageManager;
|
||||||
ci: CI;
|
ci: CI;
|
||||||
allPrompts: boolean;
|
allPrompts: boolean;
|
||||||
@ -89,11 +99,16 @@ export const commandsObject: yargs.Argv<CreateNxPluginArguments> = yargs
|
|||||||
'Create a new Nx plugin workspace',
|
'Create a new Nx plugin workspace',
|
||||||
(yargs) =>
|
(yargs) =>
|
||||||
withOptions(
|
withOptions(
|
||||||
yargs.positional('pluginName', {
|
yargs
|
||||||
describe: chalk.dim`Plugin name`,
|
.positional('pluginName', {
|
||||||
type: 'string',
|
describe: chalk.dim`Plugin name`,
|
||||||
alias: ['name'],
|
type: 'string',
|
||||||
}),
|
alias: ['name'],
|
||||||
|
})
|
||||||
|
.option('createPackageName', {
|
||||||
|
describe: 'Name of the CLI package to create workspace with plugin',
|
||||||
|
type: 'string',
|
||||||
|
}),
|
||||||
withNxCloud,
|
withNxCloud,
|
||||||
withCI,
|
withCI,
|
||||||
withAllPrompts,
|
withAllPrompts,
|
||||||
@ -164,19 +179,21 @@ async function normalizeArgsMiddleware(
|
|||||||
argv: yargs.Arguments<CreateNxPluginArguments>
|
argv: yargs.Arguments<CreateNxPluginArguments>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const name = await determinePluginName(argv);
|
const pluginName = await determinePluginName(argv);
|
||||||
|
const createPackageName = await determineCreatePackageName(argv);
|
||||||
const packageManager = await determinePackageManager(argv);
|
const packageManager = await determinePackageManager(argv);
|
||||||
const defaultBase = await determineDefaultBase(argv);
|
const defaultBase = await determineDefaultBase(argv);
|
||||||
const nxCloud = await determineNxCloud(argv);
|
const nxCloud = await determineNxCloud(argv);
|
||||||
const ci = await determineCI(argv, nxCloud);
|
const ci = await determineCI(argv, nxCloud);
|
||||||
|
|
||||||
Object.assign(argv, {
|
Object.assign(argv, {
|
||||||
name,
|
pluginName,
|
||||||
|
createPackageName,
|
||||||
nxCloud,
|
nxCloud,
|
||||||
packageManager,
|
packageManager,
|
||||||
defaultBase,
|
defaultBase,
|
||||||
ci,
|
ci,
|
||||||
});
|
} as Partial<CreateNxPluginArguments & CreateWorkspaceOptions>);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
@ -221,6 +221,7 @@ async function normalizeArgsMiddleware(
|
|||||||
} else if (monorepoStyle === 'node-standalone') {
|
} else if (monorepoStyle === 'node-standalone') {
|
||||||
preset = Preset.NodeStandalone;
|
preset = Preset.NodeStandalone;
|
||||||
} else {
|
} else {
|
||||||
|
// when choose integrated monorepo, further prompt for preset
|
||||||
preset = await determinePreset(argv);
|
preset = await determinePreset(argv);
|
||||||
}
|
}
|
||||||
} else if (argv.preset === 'react') {
|
} else if (argv.preset === 'react') {
|
||||||
|
|||||||
@ -27,8 +27,6 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/nrwl/nx/issues"
|
"url": "https://github.com/nrwl/nx/issues"
|
||||||
},
|
},
|
||||||
"main": "./index.js",
|
|
||||||
"typings": "./index.d.ts",
|
|
||||||
"homepage": "https://nx.dev",
|
"homepage": "https://nx.dev",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
"build-base": {
|
"build-base": {
|
||||||
"executor": "@nrwl/js:tsc",
|
"executor": "@nrwl/js:tsc",
|
||||||
"options": {
|
"options": {
|
||||||
"main": "packages/create-nx-workspace/bin/create-nx-workspace.ts",
|
"main": "packages/create-nx-workspace/index.ts",
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
"input": "packages/create-nx-workspace",
|
"input": "packages/create-nx-workspace",
|
||||||
|
|||||||
@ -39,7 +39,9 @@ export async function createPreset<T extends CreateWorkspaceOptions>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NX_VERBOSE_LOGGING !== 'true') {
|
if (
|
||||||
|
!(process.env.NX_VERBOSE_LOGGING === 'true' || args.includes('--verbose'))
|
||||||
|
) {
|
||||||
args = '--quiet ' + args;
|
args = '--quiet ' + args;
|
||||||
}
|
}
|
||||||
const command = `g ${preset}:preset ${args}`;
|
const command = `g ${preset}:preset ${args}`;
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { PackageManager } from './utils/package-manager';
|
import { PackageManager } from './utils/package-manager';
|
||||||
|
import { CI } from './utils/ci/ci-list';
|
||||||
|
|
||||||
export interface CreateWorkspaceOptions {
|
export interface CreateWorkspaceOptions {
|
||||||
name: string; // Workspace name (e.g. org name)
|
name: string; // Workspace name (e.g. org name)
|
||||||
packageManager: PackageManager; // Package manager to use
|
packageManager: PackageManager; // Package manager to use
|
||||||
nxCloud: boolean; // Enable Nx Cloud
|
nxCloud: boolean; // Enable Nx Cloud
|
||||||
|
presetVersion?: string; // Version of the preset to use
|
||||||
/**
|
/**
|
||||||
* @description Enable interactive mode with presets
|
* @description Enable interactive mode with presets
|
||||||
* @default true
|
* @default true
|
||||||
@ -60,7 +60,7 @@ export async function createWorkspace<T extends CreateWorkspaceOptions>(
|
|||||||
nxCloud && nxCloudInstallRes?.code === 0
|
nxCloud && nxCloudInstallRes?.code === 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!skipGit) {
|
if (!skipGit && commit) {
|
||||||
try {
|
try {
|
||||||
await initializeGitRepo(directory, { defaultBase, commit });
|
await initializeGitRepo(directory, { defaultBase, commit });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@ -5,18 +5,19 @@ import { isKnownPreset } from './preset';
|
|||||||
/**
|
/**
|
||||||
* This function is used to check if a preset is a third party preset.
|
* This function is used to check if a preset is a third party preset.
|
||||||
* @param 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(
|
export async function getThirdPartyPreset(
|
||||||
preset?: string
|
preset?: string
|
||||||
): Promise<string | null> {
|
): Promise<string | null> {
|
||||||
if (preset && !isKnownPreset(preset)) {
|
if (preset && !isKnownPreset(preset)) {
|
||||||
|
// extract the package name from the preset
|
||||||
const packageName = preset.match(/.+@/)
|
const packageName = preset.match(/.+@/)
|
||||||
? preset[0] + preset.substring(1).split('@')[0]
|
? preset[0] + preset.substring(1).split('@')[0]
|
||||||
: preset;
|
: preset;
|
||||||
const validateResult = validateNpmPackage(packageName);
|
const validateResult = validateNpmPackage(packageName);
|
||||||
if (validateResult.validForNewPackages) {
|
if (validateResult.validForNewPackages) {
|
||||||
return Promise.resolve(preset);
|
return Promise.resolve(packageName);
|
||||||
} else {
|
} else {
|
||||||
//! Error here
|
//! Error here
|
||||||
output.error({
|
output.error({
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { addDependenciesToPackageJson, Tree } from '@nx/devkit';
|
|||||||
import { tsLibVersion } from '../versions';
|
import { tsLibVersion } from '../versions';
|
||||||
|
|
||||||
export function addTsLibDependencies(tree: Tree) {
|
export function addTsLibDependencies(tree: Tree) {
|
||||||
addDependenciesToPackageJson(
|
return addDependenciesToPackageJson(
|
||||||
tree,
|
tree,
|
||||||
{
|
{
|
||||||
tslib: tsLibVersion,
|
tslib: tsLibVersion,
|
||||||
|
|||||||
@ -8,6 +8,11 @@
|
|||||||
"schema": "./src/generators/plugin/schema.json",
|
"schema": "./src/generators/plugin/schema.json",
|
||||||
"description": "Create a Nx Plugin."
|
"description": "Create a Nx Plugin."
|
||||||
},
|
},
|
||||||
|
"create-package": {
|
||||||
|
"factory": "./src/generators/create-package/create-package",
|
||||||
|
"schema": "./src/generators/create-package/schema.json",
|
||||||
|
"description": "Create a package which can be used by npx to create a new workspace"
|
||||||
|
},
|
||||||
"e2e-project": {
|
"e2e-project": {
|
||||||
"factory": "./src/generators/e2e-project/e2e",
|
"factory": "./src/generators/e2e-project/e2e",
|
||||||
"schema": "./src/generators/e2e-project/schema.json",
|
"schema": "./src/generators/e2e-project/schema.json",
|
||||||
@ -47,6 +52,11 @@
|
|||||||
"schema": "./src/generators/plugin/schema.json",
|
"schema": "./src/generators/plugin/schema.json",
|
||||||
"description": "Create a Nx Plugin."
|
"description": "Create a Nx Plugin."
|
||||||
},
|
},
|
||||||
|
"create-package": {
|
||||||
|
"factory": "./src/generators/create-package/create-package#createPackageSchematic",
|
||||||
|
"schema": "./src/generators/create-package/schema.json",
|
||||||
|
"description": "Create a package which can be used by npx to create a new workspace"
|
||||||
|
},
|
||||||
"e2e-project": {
|
"e2e-project": {
|
||||||
"factory": "./src/generators/e2e-project/e2e#e2eProjectSchematic",
|
"factory": "./src/generators/e2e-project/e2e#e2eProjectSchematic",
|
||||||
"schema": "./src/generators/e2e-project/schema.json",
|
"schema": "./src/generators/e2e-project/schema.json",
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
export * from './src/generators/create-package/create-package';
|
||||||
export * from './src/generators/e2e-project/e2e';
|
export * from './src/generators/e2e-project/e2e';
|
||||||
export * from './src/generators/executor/executor';
|
export * from './src/generators/executor/executor';
|
||||||
export * from './src/generators/generator/generator';
|
export * from './src/generators/generator/generator';
|
||||||
|
|||||||
@ -128,7 +128,8 @@
|
|||||||
"runInBand": {
|
"runInBand": {
|
||||||
"alias": "i",
|
"alias": "i",
|
||||||
"description": "Run all tests serially in the current process (rather than creating a worker pool of child processes that run tests). This is sometimes useful for debugging, but such use cases are pretty rare. Useful for CI. (https://jestjs.io/docs/cli#--runinband)",
|
"description": "Run all tests serially in the current process (rather than creating a worker pool of child processes that run tests). This is sometimes useful for debugging, but such use cases are pretty rare. Useful for CI. (https://jestjs.io/docs/cli#--runinband)",
|
||||||
"type": "boolean"
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
},
|
},
|
||||||
"showConfig": {
|
"showConfig": {
|
||||||
"description": "Print your Jest config and then exits. (https://jestjs.io/docs/en/cli#--showconfig)",
|
"description": "Print your Jest config and then exits. (https://jestjs.io/docs/en/cli#--showconfig)",
|
||||||
|
|||||||
@ -0,0 +1,119 @@
|
|||||||
|
import {
|
||||||
|
joinPathFragments,
|
||||||
|
readJson,
|
||||||
|
readProjectConfiguration,
|
||||||
|
Tree,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
|
import { Linter } from '@nx/linter';
|
||||||
|
import { PackageJson } from 'nx/src/utils/package-json';
|
||||||
|
import pluginGenerator from '../plugin/plugin';
|
||||||
|
import { createPackageGenerator } from './create-package';
|
||||||
|
import { CreatePackageSchema } from './schema';
|
||||||
|
|
||||||
|
const getSchema: (
|
||||||
|
overrides?: Partial<CreatePackageSchema>
|
||||||
|
) => CreatePackageSchema = (overrides = {}) => ({
|
||||||
|
name: 'create-a-workspace',
|
||||||
|
project: 'my-plugin',
|
||||||
|
compiler: 'tsc',
|
||||||
|
skipTsConfig: false,
|
||||||
|
skipFormat: false,
|
||||||
|
skipLintChecks: false,
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
...overrides,
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('NxPlugin Create Package Generator', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
|
await pluginGenerator(tree, {
|
||||||
|
name: 'my-plugin',
|
||||||
|
compiler: 'tsc',
|
||||||
|
skipTsConfig: false,
|
||||||
|
skipFormat: false,
|
||||||
|
skipLintChecks: false,
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the project.json file', async () => {
|
||||||
|
await createPackageGenerator(tree, getSchema());
|
||||||
|
const project = readProjectConfiguration(tree, 'create-a-workspace');
|
||||||
|
expect(project.root).toEqual('libs/create-a-workspace');
|
||||||
|
expect(project.sourceRoot).toEqual('libs/create-a-workspace/bin');
|
||||||
|
expect(project.targets.build).toEqual({
|
||||||
|
executor: '@nx/js:tsc',
|
||||||
|
outputs: ['{options.outputPath}'],
|
||||||
|
options: {
|
||||||
|
outputPath: 'dist/libs/create-a-workspace',
|
||||||
|
tsConfig: 'libs/create-a-workspace/tsconfig.lib.json',
|
||||||
|
main: 'libs/create-a-workspace/bin/index.ts',
|
||||||
|
assets: ['libs/create-a-workspace/*.md'],
|
||||||
|
updateBuildableProjectDepsInPackageJson: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should place the create-package plugin in a directory', async () => {
|
||||||
|
await createPackageGenerator(
|
||||||
|
tree,
|
||||||
|
getSchema({
|
||||||
|
directory: 'plugins',
|
||||||
|
} as Partial<CreatePackageSchema>)
|
||||||
|
);
|
||||||
|
const project = readProjectConfiguration(
|
||||||
|
tree,
|
||||||
|
'plugins-create-a-workspace'
|
||||||
|
);
|
||||||
|
expect(project.root).toEqual('libs/plugins/create-a-workspace');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should specify tsc as compiler', async () => {
|
||||||
|
await createPackageGenerator(
|
||||||
|
tree,
|
||||||
|
getSchema({
|
||||||
|
compiler: 'tsc',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const { build } = readProjectConfiguration(
|
||||||
|
tree,
|
||||||
|
'create-a-workspace'
|
||||||
|
).targets;
|
||||||
|
|
||||||
|
expect(build.executor).toEqual('@nx/js:tsc');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should specify swc as compiler', async () => {
|
||||||
|
await createPackageGenerator(
|
||||||
|
tree,
|
||||||
|
getSchema({
|
||||||
|
compiler: 'swc',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const { build } = readProjectConfiguration(
|
||||||
|
tree,
|
||||||
|
'create-a-workspace'
|
||||||
|
).targets;
|
||||||
|
|
||||||
|
expect(build.executor).toEqual('@nx/js:swc');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should use name as default for the package.json's name", async () => {
|
||||||
|
await createPackageGenerator(tree, getSchema());
|
||||||
|
|
||||||
|
const { root } = readProjectConfiguration(tree, 'create-a-workspace');
|
||||||
|
const { name } = readJson<PackageJson>(
|
||||||
|
tree,
|
||||||
|
joinPathFragments(root, 'package.json')
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(name).toEqual('create-a-workspace');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,211 @@
|
|||||||
|
import {
|
||||||
|
addDependenciesToPackageJson,
|
||||||
|
readProjectConfiguration,
|
||||||
|
Tree,
|
||||||
|
generateFiles,
|
||||||
|
readJson,
|
||||||
|
convertNxGenerator,
|
||||||
|
formatFiles,
|
||||||
|
updateProjectConfiguration,
|
||||||
|
updateJson,
|
||||||
|
GeneratorCallback,
|
||||||
|
runTasksInSerial,
|
||||||
|
joinPathFragments,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||||
|
import { nxVersion } from 'nx/src/utils/versions';
|
||||||
|
import generatorGenerator from '../generator/generator';
|
||||||
|
import { CreatePackageSchema } from './schema';
|
||||||
|
import { NormalizedSchema, normalizeSchema } from './utils/normalize-schema';
|
||||||
|
import e2eProjectGenerator from '../e2e-project/e2e';
|
||||||
|
import { hasGenerator } from '../../utils/has-generator';
|
||||||
|
|
||||||
|
export async function createPackageGenerator(
|
||||||
|
host: Tree,
|
||||||
|
schema: CreatePackageSchema
|
||||||
|
) {
|
||||||
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
|
const options = normalizeSchema(host, schema);
|
||||||
|
const pluginPackageName = await addPresetGenerator(host, options);
|
||||||
|
|
||||||
|
const installTask = addDependenciesToPackageJson(
|
||||||
|
host,
|
||||||
|
{
|
||||||
|
'create-nx-workspace': nxVersion,
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
tasks.push(installTask);
|
||||||
|
|
||||||
|
await createCliPackage(host, options, pluginPackageName);
|
||||||
|
if (options.e2eTestRunner !== 'none') {
|
||||||
|
tasks.push(await addE2eProject(host, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.skipFormat) {
|
||||||
|
await formatFiles(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
return runTasksInSerial(...tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
): Promise<string> {
|
||||||
|
const { root: projectRoot } = readProjectConfiguration(host, schema.project);
|
||||||
|
if (!hasGenerator(host, schema.project, 'preset')) {
|
||||||
|
await generatorGenerator(host, {
|
||||||
|
name: 'preset',
|
||||||
|
project: schema.project,
|
||||||
|
unitTestRunner: schema.unitTestRunner,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return readJson(host, joinPathFragments(projectRoot, 'package.json'))?.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createCliPackage(
|
||||||
|
host: Tree,
|
||||||
|
options: NormalizedSchema,
|
||||||
|
pluginPackageName: string
|
||||||
|
) {
|
||||||
|
await jsLibraryGenerator(host, {
|
||||||
|
...options,
|
||||||
|
rootProject: false,
|
||||||
|
config: 'project',
|
||||||
|
publishable: true,
|
||||||
|
bundler: options.bundler,
|
||||||
|
importPath: options.name,
|
||||||
|
skipFormat: true,
|
||||||
|
skipTsConfig: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
host.delete(joinPathFragments(options.projectRoot, 'src'));
|
||||||
|
|
||||||
|
// Add the bin entry to the package.json
|
||||||
|
updateJson(
|
||||||
|
host,
|
||||||
|
joinPathFragments(options.projectRoot, 'package.json'),
|
||||||
|
(packageJson) => {
|
||||||
|
packageJson.bin = {
|
||||||
|
[options.name]: './bin/index.js',
|
||||||
|
};
|
||||||
|
packageJson.dependencies = {
|
||||||
|
'create-nx-workspace': nxVersion,
|
||||||
|
};
|
||||||
|
return packageJson;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// update project build target to use the bin entry
|
||||||
|
const projectConfiguration = readProjectConfiguration(
|
||||||
|
host,
|
||||||
|
options.projectName
|
||||||
|
);
|
||||||
|
projectConfiguration.sourceRoot = joinPathFragments(
|
||||||
|
options.projectRoot,
|
||||||
|
'bin'
|
||||||
|
);
|
||||||
|
projectConfiguration.targets.build.options.main = joinPathFragments(
|
||||||
|
options.projectRoot,
|
||||||
|
'bin/index.ts'
|
||||||
|
);
|
||||||
|
projectConfiguration.targets.build.options.updateBuildableProjectDepsInPackageJson =
|
||||||
|
false;
|
||||||
|
projectConfiguration.implicitDependencies = [options.project];
|
||||||
|
updateProjectConfiguration(host, options.projectName, projectConfiguration);
|
||||||
|
|
||||||
|
// Add bin files to tsconfg.lib.json
|
||||||
|
updateJson(
|
||||||
|
host,
|
||||||
|
joinPathFragments(options.projectRoot, 'tsconfig.lib.json'),
|
||||||
|
(tsConfig) => {
|
||||||
|
tsConfig.include.push('bin/**/*.ts');
|
||||||
|
return tsConfig;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
generateFiles(
|
||||||
|
host,
|
||||||
|
joinPathFragments(__dirname, './files/create-framework-package'),
|
||||||
|
options.projectRoot,
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
preset: pluginPackageName,
|
||||||
|
tmpl: '',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a test file to plugin e2e project
|
||||||
|
* @param host
|
||||||
|
* @param options
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function addE2eProject(host: Tree, options: NormalizedSchema) {
|
||||||
|
const pluginProjectConfiguration = readProjectConfiguration(
|
||||||
|
host,
|
||||||
|
options.project
|
||||||
|
);
|
||||||
|
const pluginOutputPath =
|
||||||
|
pluginProjectConfiguration.targets.build.options.outputPath;
|
||||||
|
|
||||||
|
const cliProjectConfiguration = readProjectConfiguration(
|
||||||
|
host,
|
||||||
|
options.projectName
|
||||||
|
);
|
||||||
|
const cliOutputPath =
|
||||||
|
cliProjectConfiguration.targets.build.options.outputPath;
|
||||||
|
|
||||||
|
const e2eTask = await e2eProjectGenerator(host, {
|
||||||
|
pluginName: options.projectName,
|
||||||
|
projectDirectory: options.projectDirectory,
|
||||||
|
pluginOutputPath,
|
||||||
|
npmPackageName: options.name,
|
||||||
|
skipFormat: true,
|
||||||
|
rootProject: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const e2eProjectConfiguration = readProjectConfiguration(
|
||||||
|
host,
|
||||||
|
`${options.projectName}-e2e`
|
||||||
|
);
|
||||||
|
e2eProjectConfiguration.targets.e2e.dependsOn = ['^build'];
|
||||||
|
updateProjectConfiguration(
|
||||||
|
host,
|
||||||
|
e2eProjectConfiguration.name,
|
||||||
|
e2eProjectConfiguration
|
||||||
|
);
|
||||||
|
|
||||||
|
// delete the default e2e test file
|
||||||
|
host.delete(e2eProjectConfiguration.sourceRoot);
|
||||||
|
|
||||||
|
generateFiles(
|
||||||
|
host,
|
||||||
|
joinPathFragments(__dirname, './files/e2e'),
|
||||||
|
e2eProjectConfiguration.sourceRoot,
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
pluginOutputPath,
|
||||||
|
cliOutputPath,
|
||||||
|
tmpl: '',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return e2eTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createPackageGenerator;
|
||||||
|
export const createPackageSchematic = convertNxGenerator(
|
||||||
|
createPackageGenerator
|
||||||
|
);
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { createWorkspace } from 'create-nx-workspace';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const name = process.argv[2]; // TODO: use libraries like yargs or enquirer to set your workspace name
|
||||||
|
if (!name) {
|
||||||
|
throw new Error('Please provide a name for the workspace');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Creating the workspace: ${name}`);
|
||||||
|
|
||||||
|
// TODO: update below to customize the workspace
|
||||||
|
const { directory } = await createWorkspace('<%= preset %>', {
|
||||||
|
name,
|
||||||
|
nxCloud: false,
|
||||||
|
packageManager: 'npm',
|
||||||
|
// This assumes "<%= preset %>" and "<%= projectName %>" are at the same version
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
presetVersion: require('../package.json').version,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Successfully created the workspace: ${directory}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
import {
|
||||||
|
uniq,
|
||||||
|
runCreatePackageCli,
|
||||||
|
removeTmpProject,
|
||||||
|
} from '@nx/nx-plugin/testing';
|
||||||
|
|
||||||
|
describe('<%= name %> e2e', () => {
|
||||||
|
const project = uniq('<%= name %>');
|
||||||
|
let createPackageResult;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
// Create project using CLI command
|
||||||
|
createPackageResult = await runCreatePackageCli(
|
||||||
|
project,
|
||||||
|
{
|
||||||
|
pluginLibraryBuildPath: '<%= pluginOutputPath %>',
|
||||||
|
createPackageLibraryBuildPath: '<%= cliOutputPath %>',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, 240_000);
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
// Remove the generated project from the file system
|
||||||
|
removeTmpProject(project);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create project using <%= name %>', () => {
|
||||||
|
expect(createPackageResult).toContain('Successfully created');
|
||||||
|
});
|
||||||
|
});
|
||||||
17
packages/nx-plugin/src/generators/create-package/schema.d.ts
vendored
Normal file
17
packages/nx-plugin/src/generators/create-package/schema.d.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import type { Linter } from '@nx/linter';
|
||||||
|
|
||||||
|
export interface CreatePackageSchema {
|
||||||
|
name: string;
|
||||||
|
project: string;
|
||||||
|
|
||||||
|
// options to create cli package, passed to js library generator
|
||||||
|
directory?: string;
|
||||||
|
skipFormat: boolean;
|
||||||
|
tags?: string;
|
||||||
|
unitTestRunner: 'jest' | 'none';
|
||||||
|
linter: Linter;
|
||||||
|
compiler: 'swc' | 'tsc';
|
||||||
|
|
||||||
|
// options to create e2e project, passed to e2e project generator
|
||||||
|
e2eTestRunner?: 'jest' | 'none';
|
||||||
|
}
|
||||||
69
packages/nx-plugin/src/generators/create-package/schema.json
Normal file
69
packages/nx-plugin/src/generators/create-package/schema.json
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/schema",
|
||||||
|
"cli": "nx",
|
||||||
|
"$id": "NxPluginCreatePackage",
|
||||||
|
"title": "Create a framework package",
|
||||||
|
"description": "Create a framework package that uses Nx CLI.",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The package name of cli, e.g. `create-framework-package`. Note this must be a valid NPM name to be published.",
|
||||||
|
"$default": {
|
||||||
|
"$source": "argv",
|
||||||
|
"index": 0
|
||||||
|
},
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the generator project.",
|
||||||
|
"alias": "p",
|
||||||
|
"$default": {
|
||||||
|
"$source": "projectName"
|
||||||
|
},
|
||||||
|
"x-prompt": "What is the name of the project for the generator?",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
|
"unitTestRunner": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["jest", "none"],
|
||||||
|
"description": "Test runner to use for unit tests.",
|
||||||
|
"default": "jest"
|
||||||
|
},
|
||||||
|
"directory": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "A directory where the app is placed."
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint"],
|
||||||
|
"default": "eslint"
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Add tags to the library (used for linting).",
|
||||||
|
"alias": "t"
|
||||||
|
},
|
||||||
|
"skipFormat": {
|
||||||
|
"description": "Skip formatting files.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"x-priority": "internal"
|
||||||
|
},
|
||||||
|
"compiler": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["tsc", "swc"],
|
||||||
|
"default": "tsc",
|
||||||
|
"description": "The compiler used by the build and test targets."
|
||||||
|
},
|
||||||
|
"e2eTestRunner": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["jest", "none"],
|
||||||
|
"description": "Test runner to use for end to end (E2E) tests.",
|
||||||
|
"default": "jest"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["name", "project"]
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
import {
|
||||||
|
extractLayoutDirectory,
|
||||||
|
getWorkspaceLayout,
|
||||||
|
joinPathFragments,
|
||||||
|
names,
|
||||||
|
Tree,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { CreatePackageSchema } from '../schema';
|
||||||
|
|
||||||
|
export interface NormalizedSchema extends CreatePackageSchema {
|
||||||
|
bundler: 'swc' | 'tsc';
|
||||||
|
libsDir: string;
|
||||||
|
projectName: string;
|
||||||
|
projectRoot: string;
|
||||||
|
projectDirectory: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeSchema(
|
||||||
|
host: Tree,
|
||||||
|
schema: CreatePackageSchema
|
||||||
|
): NormalizedSchema {
|
||||||
|
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
|
||||||
|
schema.directory
|
||||||
|
);
|
||||||
|
const { libsDir: defaultLibsDir } = getWorkspaceLayout(host);
|
||||||
|
const libsDir = layoutDirectory ?? defaultLibsDir;
|
||||||
|
const name = names(schema.name).fileName;
|
||||||
|
const fullProjectDirectory = projectDirectory
|
||||||
|
? `${names(projectDirectory).fileName}/${name}`
|
||||||
|
: name;
|
||||||
|
const projectName = fullProjectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||||
|
const projectRoot = joinPathFragments(libsDir, fullProjectDirectory);
|
||||||
|
return {
|
||||||
|
...schema,
|
||||||
|
bundler: schema.compiler ?? 'tsc',
|
||||||
|
libsDir,
|
||||||
|
projectName,
|
||||||
|
projectRoot,
|
||||||
|
name,
|
||||||
|
projectDirectory: fullProjectDirectory,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -74,7 +74,7 @@ function updateWorkspaceConfiguration(host: Tree, options: NormalizedSchema) {
|
|||||||
addProjectConfiguration(host, options.projectName, {
|
addProjectConfiguration(host, options.projectName, {
|
||||||
root: options.projectRoot,
|
root: options.projectRoot,
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
sourceRoot: `${options.projectRoot}/src`,
|
sourceRoot: `${options.projectRoot}/tests`,
|
||||||
targets: {
|
targets: {
|
||||||
e2e: {
|
e2e: {
|
||||||
executor: '@nx/nx-plugin:e2e',
|
executor: '@nx/nx-plugin:e2e',
|
||||||
|
|||||||
@ -32,6 +32,6 @@ describe('<%= pluginName %> e2e', () => {
|
|||||||
const generator = 'PLACEHOLDER';
|
const generator = 'PLACEHOLDER';
|
||||||
await runNxCommandAsync(`generate <%= npmPackageName %>:${generator} --name ${name}`);
|
await runNxCommandAsync(`generate <%= npmPackageName %>:${generator} --name ${name}`);
|
||||||
expect(() => runNxCommand('build ${proj}')).not.toThrow();
|
expect(() => runNxCommand('build ${proj}')).not.toThrow();
|
||||||
expect(() => checkFilesExist([`dist/${name}/index.js`])).not.toThrow();
|
expect(() => checkFilesExist(`dist/${name}/index.js`)).not.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
writeJson,
|
writeJson,
|
||||||
readJson,
|
readJson,
|
||||||
ExecutorsJson,
|
ExecutorsJson,
|
||||||
|
formatFiles,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import type { Tree } from '@nx/devkit';
|
import type { Tree } from '@nx/devkit';
|
||||||
import type { Schema } from './schema';
|
import type { Schema } from './schema';
|
||||||
@ -176,6 +177,10 @@ export async function executorGenerator(host: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await updateExecutorJson(host, options);
|
await updateExecutorJson(host, options);
|
||||||
|
|
||||||
|
if (!schema.skipFormat) {
|
||||||
|
await formatFiles(host);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default executorGenerator;
|
export default executorGenerator;
|
||||||
|
|||||||
@ -5,4 +5,5 @@ export interface Schema {
|
|||||||
unitTestRunner: 'jest' | 'none';
|
unitTestRunner: 'jest' | 'none';
|
||||||
includeHasher: boolean;
|
includeHasher: boolean;
|
||||||
skipLintChecks?: boolean;
|
skipLintChecks?: boolean;
|
||||||
|
skipFormat?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,12 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add an eslint configuration for plugin json files."
|
"description": "Do not add an eslint configuration for plugin json files."
|
||||||
|
},
|
||||||
|
"skipFormat": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Skip formatting files.",
|
||||||
|
"default": false,
|
||||||
|
"x-priority": "internal"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["project", "name"],
|
"required": ["project", "name"],
|
||||||
|
|||||||
@ -23,7 +23,10 @@ function normalizeOptions(tree: Tree, options: <%= className %>GeneratorSchema):
|
|||||||
? `${names(options.directory).fileName}/${name}`
|
? `${names(options.directory).fileName}/${name}`
|
||||||
: name;
|
: name;
|
||||||
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||||
const projectRoot = `${getWorkspaceLayout(tree).libsDir}/${projectDirectory}`;
|
const projectRoot =
|
||||||
|
getWorkspaceLayout(tree).libsDir === '.'
|
||||||
|
? '.'
|
||||||
|
: `${getWorkspaceLayout(tree).libsDir}/${projectDirectory}`;
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
: [];
|
: [];
|
||||||
|
|||||||
@ -4,8 +4,6 @@ import {
|
|||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
Tree,
|
Tree,
|
||||||
writeJson,
|
writeJson,
|
||||||
} from '@nx/devkit';
|
|
||||||
import {
|
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
getWorkspaceLayout,
|
getWorkspaceLayout,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { Linter } from '@nx/linter';
|
import { Linter } from '@nx/linter';
|
||||||
|
import { PackageJson } from 'nx/src/utils/package-json';
|
||||||
import { pluginGenerator } from './plugin';
|
import { pluginGenerator } from './plugin';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
@ -161,7 +162,7 @@ describe('NxPlugin Plugin Generator', () => {
|
|||||||
await pluginGenerator(tree, getSchema());
|
await pluginGenerator(tree, getSchema());
|
||||||
|
|
||||||
const { root } = readProjectConfiguration(tree, 'my-plugin');
|
const { root } = readProjectConfiguration(tree, 'my-plugin');
|
||||||
const { name } = readJson<{ name: string }>(
|
const { name } = readJson<PackageJson>(
|
||||||
tree,
|
tree,
|
||||||
joinPathFragments(root, 'package.json')
|
joinPathFragments(root, 'package.json')
|
||||||
);
|
);
|
||||||
@ -178,7 +179,7 @@ describe('NxPlugin Plugin Generator', () => {
|
|||||||
await pluginGenerator(tree, getSchema());
|
await pluginGenerator(tree, getSchema());
|
||||||
|
|
||||||
const { root } = readProjectConfiguration(tree, 'my-plugin');
|
const { root } = readProjectConfiguration(tree, 'my-plugin');
|
||||||
const { name } = readJson<{ name: string }>(
|
const { name } = readJson<PackageJson>(
|
||||||
tree,
|
tree,
|
||||||
joinPathFragments(root, 'package.json')
|
joinPathFragments(root, 'package.json')
|
||||||
);
|
);
|
||||||
@ -193,7 +194,7 @@ describe('NxPlugin Plugin Generator', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { root } = readProjectConfiguration(tree, 'my-plugin');
|
const { root } = readProjectConfiguration(tree, 'my-plugin');
|
||||||
const { name } = readJson<{ name: string }>(
|
const { name } = readJson<PackageJson>(
|
||||||
tree,
|
tree,
|
||||||
joinPathFragments(root, 'package.json')
|
joinPathFragments(root, 'package.json')
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,9 +3,10 @@ import {
|
|||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
installPackagesTask,
|
GeneratorCallback,
|
||||||
normalizePath,
|
normalizePath,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
@ -73,55 +74,65 @@ function updatePluginConfig(host: Tree, options: NormalizedSchema) {
|
|||||||
|
|
||||||
export async function pluginGenerator(host: Tree, schema: Schema) {
|
export async function pluginGenerator(host: Tree, schema: Schema) {
|
||||||
const options = normalizeOptions(host, schema);
|
const options = normalizeOptions(host, schema);
|
||||||
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
await jsLibraryGenerator(host, {
|
tasks.push(
|
||||||
...schema,
|
await jsLibraryGenerator(host, {
|
||||||
config: 'project',
|
...schema,
|
||||||
bundler: options.bundler,
|
config: 'project',
|
||||||
importPath: options.npmPackageName,
|
bundler: options.bundler,
|
||||||
skipFormat: true,
|
publishable: true,
|
||||||
});
|
importPath: options.npmPackageName,
|
||||||
|
skipFormat: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
addTsLibDependencies(host);
|
tasks.push(addTsLibDependencies(host));
|
||||||
|
|
||||||
addDependenciesToPackageJson(
|
tasks.push(
|
||||||
host,
|
addDependenciesToPackageJson(
|
||||||
{
|
host,
|
||||||
'@nx/devkit': nxVersion,
|
{
|
||||||
},
|
'@nx/devkit': nxVersion,
|
||||||
{
|
},
|
||||||
'@nx/jest': nxVersion,
|
{
|
||||||
'@nx/js': nxVersion,
|
'@nx/jest': nxVersion,
|
||||||
'@nx/nx-plugin': nxVersion,
|
'@nx/js': nxVersion,
|
||||||
}
|
'@nx/nx-plugin': nxVersion,
|
||||||
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensures Swc Deps are installed to handle running
|
// Ensures Swc Deps are installed to handle running
|
||||||
// local plugin generators and executors
|
// local plugin generators and executors
|
||||||
addSwcDependencies(host);
|
tasks.push(addSwcDependencies(host));
|
||||||
addSwcRegisterDependencies(host);
|
tasks.push(addSwcRegisterDependencies(host));
|
||||||
|
|
||||||
await addFiles(host, options);
|
await addFiles(host, options);
|
||||||
updatePluginConfig(host, options);
|
updatePluginConfig(host, options);
|
||||||
|
|
||||||
if (options.e2eTestRunner !== 'none') {
|
if (options.e2eTestRunner !== 'none') {
|
||||||
await e2eProjectGenerator(host, {
|
tasks.push(
|
||||||
pluginName: options.name,
|
await e2eProjectGenerator(host, {
|
||||||
projectDirectory: options.projectDirectory,
|
pluginName: options.name,
|
||||||
pluginOutputPath: `dist/${options.libsDir}/${options.projectDirectory}`,
|
projectDirectory: options.projectDirectory,
|
||||||
npmPackageName: options.npmPackageName,
|
pluginOutputPath: `dist/${options.libsDir}/${options.projectDirectory}`,
|
||||||
skipFormat: true,
|
npmPackageName: options.npmPackageName,
|
||||||
rootProject: options.rootProject,
|
skipFormat: true,
|
||||||
});
|
rootProject: options.rootProject,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.linter === Linter.EsLint && !options.skipLintChecks) {
|
if (options.linter === Linter.EsLint && !options.skipLintChecks) {
|
||||||
await pluginLintCheckGenerator(host, { projectName: options.name });
|
await pluginLintCheckGenerator(host, { projectName: options.name });
|
||||||
}
|
}
|
||||||
|
|
||||||
await formatFiles(host);
|
if (!options.skipFormat) {
|
||||||
|
await formatFiles(host);
|
||||||
|
}
|
||||||
|
|
||||||
return () => installPackagesTask(host);
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default pluginGenerator;
|
export default pluginGenerator;
|
||||||
|
|||||||
@ -4,9 +4,9 @@ export interface Schema {
|
|||||||
name: string;
|
name: string;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
importPath?: string;
|
importPath?: string;
|
||||||
skipTsConfig: boolean;
|
skipTsConfig?: boolean; // default is false
|
||||||
skipFormat: boolean;
|
skipFormat?: boolean; // default is false
|
||||||
skipLintChecks: boolean;
|
skipLintChecks?: boolean; // default is false
|
||||||
e2eTestRunner?: 'jest' | 'none';
|
e2eTestRunner?: 'jest' | 'none';
|
||||||
tags?: string;
|
tags?: string;
|
||||||
unitTestRunner: 'jest' | 'none';
|
unitTestRunner: 'jest' | 'none';
|
||||||
|
|||||||
@ -1,34 +1,58 @@
|
|||||||
import { Tree, updateJson, updateNxJson, readNxJson } from '@nx/devkit';
|
import {
|
||||||
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
updateNxJson,
|
||||||
|
readNxJson,
|
||||||
|
formatFiles,
|
||||||
|
runTasksInSerial,
|
||||||
|
GeneratorCallback,
|
||||||
|
} from '@nx/devkit';
|
||||||
import { Linter } from '@nx/linter';
|
import { Linter } from '@nx/linter';
|
||||||
import { PackageJson } from 'nx/src/utils/package-json';
|
import { PackageJson } from 'nx/src/utils/package-json';
|
||||||
import { pluginGenerator } from '../plugin/plugin';
|
import { pluginGenerator } from '../plugin/plugin';
|
||||||
import { PresetGeneratorSchema } from './schema';
|
import { PresetGeneratorSchema } from './schema';
|
||||||
|
import createPackageGenerator from '../create-package/create-package';
|
||||||
|
|
||||||
export default async function (tree: Tree, options: PresetGeneratorSchema) {
|
export default async function (tree: Tree, options: PresetGeneratorSchema) {
|
||||||
const task = await pluginGenerator(tree, {
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
const pluginTask = await pluginGenerator(tree, {
|
||||||
compiler: 'tsc',
|
compiler: 'tsc',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
name: options.pluginName.includes('/')
|
name: options.pluginName.includes('/')
|
||||||
? options.pluginName.split('/')[1]
|
? options.pluginName.split('/')[1]
|
||||||
: options.pluginName,
|
: options.pluginName,
|
||||||
skipFormat: false,
|
skipFormat: true,
|
||||||
skipLintChecks: false,
|
|
||||||
skipTsConfig: false,
|
|
||||||
unitTestRunner: 'jest',
|
unitTestRunner: 'jest',
|
||||||
importPath: options.pluginName,
|
importPath: options.pluginName,
|
||||||
rootProject: true,
|
rootProject: true,
|
||||||
e2eTestRunner: 'jest',
|
e2eTestRunner: 'jest',
|
||||||
});
|
});
|
||||||
|
tasks.push(pluginTask);
|
||||||
|
|
||||||
removeNpmScope(tree);
|
removeNpmScope(tree);
|
||||||
moveNxPluginToDevDeps(tree);
|
moveNxPluginToDevDeps(tree);
|
||||||
|
|
||||||
return task;
|
if (options.createPackageName) {
|
||||||
|
const cliTask = await createPackageGenerator(tree, {
|
||||||
|
name: options.createPackageName,
|
||||||
|
project: options.pluginName,
|
||||||
|
skipFormat: true,
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
compiler: 'tsc',
|
||||||
|
});
|
||||||
|
tasks.push(cliTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
await formatFiles(tree);
|
||||||
|
|
||||||
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeNpmScope(tree: Tree) {
|
function removeNpmScope(tree: Tree) {
|
||||||
updateNxJson(tree, { ...readNxJson(tree), npmScope: undefined });
|
updateNxJson(tree, { ...readNxJson(tree), npmScope: undefined });
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveNxPluginToDevDeps(tree: Tree) {
|
function moveNxPluginToDevDeps(tree: Tree) {
|
||||||
updateJson<PackageJson>(tree, 'package.json', (json) => {
|
updateJson<PackageJson>(tree, 'package.json', (json) => {
|
||||||
const nxPluginEntry = json.dependencies['@nx/nx-plugin'];
|
const nxPluginEntry = json.dependencies['@nx/nx-plugin'];
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
export interface PresetGeneratorSchema {
|
export interface PresetGeneratorSchema {
|
||||||
pluginName: string;
|
pluginName: string;
|
||||||
|
createPackageName?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Plugin name",
|
"description": "Plugin name",
|
||||||
"aliases": ["name"]
|
"aliases": ["name"]
|
||||||
|
},
|
||||||
|
"createPackageName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of package which creates a workspace"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["pluginName"]
|
"required": ["pluginName"]
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { fileExists } from './utils';
|
|||||||
*/
|
*/
|
||||||
export function runCommandAsync(
|
export function runCommandAsync(
|
||||||
command: string,
|
command: string,
|
||||||
opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv } = {
|
opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = {
|
||||||
silenceError: false,
|
silenceError: false,
|
||||||
}
|
}
|
||||||
): Promise<{ stdout: string; stderr: string }> {
|
): Promise<{ stdout: string; stderr: string }> {
|
||||||
@ -19,7 +19,7 @@ export function runCommandAsync(
|
|||||||
exec(
|
exec(
|
||||||
command,
|
command,
|
||||||
{
|
{
|
||||||
cwd: tmpProjPath(),
|
cwd: opts.cwd ?? tmpProjPath(),
|
||||||
env: { ...process.env, ...opts.env },
|
env: { ...process.env, ...opts.env },
|
||||||
},
|
},
|
||||||
(err, stdout, stderr) => {
|
(err, stdout, stderr) => {
|
||||||
@ -39,7 +39,7 @@ export function runCommandAsync(
|
|||||||
*/
|
*/
|
||||||
export function runNxCommandAsync(
|
export function runNxCommandAsync(
|
||||||
command: string,
|
command: string,
|
||||||
opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv } = {
|
opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = {
|
||||||
silenceError: false,
|
silenceError: false,
|
||||||
}
|
}
|
||||||
): Promise<{ stdout: string; stderr: string }> {
|
): Promise<{ stdout: string; stderr: string }> {
|
||||||
|
|||||||
@ -12,13 +12,13 @@ import { fileExists } from './utils';
|
|||||||
*/
|
*/
|
||||||
export function runNxCommand(
|
export function runNxCommand(
|
||||||
command?: string,
|
command?: string,
|
||||||
opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv } = {
|
opts: { silenceError?: boolean; env?: NodeJS.ProcessEnv; cwd?: string } = {
|
||||||
silenceError: false,
|
silenceError: false,
|
||||||
}
|
}
|
||||||
): string {
|
): string {
|
||||||
function _runNxCommand(c) {
|
function _runNxCommand(c) {
|
||||||
const execSyncOptions: ExecOptions = {
|
const execSyncOptions: ExecOptions = {
|
||||||
cwd: tmpProjPath(),
|
cwd: opts.cwd,
|
||||||
env: { ...process.env, ...opts.env },
|
env: { ...process.env, ...opts.env },
|
||||||
};
|
};
|
||||||
if (fileExists(tmpProjPath('package.json'))) {
|
if (fileExists(tmpProjPath('package.json'))) {
|
||||||
@ -50,11 +50,11 @@ export function runNxCommand(
|
|||||||
|
|
||||||
export function runCommand(
|
export function runCommand(
|
||||||
command: string,
|
command: string,
|
||||||
opts?: { env?: NodeJS.ProcessEnv }
|
opts: { env?: NodeJS.ProcessEnv; cwd?: string }
|
||||||
): string {
|
): string {
|
||||||
try {
|
try {
|
||||||
return execSync(command, {
|
return execSync(command, {
|
||||||
cwd: tmpProjPath(),
|
cwd: opts.cwd ?? tmpProjPath(),
|
||||||
stdio: ['pipe', 'pipe', 'pipe'],
|
stdio: ['pipe', 'pipe', 'pipe'],
|
||||||
env: { ...process.env, ...opts?.env },
|
env: { ...process.env, ...opts?.env },
|
||||||
}).toString();
|
}).toString();
|
||||||
|
|||||||
@ -0,0 +1,72 @@
|
|||||||
|
import { workspaceRoot } from '@nx/devkit';
|
||||||
|
import { tmpFolder } from './paths';
|
||||||
|
import { fork } from 'child_process';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used to run the create package CLI command.
|
||||||
|
* It builds the plugin library and the create package library and run the create package command with for the plugin library.
|
||||||
|
* It needs to be ran inside an Nx project. It would assume that an Nx project already exists.
|
||||||
|
* @param projectToBeCreated project name to be created using the cli
|
||||||
|
* @param pluginLibraryBuildPath e.g. dist/packages/my-plugin
|
||||||
|
* @param createPackageLibraryBuildPath e.g. dist/packages/create-my-plugin-package
|
||||||
|
* @param extraArguments extra arguments to be passed to the create package command
|
||||||
|
* @param verbose if true, NX_VERBOSE_LOGGING will be set to true
|
||||||
|
* @returns results for the create package command
|
||||||
|
*/
|
||||||
|
export function runCreatePackageCli(
|
||||||
|
projectToBeCreated: string,
|
||||||
|
{
|
||||||
|
pluginLibraryBuildPath,
|
||||||
|
createPackageLibraryBuildPath,
|
||||||
|
extraArguments,
|
||||||
|
verbose,
|
||||||
|
}: {
|
||||||
|
pluginLibraryBuildPath: string;
|
||||||
|
createPackageLibraryBuildPath: string;
|
||||||
|
extraArguments?: string[];
|
||||||
|
verbose?: boolean;
|
||||||
|
}
|
||||||
|
): Promise<string> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const childProcess = fork(
|
||||||
|
`${workspaceRoot}/${createPackageLibraryBuildPath}/bin/index.js`,
|
||||||
|
[projectToBeCreated, ...(extraArguments || [])],
|
||||||
|
{
|
||||||
|
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
[`NX_E2E_PRESET_VERSION`]: `file:${workspaceRoot}/${pluginLibraryBuildPath}`,
|
||||||
|
// only add NX_VERBOSE_LOGGING if verbose is true
|
||||||
|
...(verbose && { NX_VERBOSE_LOGGING: 'true' }),
|
||||||
|
},
|
||||||
|
cwd: tmpFolder(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure the child process is killed when the parent exits
|
||||||
|
process.on('exit', () => childProcess.kill());
|
||||||
|
process.on('SIGTERM', () => childProcess.kill());
|
||||||
|
|
||||||
|
let allMessages = '';
|
||||||
|
childProcess.on('message', (message) => {
|
||||||
|
allMessages += message;
|
||||||
|
});
|
||||||
|
childProcess.stdout.on('data', (data) => {
|
||||||
|
allMessages += data;
|
||||||
|
});
|
||||||
|
childProcess.on('error', (error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
childProcess.on('exit', (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
resolve(allMessages);
|
||||||
|
} else {
|
||||||
|
reject(allMessages);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generatedPackagePath(projectToBeCreated: string) {
|
||||||
|
return `${tmpFolder()}/${projectToBeCreated}`;
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
export * from './async-commands';
|
export * from './async-commands';
|
||||||
export * from './commands';
|
export * from './commands';
|
||||||
|
export * from './create-package-cli';
|
||||||
export * from './paths';
|
export * from './paths';
|
||||||
export * from './nx-project';
|
export * from './nx-project';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
|
|||||||
@ -1,3 +1,9 @@
|
|||||||
|
import { workspaceRoot } from '@nx/devkit';
|
||||||
|
|
||||||
|
export function tmpFolder() {
|
||||||
|
return `${workspaceRoot}/tmp`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The directory where the e2e workspace resides in.
|
* The directory where the e2e workspace resides in.
|
||||||
*
|
*
|
||||||
@ -6,8 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
export function tmpProjPath(path?: string) {
|
export function tmpProjPath(path?: string) {
|
||||||
return path
|
return path
|
||||||
? `${process.cwd()}/tmp/nx-e2e/proj/${path}`
|
? `${tmpFolder()}/nx-e2e/proj/${path}`
|
||||||
: `${process.cwd()}/tmp/nx-e2e/proj`;
|
: `${tmpFolder()}/nx-e2e/proj`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,6 +24,6 @@ export function tmpProjPath(path?: string) {
|
|||||||
*/
|
*/
|
||||||
export function tmpBackupProjPath(path?: string) {
|
export function tmpBackupProjPath(path?: string) {
|
||||||
return path
|
return path
|
||||||
? `${process.cwd()}/tmp/nx-e2e/proj-backup/${path}`
|
? `${workspaceRoot}/tmp/nx-e2e/proj-backup/${path}`
|
||||||
: `${process.cwd()}/tmp/nx-e2e/proj-backup`;
|
: `${workspaceRoot}/tmp/nx-e2e/proj-backup`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
writeFileSync,
|
writeFileSync,
|
||||||
} from 'fs-extra';
|
} from 'fs-extra';
|
||||||
import { dirname, isAbsolute } from 'path';
|
import { dirname, isAbsolute } from 'path';
|
||||||
import { tmpProjPath } from './paths';
|
import { tmpFolder, tmpProjPath } from './paths';
|
||||||
import { parseJson } from '@nx/devkit';
|
import { parseJson } from '@nx/devkit';
|
||||||
import type { JsonParseOptions } from '@nx/devkit';
|
import type { JsonParseOptions } from '@nx/devkit';
|
||||||
import { directoryExists, fileExists } from 'nx/src/utils/fileutils';
|
import { directoryExists, fileExists } from 'nx/src/utils/fileutils';
|
||||||
@ -135,6 +135,10 @@ export function rmDist(): void {
|
|||||||
removeSync(`${tmpProjPath()}/dist`);
|
removeSync(`${tmpProjPath()}/dist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function removeTmpProject(project: string): void {
|
||||||
|
removeSync(`${tmpFolder()}/${project}`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the currend `cwd` in the process
|
* Get the currend `cwd` in the process
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { ModuleFederationConfig } from '@nx/devkit';
|
|||||||
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';
|
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';
|
||||||
import { getModuleFederationConfig } from './utils';
|
import { getModuleFederationConfig } from './utils';
|
||||||
import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
|
import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
|
||||||
import type { AsyncNxWebpackPlugin, NxWebpackPlugin } from '@nx/webpack';
|
import type { AsyncNxWebpackPlugin } from '@nx/webpack';
|
||||||
|
|
||||||
function determineRemoteUrl(remote: string) {
|
function determineRemoteUrl(remote: string) {
|
||||||
const remoteConfiguration = readCachedProjectConfiguration(remote);
|
const remoteConfiguration = readCachedProjectConfiguration(remote);
|
||||||
|
|||||||
@ -94,5 +94,6 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["cypress", "jest", "detox", "none"]
|
"enum": ["cypress", "jest", "detox", "none"]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": ["preset", "name"]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user