feat(nx-plugin): add new package for creating nx plugins
This commit is contained in:
parent
ca69622ebe
commit
fe98e29e4b
@ -21,6 +21,7 @@ module.exports = {
|
||||
{ name: 'docs', description: 'anything related to docs infrastructure' },
|
||||
{ name: 'nextjs', description: 'anything Next specific' },
|
||||
{ name: 'node', description: 'anything Node specific' },
|
||||
{ name: 'nx-plugin', description: 'anything Nx Plugin specific' },
|
||||
{ name: 'react', description: 'anything React specific' },
|
||||
{ name: 'storybook', description: 'anything Storybook specific' },
|
||||
{
|
||||
|
||||
25
docs/angular/api-nx-plugin/builders/e2e.md
Normal file
25
docs/angular/api-nx-plugin/builders/e2e.md
Normal file
@ -0,0 +1,25 @@
|
||||
# e2e
|
||||
|
||||
Creates and runs an e2e for a Nx Plugin
|
||||
|
||||
Builder properties can be configured in angular.json when defining the builder, or when invoking it.
|
||||
|
||||
## Properties
|
||||
|
||||
### jestConfig
|
||||
|
||||
Type: `string`
|
||||
|
||||
Jest config file
|
||||
|
||||
### target
|
||||
|
||||
Type: `string`
|
||||
|
||||
the target Nx Plugin project and build
|
||||
|
||||
### tsSpecConfig
|
||||
|
||||
Type: `string`
|
||||
|
||||
Spec tsconfig file
|
||||
91
docs/angular/api-nx-plugin/schematics/plugin.md
Normal file
91
docs/angular/api-nx-plugin/schematics/plugin.md
Normal file
@ -0,0 +1,91 @@
|
||||
# plugin
|
||||
|
||||
Create a Nx Plugin
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
ng generate plugin ...
|
||||
```
|
||||
|
||||
By default, Nx will search for `plugin` in the default collection provisioned in `angular.json`.
|
||||
|
||||
You can specify the collection explicitly as follows:
|
||||
|
||||
```bash
|
||||
ng g @nrwl/nx-plugin:plugin ...
|
||||
```
|
||||
|
||||
Show what will be generated without writing to disk:
|
||||
|
||||
```bash
|
||||
ng g plugin ... --dry-run
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
Generate libs/plugins/my-plugin:
|
||||
|
||||
```bash
|
||||
ng g plugin my-plugin --directory=plugins
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### directory
|
||||
|
||||
Alias(es): d
|
||||
|
||||
Type: `string`
|
||||
|
||||
A directory where the plugin is placed
|
||||
|
||||
### linter
|
||||
|
||||
Default: `tslint`
|
||||
|
||||
Type: `string`
|
||||
|
||||
Possible values: `eslint`, `tslint`
|
||||
|
||||
The tool to use for running lint checks.
|
||||
|
||||
### name
|
||||
|
||||
Type: `string`
|
||||
|
||||
Plugin name
|
||||
|
||||
### skipFormat
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Skip formatting files
|
||||
|
||||
### skipTsConfig
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Do not update tsconfig.json for development experience.
|
||||
|
||||
### tags
|
||||
|
||||
Alias(es): t
|
||||
|
||||
Type: `string`
|
||||
|
||||
Add tags to the library (used for linting)
|
||||
|
||||
### unitTestRunner
|
||||
|
||||
Default: `jest`
|
||||
|
||||
Type: `string`
|
||||
|
||||
Possible values: `jest`, `none`
|
||||
|
||||
Test runner to use for unit tests
|
||||
@ -6,6 +6,7 @@
|
||||
"nest",
|
||||
"next",
|
||||
"node",
|
||||
"nx-plugin",
|
||||
"storybook",
|
||||
"web",
|
||||
"workspace"
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"nest",
|
||||
"next",
|
||||
"node",
|
||||
"nx-plugin",
|
||||
"react",
|
||||
"storybook",
|
||||
"web",
|
||||
|
||||
26
docs/react/api-nx-plugin/builders/e2e.md
Normal file
26
docs/react/api-nx-plugin/builders/e2e.md
Normal file
@ -0,0 +1,26 @@
|
||||
# e2e
|
||||
|
||||
Creates and runs an e2e for a Nx Plugin
|
||||
|
||||
Builder properties can be configured in workspace.json when defining the builder, or when invoking it.
|
||||
Read more about how to use builders and the CLI here: https://nx.dev/react/guides/cli.
|
||||
|
||||
## Properties
|
||||
|
||||
### jestConfig
|
||||
|
||||
Type: `string`
|
||||
|
||||
Jest config file
|
||||
|
||||
### target
|
||||
|
||||
Type: `string`
|
||||
|
||||
the target Nx Plugin project and build
|
||||
|
||||
### tsSpecConfig
|
||||
|
||||
Type: `string`
|
||||
|
||||
Spec tsconfig file
|
||||
91
docs/react/api-nx-plugin/schematics/plugin.md
Normal file
91
docs/react/api-nx-plugin/schematics/plugin.md
Normal file
@ -0,0 +1,91 @@
|
||||
# plugin
|
||||
|
||||
Create a Nx Plugin
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
nx generate plugin ...
|
||||
```
|
||||
|
||||
By default, Nx will search for `plugin` in the default collection provisioned in `workspace.json`.
|
||||
|
||||
You can specify the collection explicitly as follows:
|
||||
|
||||
```bash
|
||||
nx g @nrwl/nx-plugin:plugin ...
|
||||
```
|
||||
|
||||
Show what will be generated without writing to disk:
|
||||
|
||||
```bash
|
||||
nx g plugin ... --dry-run
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
Generate libs/plugins/my-plugin:
|
||||
|
||||
```bash
|
||||
nx g plugin my-plugin --directory=plugins
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### directory
|
||||
|
||||
Alias(es): d
|
||||
|
||||
Type: `string`
|
||||
|
||||
A directory where the plugin is placed
|
||||
|
||||
### linter
|
||||
|
||||
Default: `tslint`
|
||||
|
||||
Type: `string`
|
||||
|
||||
Possible values: `eslint`, `tslint`
|
||||
|
||||
The tool to use for running lint checks.
|
||||
|
||||
### name
|
||||
|
||||
Type: `string`
|
||||
|
||||
Plugin name
|
||||
|
||||
### skipFormat
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Skip formatting files
|
||||
|
||||
### skipTsConfig
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Do not update tsconfig.json for development experience.
|
||||
|
||||
### tags
|
||||
|
||||
Alias(es): t
|
||||
|
||||
Type: `string`
|
||||
|
||||
Add tags to the library (used for linting)
|
||||
|
||||
### unitTestRunner
|
||||
|
||||
Default: `jest`
|
||||
|
||||
Type: `string`
|
||||
|
||||
Possible values: `jest`, `none`
|
||||
|
||||
Test runner to use for unit tests
|
||||
@ -6,6 +6,7 @@
|
||||
"nest",
|
||||
"next",
|
||||
"node",
|
||||
"nx-plugin",
|
||||
"storybook",
|
||||
"web",
|
||||
"workspace"
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"nest",
|
||||
"next",
|
||||
"node",
|
||||
"nx-plugin",
|
||||
"react",
|
||||
"storybook",
|
||||
"web",
|
||||
|
||||
26
docs/web/api-nx-plugin/builders/e2e.md
Normal file
26
docs/web/api-nx-plugin/builders/e2e.md
Normal file
@ -0,0 +1,26 @@
|
||||
# e2e
|
||||
|
||||
Creates and runs an e2e for a Nx Plugin
|
||||
|
||||
Builder properties can be configured in workspace.json when defining the builder, or when invoking it.
|
||||
Read more about how to use builders and the CLI here: https://nx.dev/web/guides/cli.
|
||||
|
||||
## Properties
|
||||
|
||||
### jestConfig
|
||||
|
||||
Type: `string`
|
||||
|
||||
Jest config file
|
||||
|
||||
### target
|
||||
|
||||
Type: `string`
|
||||
|
||||
the target Nx Plugin project and build
|
||||
|
||||
### tsSpecConfig
|
||||
|
||||
Type: `string`
|
||||
|
||||
Spec tsconfig file
|
||||
91
docs/web/api-nx-plugin/schematics/plugin.md
Normal file
91
docs/web/api-nx-plugin/schematics/plugin.md
Normal file
@ -0,0 +1,91 @@
|
||||
# plugin
|
||||
|
||||
Create a Nx Plugin
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
nx generate plugin ...
|
||||
```
|
||||
|
||||
By default, Nx will search for `plugin` in the default collection provisioned in `workspace.json`.
|
||||
|
||||
You can specify the collection explicitly as follows:
|
||||
|
||||
```bash
|
||||
nx g @nrwl/nx-plugin:plugin ...
|
||||
```
|
||||
|
||||
Show what will be generated without writing to disk:
|
||||
|
||||
```bash
|
||||
nx g plugin ... --dry-run
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
Generate libs/plugins/my-plugin:
|
||||
|
||||
```bash
|
||||
nx g plugin my-plugin --directory=plugins
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### directory
|
||||
|
||||
Alias(es): d
|
||||
|
||||
Type: `string`
|
||||
|
||||
A directory where the plugin is placed
|
||||
|
||||
### linter
|
||||
|
||||
Default: `tslint`
|
||||
|
||||
Type: `string`
|
||||
|
||||
Possible values: `eslint`, `tslint`
|
||||
|
||||
The tool to use for running lint checks.
|
||||
|
||||
### name
|
||||
|
||||
Type: `string`
|
||||
|
||||
Plugin name
|
||||
|
||||
### skipFormat
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Skip formatting files
|
||||
|
||||
### skipTsConfig
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Do not update tsconfig.json for development experience.
|
||||
|
||||
### tags
|
||||
|
||||
Alias(es): t
|
||||
|
||||
Type: `string`
|
||||
|
||||
Add tags to the library (used for linting)
|
||||
|
||||
### unitTestRunner
|
||||
|
||||
Default: `jest`
|
||||
|
||||
Type: `string`
|
||||
|
||||
Possible values: `jest`, `none`
|
||||
|
||||
Test runner to use for unit tests
|
||||
@ -6,6 +6,7 @@
|
||||
"nest",
|
||||
"next",
|
||||
"node",
|
||||
"nx-plugin",
|
||||
"storybook",
|
||||
"web",
|
||||
"workspace"
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"nest",
|
||||
"next",
|
||||
"node",
|
||||
"nx-plugin",
|
||||
"react",
|
||||
"storybook",
|
||||
"web",
|
||||
|
||||
97
e2e/nx-plugin.test.ts
Normal file
97
e2e/nx-plugin.test.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import {
|
||||
forEachCli,
|
||||
ensureProject,
|
||||
uniq,
|
||||
runCLI,
|
||||
updateFile,
|
||||
expectTestsPass,
|
||||
runCLIAsync,
|
||||
checkFilesExist,
|
||||
readJson,
|
||||
workspaceConfigName
|
||||
} from './utils';
|
||||
|
||||
forEachCli(currentCLIName => {
|
||||
const linter = currentCLIName === 'angular' ? 'tslint' : 'eslint';
|
||||
|
||||
describe('Nx Plugin', () => {
|
||||
it('should be able to generate a Nx Plugin ', async done => {
|
||||
ensureProject();
|
||||
const plugin = uniq('plugin');
|
||||
|
||||
runCLI(`generate @nrwl/nx-plugin:plugin ${plugin} --linter=${linter}`);
|
||||
const lintResults = runCLI(`lint ${plugin}`);
|
||||
expect(lintResults).toContain('All files pass linting.');
|
||||
|
||||
expectTestsPass(await runCLIAsync(`test ${plugin}`));
|
||||
|
||||
const buildResults = runCLI(`build ${plugin}`);
|
||||
expect(buildResults).toContain('Done compiling TypeScript files');
|
||||
checkFilesExist(
|
||||
`dist/libs/${plugin}/package.json`,
|
||||
`dist/libs/${plugin}/collection.json`,
|
||||
`dist/libs/${plugin}/builders.json`,
|
||||
`dist/libs/${plugin}/src/index.js`,
|
||||
`dist/libs/${plugin}/src/schematics/${plugin}/schema.json`,
|
||||
`dist/libs/${plugin}/src/schematics/${plugin}/schema.d.ts`,
|
||||
`dist/libs/${plugin}/src/schematics/${plugin}/schematic.js`,
|
||||
`dist/libs/${plugin}/src/schematics/${plugin}/files/src/index.ts.template`,
|
||||
`dist/libs/${plugin}/src/builders/${plugin}/builder.js`,
|
||||
`dist/libs/${plugin}/src/builders/${plugin}/schema.d.ts`,
|
||||
`dist/libs/${plugin}/src/builders/${plugin}/schema.json`
|
||||
);
|
||||
const nxJson = readJson('nx.json');
|
||||
expect(nxJson).toMatchObject({
|
||||
projects: expect.objectContaining({
|
||||
[plugin]: {
|
||||
tags: []
|
||||
},
|
||||
[`${plugin}-e2e`]: {
|
||||
tags: [],
|
||||
implicitDependencies: [`${plugin}`]
|
||||
}
|
||||
})
|
||||
});
|
||||
done();
|
||||
}, 45000);
|
||||
|
||||
it(`should run the plugin's e2e tests`, async done => {
|
||||
ensureProject();
|
||||
const plugin = uniq('plugin');
|
||||
runCLI(`generate @nrwl/nx-plugin:plugin ${plugin} --linter=${linter}`);
|
||||
const results = await runCLIAsync(`e2e ${plugin}-e2e`);
|
||||
expect(results.stdout).toContain('Compiling TypeScript files');
|
||||
expectTestsPass(results);
|
||||
|
||||
done();
|
||||
}, 75000);
|
||||
|
||||
describe('--directory', () => {
|
||||
it('should create a plugin in the specified directory', () => {
|
||||
ensureProject();
|
||||
const plugin = uniq('plugin');
|
||||
runCLI(
|
||||
`generate @nrwl/nx-plugin:plugin ${plugin} --linter=${linter} --directory subdir`
|
||||
);
|
||||
checkFilesExist(`libs/subdir/${plugin}/package.json`);
|
||||
const workspace = readJson(workspaceConfigName());
|
||||
expect(workspace.projects[`subdir-${plugin}`]).toBeTruthy();
|
||||
expect(workspace.projects[`subdir-${plugin}`].root).toBe(
|
||||
`libs/subdir/${plugin}`
|
||||
);
|
||||
expect(workspace.projects[`subdir-${plugin}-e2e`]).toBeTruthy();
|
||||
}, 45000);
|
||||
});
|
||||
describe('--tags', () => {
|
||||
it('should add tags to nx.json', async () => {
|
||||
ensureProject();
|
||||
const plugin = uniq('plugin');
|
||||
runCLI(
|
||||
`generate @nrwl/nx-plugin:plugin ${plugin} --linter=${linter} --tags=e2etag,e2ePackage`
|
||||
);
|
||||
const nxJson = readJson('nx.json');
|
||||
expect(nxJson.projects[plugin].tags).toEqual(['e2etag', 'e2ePackage']);
|
||||
}, 45000);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -76,6 +76,7 @@
|
||||
"@testing-library/react": "9.4.0",
|
||||
"@types/express": "4.17.0",
|
||||
"@types/fast-levenshtein": "^0.0.1",
|
||||
"@types/fs-extra": "7.0.0",
|
||||
"@types/jasmine": "~2.8.6",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/jest": "24.0.9",
|
||||
|
||||
@ -104,6 +104,18 @@ describe('NodeCompileBuilder', () => {
|
||||
fakeEventEmitter.emit('exit', 0);
|
||||
});
|
||||
|
||||
it('should have the output path in the BuilderOutput', done => {
|
||||
runNodePackageBuilder(testOptions, context).subscribe({
|
||||
next: value => {
|
||||
expect(value.outputPath).toEqual(testOptions.outputPath);
|
||||
},
|
||||
complete: () => {
|
||||
done();
|
||||
}
|
||||
});
|
||||
fakeEventEmitter.emit('exit', 0);
|
||||
});
|
||||
|
||||
describe('Asset copying', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
@ -11,7 +11,7 @@ import { copy, removeSync } from 'fs-extra';
|
||||
import * as glob from 'glob';
|
||||
import { basename, dirname, join, normalize, relative } from 'path';
|
||||
import { Observable, Subscriber } from 'rxjs';
|
||||
import { switchMap, tap } from 'rxjs/operators';
|
||||
import { switchMap, tap, map } from 'rxjs/operators';
|
||||
import * as treeKill from 'tree-kill';
|
||||
|
||||
export interface NodePackageBuilderOptions extends JsonObject {
|
||||
@ -26,6 +26,7 @@ export interface NodePackageBuilderOptions extends JsonObject {
|
||||
|
||||
interface NormalizedBuilderOptions extends NodePackageBuilderOptions {
|
||||
files: Array<FileInputOutput>;
|
||||
normalizedOutputPath: string;
|
||||
relativeMainFileOutput: string;
|
||||
}
|
||||
|
||||
@ -51,6 +52,12 @@ export function runNodePackageBuilder(
|
||||
}),
|
||||
switchMap(() => {
|
||||
return copyAssetFiles(normalizedOptions, context);
|
||||
}),
|
||||
map(value => {
|
||||
return {
|
||||
...value,
|
||||
outputPath: normalizedOptions.outputPath
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -109,7 +116,8 @@ function normalizeOptions(
|
||||
return {
|
||||
...options,
|
||||
files,
|
||||
relativeMainFileOutput
|
||||
relativeMainFileOutput,
|
||||
normalizedOutputPath: join(context.workspaceRoot, options.outputPath)
|
||||
};
|
||||
}
|
||||
|
||||
@ -122,7 +130,7 @@ function compileTypeScriptFiles(
|
||||
killProcess(context);
|
||||
}
|
||||
// Cleaning the /dist folder
|
||||
removeSync(join(context.workspaceRoot, options.outputPath));
|
||||
removeSync(options.normalizedOutputPath);
|
||||
|
||||
return Observable.create((subscriber: Subscriber<BuilderOutput>) => {
|
||||
try {
|
||||
@ -130,7 +138,7 @@ function compileTypeScriptFiles(
|
||||
'-p',
|
||||
join(context.workspaceRoot, options.tsConfig),
|
||||
'--outDir',
|
||||
join(context.workspaceRoot, options.outputPath)
|
||||
options.normalizedOutputPath
|
||||
];
|
||||
|
||||
if (options.sourceMap) {
|
||||
|
||||
248
packages/nx-plugin/bin/create.ts
Normal file
248
packages/nx-plugin/bin/create.ts
Normal file
@ -0,0 +1,248 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// we can import from '@nrwl/workspace' because it will require typescript
|
||||
import { output } from '@nrwl/workspace/src/utils/output';
|
||||
import { dirSync } from 'tmp';
|
||||
import { writeFileSync } from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { execSync } from 'child_process';
|
||||
import * as inquirer from 'inquirer';
|
||||
import yargsParser = require('yargs-parser');
|
||||
|
||||
const tsVersion = 'TYPESCRIPT_VERSION';
|
||||
const cliVersion = 'NX_VERSION';
|
||||
const nxVersion = 'NX_VERSION';
|
||||
const prettierVersion = 'PRETTIER_VERSION';
|
||||
|
||||
const parsedArgs = yargsParser(process.argv, {
|
||||
string: ['pluginName'],
|
||||
alias: {
|
||||
pluginName: 'plugin-name'
|
||||
},
|
||||
boolean: ['help']
|
||||
});
|
||||
|
||||
if (parsedArgs.help) {
|
||||
showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const packageManager = determinePackageManager();
|
||||
determineWorkspaceName(parsedArgs).then(workspaceName => {
|
||||
return determinPluginName(parsedArgs).then(pluginName => {
|
||||
const tmpDir = createSandbox(packageManager);
|
||||
createWorkspace(tmpDir, packageManager, parsedArgs, workspaceName);
|
||||
createNxPlugin(workspaceName, pluginName);
|
||||
commitChanges(workspaceName);
|
||||
showNxWarning(workspaceName);
|
||||
});
|
||||
});
|
||||
|
||||
function createSandbox(packageManager: string) {
|
||||
console.log(`Creating a sandbox with Nx...`);
|
||||
const tmpDir = dirSync().name;
|
||||
writeFileSync(
|
||||
path.join(tmpDir, 'package.json'),
|
||||
JSON.stringify({
|
||||
dependencies: {
|
||||
'@nrwl/workspace': nxVersion,
|
||||
'@nrwl/tao': cliVersion,
|
||||
typescript: tsVersion,
|
||||
prettier: prettierVersion
|
||||
},
|
||||
license: 'MIT'
|
||||
})
|
||||
);
|
||||
|
||||
execSync(`${packageManager} install --silent`, {
|
||||
cwd: tmpDir,
|
||||
stdio: [0, 1, 2]
|
||||
});
|
||||
|
||||
return tmpDir;
|
||||
}
|
||||
|
||||
function createWorkspace(
|
||||
tmpDir: string,
|
||||
packageManager: string,
|
||||
parsedArgs: any,
|
||||
name: string
|
||||
) {
|
||||
const args = [
|
||||
name,
|
||||
...process.argv.slice(parsedArgs._[2] ? 3 : 2).map(a => `"${a}"`)
|
||||
].join(' ');
|
||||
|
||||
console.log(`new ${args} --preset=empty --collection=@nrwl/workspace`);
|
||||
execSync(
|
||||
`"${path.join(
|
||||
tmpDir,
|
||||
'node_modules',
|
||||
'.bin',
|
||||
'tao'
|
||||
)}" new ${args} --preset=empty --collection=@nrwl/workspace`,
|
||||
{
|
||||
stdio: [0, 1, 2]
|
||||
}
|
||||
);
|
||||
execSync(`${packageManager} add -D @nrwl/nx-plugin@${nxVersion}`, {
|
||||
cwd: name,
|
||||
stdio: [0, 1, 2]
|
||||
});
|
||||
}
|
||||
|
||||
function createNxPlugin(workspaceName, pluginName) {
|
||||
console.log(`nx generate @nrwl/nx-plugin:plugin ${pluginName}`);
|
||||
execSync(
|
||||
`node ./node_modules/@nrwl/cli/bin/nx.js generate @nrwl/nx-plugin:plugin ${pluginName}`,
|
||||
{
|
||||
cwd: workspaceName,
|
||||
stdio: [0, 1, 2]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function commitChanges(workspaceName) {
|
||||
execSync('git add .', {
|
||||
cwd: workspaceName,
|
||||
stdio: 'ignore'
|
||||
});
|
||||
execSync('git commit --amend --no-edit', {
|
||||
cwd: workspaceName,
|
||||
stdio: 'ignore'
|
||||
});
|
||||
}
|
||||
|
||||
function showNxWarning(workspaceName: string) {
|
||||
try {
|
||||
const pathToRunNxCommand = path.resolve(process.cwd(), workspaceName);
|
||||
execSync('nx --version', {
|
||||
cwd: pathToRunNxCommand,
|
||||
stdio: ['ignore', 'ignore', 'ignore']
|
||||
});
|
||||
} catch (e) {
|
||||
// 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 "npm nx" to execute commands in the workspace.`,
|
||||
`Run "yarn global add @nrwl/cli" or "npm install -g @nrwl/cli" to be able to execute command directly.`
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Move to @nrwl/workspace package?
|
||||
function determinePackageManager() {
|
||||
let packageManager = getPackageManagerFromAngularCLI();
|
||||
if (packageManager === 'npm' || isPackageManagerInstalled(packageManager)) {
|
||||
return packageManager;
|
||||
}
|
||||
|
||||
if (isPackageManagerInstalled('yarn')) {
|
||||
return 'yarn';
|
||||
}
|
||||
|
||||
if (isPackageManagerInstalled('pnpm')) {
|
||||
return 'pnpm';
|
||||
}
|
||||
|
||||
return 'npm';
|
||||
}
|
||||
|
||||
function getPackageManagerFromAngularCLI(): string {
|
||||
// If you have Angular CLI installed, read Angular CLI config.
|
||||
// If it isn't installed, default to 'yarn'.
|
||||
try {
|
||||
return execSync('ng config -g cli.packageManager', {
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
timeout: 500
|
||||
})
|
||||
.toString()
|
||||
.trim();
|
||||
} catch (e) {
|
||||
return 'yarn';
|
||||
}
|
||||
}
|
||||
|
||||
function isPackageManagerInstalled(packageManager: string) {
|
||||
let isInstalled = false;
|
||||
try {
|
||||
execSync(`${packageManager} --version`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore']
|
||||
});
|
||||
isInstalled = true;
|
||||
} catch (e) {
|
||||
/* do nothing */
|
||||
}
|
||||
return isInstalled;
|
||||
}
|
||||
|
||||
function determineWorkspaceName(parsedArgs: any): Promise<string> {
|
||||
const workspaceName: string = parsedArgs._[2];
|
||||
|
||||
if (workspaceName) {
|
||||
return Promise.resolve(workspaceName);
|
||||
}
|
||||
|
||||
return inquirer
|
||||
.prompt([
|
||||
{
|
||||
name: 'WorkspaceName',
|
||||
message: `Workspace name (e.g., org name) `,
|
||||
type: 'string'
|
||||
}
|
||||
])
|
||||
.then(a => {
|
||||
if (!a.WorkspaceName) {
|
||||
output.error({
|
||||
title: 'Invalid workspace name',
|
||||
bodyLines: [`Workspace name cannot be empty`]
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
return a.WorkspaceName;
|
||||
});
|
||||
}
|
||||
|
||||
function determinPluginName(parsedArgs) {
|
||||
if (parsedArgs.pluginName) {
|
||||
return Promise.resolve(parsedArgs.pluginName);
|
||||
}
|
||||
|
||||
return inquirer
|
||||
.prompt([
|
||||
{
|
||||
name: 'PluginName',
|
||||
message: `Plugin name `,
|
||||
type: 'string'
|
||||
}
|
||||
])
|
||||
.then(a => {
|
||||
if (!a.PluginName) {
|
||||
output.error({
|
||||
title: 'Invalid name',
|
||||
bodyLines: [`Name cannot be empty`]
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
return a.PluginName;
|
||||
});
|
||||
}
|
||||
|
||||
function showHelp() {
|
||||
console.log(`
|
||||
Usage: <name> [options]
|
||||
|
||||
Create a new Nx workspace
|
||||
|
||||
Args:
|
||||
|
||||
name workspace name
|
||||
|
||||
Options:
|
||||
|
||||
pluginName the name of the plugin to be created
|
||||
`);
|
||||
}
|
||||
10
packages/nx-plugin/builders.json
Normal file
10
packages/nx-plugin/builders.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "@angular-devkit/architect/src/builders-schema.json",
|
||||
"builders": {
|
||||
"e2e": {
|
||||
"implementation": "./src/builders/e2e/e2e.impl",
|
||||
"schema": "./src/builders/e2e/schema.json",
|
||||
"description": "Creates and runs an e2e for a Nx Plugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
18
packages/nx-plugin/collection.json
Normal file
18
packages/nx-plugin/collection.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Nx Plugin",
|
||||
"version": "0.1",
|
||||
"extends": ["@nrwl/workspace"],
|
||||
"schematics": {
|
||||
"plugin": {
|
||||
"factory": "./src/schematics/plugin/plugin",
|
||||
"schema": "./src/schematics/plugin/schema.json",
|
||||
"description": "Create a Nx Plugin"
|
||||
},
|
||||
"e2e-project": {
|
||||
"factory": "./src/schematics/e2e-project/e2e",
|
||||
"schema": "./src/schematics/e2e-project/schema.json",
|
||||
"description": "Create a e2e application for a Nx Plugin",
|
||||
"hidden": true
|
||||
}
|
||||
}
|
||||
}
|
||||
0
packages/nx-plugin/index.ts
Normal file
0
packages/nx-plugin/index.ts
Normal file
3
packages/nx-plugin/migrations.json
Normal file
3
packages/nx-plugin/migrations.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"schematics": {}
|
||||
}
|
||||
49
packages/nx-plugin/package.json
Normal file
49
packages/nx-plugin/package.json
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@nrwl/nx-plugin",
|
||||
"version": "0.0.1",
|
||||
"description": "Node Plugin for Nx",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nrwl/nx.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Monorepo",
|
||||
"Node",
|
||||
"Nest",
|
||||
"Jest",
|
||||
"Cypress",
|
||||
"CLI"
|
||||
],
|
||||
"main": "./index.js",
|
||||
"types": "./index.d.ts",
|
||||
"bin": "./bin/create.js",
|
||||
"author": "Nrwl",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nrwl/nx/issues"
|
||||
},
|
||||
"homepage": "https://nx.dev",
|
||||
"schematics": "./collection.json",
|
||||
"builders": "./builders.json",
|
||||
"ng-update": {
|
||||
"requirements": {},
|
||||
"migrations": "./migrations.json"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nrwl/workspace": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nrwl/node": "*",
|
||||
"@nrwl/linter": "*",
|
||||
"@nrwl/workspace": "*",
|
||||
"@nrwl/tao": "*",
|
||||
"@angular-devkit/architect": "0.803.23",
|
||||
"@angular-devkit/core": "8.3.23",
|
||||
"@angular-devkit/schematics": "8.3.23",
|
||||
"fs-extra": "7.0.1",
|
||||
"tmp": "0.0.33",
|
||||
"yargs-parser": "10.0.0",
|
||||
"yargs": "^11.0.0",
|
||||
"inquirer": "^6.3.1"
|
||||
}
|
||||
}
|
||||
64
packages/nx-plugin/src/builders/e2e/e2e.impl.spec.ts
Normal file
64
packages/nx-plugin/src/builders/e2e/e2e.impl.spec.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import { NxPluginE2EBuilderOptions, runNxPluginE2EBuilder } from './e2e.impl';
|
||||
import { MockBuilderContext } from '@nrwl/workspace/testing';
|
||||
import { getMockContext } from '../../utils/testing';
|
||||
import * as devkitArchitect from '@angular-devkit/architect';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
describe('NxPluginE2EBuilder', () => {
|
||||
let testOptions: NxPluginE2EBuilderOptions;
|
||||
let context: MockBuilderContext;
|
||||
let scheduleTargetAndForgetSpy: jest.SpyInstance;
|
||||
let contextBuilderSpy: jest.SpyInstance;
|
||||
beforeEach(async () => {
|
||||
context = await getMockContext();
|
||||
context.addTarget(
|
||||
{ project: 'plugin-e2e', target: 'build' },
|
||||
'@nrwl/nx-plugin:e2e'
|
||||
);
|
||||
testOptions = {
|
||||
jestConfig: 'apps/plugin-e2e/jest.config.js',
|
||||
tsSpecConfig: 'apps/plugin-e2e/tsconfig.spec.js',
|
||||
target: 'plugin:build'
|
||||
};
|
||||
|
||||
scheduleTargetAndForgetSpy = jest
|
||||
.spyOn(devkitArchitect, 'scheduleTargetAndForget')
|
||||
.mockImplementation((context, options) => {
|
||||
debugger;
|
||||
return of({ success: true });
|
||||
});
|
||||
|
||||
contextBuilderSpy = jest
|
||||
.spyOn(context, 'scheduleBuilder')
|
||||
.mockImplementation((name, overrides) => {
|
||||
console.log('hello');
|
||||
return new Promise((res, rej) => {
|
||||
res({
|
||||
result: of({ success: true }).toPromise(),
|
||||
id: 1,
|
||||
info: {
|
||||
builderName: 'builder',
|
||||
description: '',
|
||||
optionSchema: {}
|
||||
},
|
||||
output: of({ success: true }),
|
||||
progress: of({} as any),
|
||||
stop: jest.fn()
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should build the plugin and run the test', async () => {
|
||||
await runNxPluginE2EBuilder(testOptions, context).toPromise();
|
||||
expect(scheduleTargetAndForgetSpy).toHaveBeenCalledWith(context, {
|
||||
project: 'plugin',
|
||||
target: 'build'
|
||||
});
|
||||
expect(contextBuilderSpy).toHaveBeenCalledWith('@nrwl/jest:jest', {
|
||||
tsConfig: testOptions.tsSpecConfig,
|
||||
jestConfig: testOptions.jestConfig,
|
||||
watch: false
|
||||
});
|
||||
});
|
||||
});
|
||||
37
packages/nx-plugin/src/builders/e2e/e2e.impl.ts
Normal file
37
packages/nx-plugin/src/builders/e2e/e2e.impl.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import {
|
||||
BuilderContext,
|
||||
createBuilder,
|
||||
scheduleTargetAndForget,
|
||||
targetFromTargetString
|
||||
} from '@angular-devkit/architect';
|
||||
import { switchMap, concatMap } from 'rxjs/operators';
|
||||
import { Schema } from './schema';
|
||||
import { from } from 'rxjs';
|
||||
|
||||
try {
|
||||
require('dotenv').config();
|
||||
} catch (e) {}
|
||||
|
||||
export interface NxPluginE2EBuilderOptions extends Schema {}
|
||||
|
||||
export default createBuilder(runNxPluginE2EBuilder);
|
||||
export function runNxPluginE2EBuilder(
|
||||
options: NxPluginE2EBuilderOptions,
|
||||
context: BuilderContext
|
||||
) {
|
||||
return buildTarget(context, options.target).pipe(
|
||||
switchMap(() => {
|
||||
return from(
|
||||
context.scheduleBuilder('@nrwl/jest:jest', {
|
||||
tsConfig: options.tsSpecConfig,
|
||||
jestConfig: options.jestConfig,
|
||||
watch: false
|
||||
})
|
||||
).pipe(concatMap(run => run.output));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function buildTarget(context: BuilderContext, target: string) {
|
||||
return scheduleTargetAndForget(context, targetFromTargetString(target));
|
||||
}
|
||||
7
packages/nx-plugin/src/builders/e2e/schema.d.ts
vendored
Normal file
7
packages/nx-plugin/src/builders/e2e/schema.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { JsonObject } from '@angular-devkit/core';
|
||||
|
||||
export interface Schema extends JsonObject {
|
||||
target: string;
|
||||
jestConfig: string;
|
||||
tsSpecConfig: string;
|
||||
}
|
||||
20
packages/nx-plugin/src/builders/e2e/schema.json
Normal file
20
packages/nx-plugin/src/builders/e2e/schema.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"title": "Nx Plugin Playground Target",
|
||||
"description": "Creates a playground for a Nx Plugin",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"target": {
|
||||
"type": "string",
|
||||
"description": "the target Nx Plugin project and build"
|
||||
},
|
||||
"jestConfig": {
|
||||
"type": "string",
|
||||
"description": "Jest config file"
|
||||
},
|
||||
"tsSpecConfig": {
|
||||
"type": "string",
|
||||
"description": "Spec tsconfig file"
|
||||
}
|
||||
},
|
||||
"required": ["target", "jestConfig", "tsSpecConfig"]
|
||||
}
|
||||
130
packages/nx-plugin/src/schematics/e2e-project/e2e.spec.ts
Normal file
130
packages/nx-plugin/src/schematics/e2e-project/e2e.spec.ts
Normal file
@ -0,0 +1,130 @@
|
||||
import { Tree } from '@angular-devkit/schematics';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
import {
|
||||
updateWorkspace,
|
||||
readJsonInTree,
|
||||
readWorkspace,
|
||||
getWorkspace
|
||||
} from '@nrwl/workspace';
|
||||
import { runSchematic } from '../../utils/testing';
|
||||
|
||||
describe('NxPlugin e2e-project', () => {
|
||||
let appTree: Tree;
|
||||
beforeEach(() => {
|
||||
appTree = createEmptyWorkspace(Tree.empty());
|
||||
// add a plugin project to the workspace for validations
|
||||
updateWorkspace(workspace => {
|
||||
workspace.projects.add({ name: 'my-plugin', root: 'libs/my-plugin' });
|
||||
})(appTree, null);
|
||||
});
|
||||
|
||||
it('should validate the plugin name', async () => {
|
||||
await expect(
|
||||
runSchematic(
|
||||
'e2e-project',
|
||||
{
|
||||
pluginName: 'my-plugin',
|
||||
pluginOutputPath: `dist/libs/my-plugin`,
|
||||
npmPackageName: '@proj/my-plugin'
|
||||
},
|
||||
appTree
|
||||
)
|
||||
).resolves.not.toThrow();
|
||||
|
||||
await expect(
|
||||
runSchematic(
|
||||
'e2e-project',
|
||||
{
|
||||
pluginName: 'my-nonexistentplugin',
|
||||
pluginOutputPath: `dist/libs/my-nonexistentplugin`,
|
||||
npmPackageName: '@proj/my-nonexistentplugin'
|
||||
},
|
||||
appTree
|
||||
)
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('should add files related to e2e', async () => {
|
||||
const tree = await runSchematic(
|
||||
'e2e-project',
|
||||
{
|
||||
pluginName: 'my-plugin',
|
||||
pluginOutputPath: `dist/libs/my-plugin`,
|
||||
npmPackageName: '@proj/my-plugin'
|
||||
},
|
||||
appTree
|
||||
);
|
||||
expect(tree.exists('apps/my-plugin-e2e/tsconfig.json')).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('apps/my-plugin-e2e/tests/my-plugin.test.ts')
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update the nxJson', async () => {
|
||||
const tree = await runSchematic(
|
||||
'e2e-project',
|
||||
{
|
||||
pluginName: 'my-plugin',
|
||||
pluginOutputPath: `dist/libs/my-plugin`,
|
||||
npmPackageName: '@proj/my-plugin'
|
||||
},
|
||||
appTree
|
||||
);
|
||||
expect(JSON.parse(tree.readContent('nx.json'))).toMatchObject({
|
||||
projects: {
|
||||
'my-plugin-e2e': {
|
||||
tags: [],
|
||||
implicitDependencies: ['my-plugin']
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should update the workspace', async () => {
|
||||
const tree = await runSchematic(
|
||||
'e2e-project',
|
||||
{
|
||||
pluginName: 'my-plugin',
|
||||
pluginOutputPath: `dist/libs/my-plugin`,
|
||||
npmPackageName: '@proj/my-plugin'
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const workspace = await getWorkspace(tree);
|
||||
const project = workspace.projects.get('my-plugin-e2e');
|
||||
expect(project).toBeTruthy();
|
||||
expect(project.root).toEqual('apps/my-plugin-e2e');
|
||||
expect(project.targets.get('e2e')).toBeTruthy();
|
||||
expect(project.targets.get('e2e')).toMatchObject({
|
||||
builder: '@nrwl/nx-plugin:e2e',
|
||||
options: expect.objectContaining({
|
||||
target: 'my-plugin:build',
|
||||
npmPackageName: '@proj/my-plugin',
|
||||
pluginOutputPath: 'dist/libs/my-plugin'
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('should add jest support', async () => {
|
||||
const tree = await runSchematic(
|
||||
'e2e-project',
|
||||
{
|
||||
pluginName: 'my-plugin',
|
||||
pluginOutputPath: `dist/libs/my-plugin`,
|
||||
npmPackageName: '@proj/my-plugin'
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const workspace = await getWorkspace(tree);
|
||||
const project = workspace.projects.get('my-plugin-e2e');
|
||||
expect(project.targets.get('e2e')).toMatchObject({
|
||||
options: expect.objectContaining({
|
||||
tsSpecConfig: 'apps/my-plugin-e2e/tsconfig.spec.json',
|
||||
jestConfig: 'apps/my-plugin-e2e/jest.config.js'
|
||||
})
|
||||
});
|
||||
|
||||
expect(tree.exists('apps/my-plugin-e2e/tsconfig.spec.json')).toBeTruthy();
|
||||
expect(tree.exists('apps/my-plugin-e2e/jest.config.js')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
143
packages/nx-plugin/src/schematics/e2e-project/e2e.ts
Normal file
143
packages/nx-plugin/src/schematics/e2e-project/e2e.ts
Normal file
@ -0,0 +1,143 @@
|
||||
import { normalize } from '@angular-devkit/core';
|
||||
import { WorkspaceDefinition } from '@angular-devkit/core/src/workspace';
|
||||
import {
|
||||
apply,
|
||||
chain,
|
||||
externalSchematic,
|
||||
mergeWith,
|
||||
move,
|
||||
Rule,
|
||||
SchematicContext,
|
||||
SchematicsException,
|
||||
template,
|
||||
Tree,
|
||||
url
|
||||
} from '@angular-devkit/schematics';
|
||||
import {
|
||||
addProjectToNxJsonInTree,
|
||||
getWorkspace,
|
||||
offsetFromRoot,
|
||||
readNxJsonInTree,
|
||||
toPropertyName,
|
||||
updateWorkspace
|
||||
} from '@nrwl/workspace';
|
||||
import { join } from 'path';
|
||||
import { Schema } from './schema';
|
||||
|
||||
export interface NxPluginE2ESchema extends Schema {
|
||||
projectRoot: string;
|
||||
projectName: string;
|
||||
pluginPropertyName: string;
|
||||
npmScope: string;
|
||||
}
|
||||
|
||||
export default function(options: Schema): Rule {
|
||||
return async (host: Tree, context: SchematicContext) => {
|
||||
const workspace = await getWorkspace(host);
|
||||
validatePlugin(workspace, options.pluginName);
|
||||
const normalizedOptions = normalizeOptions(host, options);
|
||||
return chain([
|
||||
updateFiles(normalizedOptions),
|
||||
updateNxJson(normalizedOptions),
|
||||
updateWorkspaceJson(normalizedOptions),
|
||||
addJest(normalizedOptions)
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
function validatePlugin(workspace: WorkspaceDefinition, pluginName: string) {
|
||||
const project = workspace.projects.get(pluginName);
|
||||
if (!project) {
|
||||
throw new SchematicsException(
|
||||
`Project name "${pluginName}" doesn't not exist.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeOptions(host: Tree, options: Schema): NxPluginE2ESchema {
|
||||
const projectName = `${options.pluginName}-e2e`;
|
||||
const projectRoot = join(normalize('apps'), projectName);
|
||||
const npmScope = readNxJsonInTree(host).npmScope;
|
||||
const pluginPropertyName = toPropertyName(options.pluginName);
|
||||
return {
|
||||
...options,
|
||||
projectName,
|
||||
pluginPropertyName,
|
||||
projectRoot,
|
||||
npmScope
|
||||
};
|
||||
}
|
||||
|
||||
function updateNxJson(options: NxPluginE2ESchema): Rule {
|
||||
return addProjectToNxJsonInTree(options.projectName, {
|
||||
tags: [],
|
||||
implicitDependencies: [options.pluginName]
|
||||
});
|
||||
}
|
||||
|
||||
function updateWorkspaceJson(options: NxPluginE2ESchema): Rule {
|
||||
return chain([
|
||||
async (host, context) => {
|
||||
const workspace = await getWorkspace(host);
|
||||
workspace.projects.add({
|
||||
name: options.projectName,
|
||||
root: options.projectRoot,
|
||||
projectType: 'application',
|
||||
sourceRoot: `${options.projectRoot}/src`,
|
||||
targets: {
|
||||
e2e: {
|
||||
builder: '@nrwl/nx-plugin:e2e',
|
||||
options: {
|
||||
target: `${options.pluginName}:build`,
|
||||
npmPackageName: options.npmPackageName,
|
||||
pluginOutputPath: options.pluginOutputPath
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updateWorkspace(workspace);
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
function updateFiles(options: NxPluginE2ESchema): Rule {
|
||||
return mergeWith(
|
||||
apply(url('./files'), [
|
||||
template({
|
||||
tmpl: '',
|
||||
...options,
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot)
|
||||
}),
|
||||
move(options.projectRoot)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
function addJest(options: NxPluginE2ESchema): Rule {
|
||||
return chain([
|
||||
externalSchematic('@nrwl/jest', 'jest-project', {
|
||||
project: options.projectName,
|
||||
setupFile: 'none',
|
||||
supportTsx: false,
|
||||
skipSerializers: true
|
||||
}),
|
||||
async (host, context) => {
|
||||
const workspace = await getWorkspace(host);
|
||||
const project = workspace.projects.get(options.projectName);
|
||||
const testOptions = project.targets.get('test').options;
|
||||
const e2eOptions = project.targets.get('e2e').options;
|
||||
project.targets.get('e2e').options = {
|
||||
...e2eOptions,
|
||||
...{
|
||||
jestConfig: testOptions.jestConfig,
|
||||
tsSpecConfig: testOptions.tsConfig
|
||||
}
|
||||
};
|
||||
|
||||
// remove the jest build target
|
||||
project.targets.delete('test');
|
||||
|
||||
return updateWorkspace(workspace);
|
||||
}
|
||||
]);
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
import {
|
||||
checkFilesExist,
|
||||
ensureNxProject,
|
||||
readJson,
|
||||
runNxCommandAsync,
|
||||
uniq,
|
||||
} from '@nrwl/nx-plugin/testing';
|
||||
describe('<%= pluginName %> e2e', () => {
|
||||
it('should create <%= pluginName %>', async (done) => {
|
||||
const plugin = uniq('<%= pluginName %>');
|
||||
ensureNxProject('<%= npmPackageName %>', '<%= pluginOutputPath %>');
|
||||
await runNxCommandAsync(`generate <%=npmPackageName%>:<%= pluginPropertyName %> ${plugin}`);
|
||||
|
||||
const result = await runNxCommandAsync(`build ${plugin}`);
|
||||
expect(result.stdout).toContain('Builder ran');
|
||||
|
||||
done();
|
||||
})
|
||||
|
||||
describe('--directory', () => {
|
||||
it('should create src in the specified directory', async (done) => {
|
||||
const plugin = uniq('<%= pluginName %>');
|
||||
ensureNxProject('<%= npmPackageName %>', '<%= pluginOutputPath %>');
|
||||
await runNxCommandAsync(
|
||||
`generate <%=npmPackageName%>:<%= pluginPropertyName %> ${plugin} --directory subdir`
|
||||
);
|
||||
expect(() => checkFilesExist(`libs/subdir/${plugin}/src/index.ts`)).not.toThrow();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('--tags', () => {
|
||||
it('should add tags to nx.json', async (done) => {
|
||||
const plugin = uniq('<%= pluginName %>');
|
||||
ensureNxProject('<%= npmPackageName %>', '<%= pluginOutputPath %>');
|
||||
await runNxCommandAsync(
|
||||
`generate <%=npmPackageName%>:<%= pluginPropertyName %> ${plugin} --tags e2etag,e2ePackage`
|
||||
);
|
||||
const nxJson = readJson('nx.json');
|
||||
expect(nxJson.projects[plugin].tags).toEqual(['e2etag', 'e2ePackage']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "<%= offsetFromRoot %>tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"types": [
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": ["**/*.ts"]
|
||||
}
|
||||
9
packages/nx-plugin/src/schematics/e2e-project/schema.d.ts
vendored
Normal file
9
packages/nx-plugin/src/schematics/e2e-project/schema.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
import { Linter } from '@nrwl/workspace';
|
||||
|
||||
export interface Schema {
|
||||
pluginName: string;
|
||||
npmPackageName: string;
|
||||
pluginOutputPath: string;
|
||||
jestConfig: string;
|
||||
tsSpecConfig: string;
|
||||
}
|
||||
28
packages/nx-plugin/src/schematics/e2e-project/schema.json
Normal file
28
packages/nx-plugin/src/schematics/e2e-project/schema.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"id": "NxPluginE2E",
|
||||
"title": "Create an e2e app for a Nx Plugin",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pluginName": {
|
||||
"type": "string",
|
||||
"description": "the name of the pluging to be tested"
|
||||
},
|
||||
"npmPackageName": {
|
||||
"type": "string",
|
||||
"description": "the name of the package that would be published to NPM"
|
||||
},
|
||||
"pluginOutputPath": {
|
||||
"type": "string",
|
||||
"description": "the output path of the plugin after it builds"
|
||||
},
|
||||
"jestConfig": {
|
||||
"type": "string",
|
||||
"description": "Jest config file"
|
||||
},
|
||||
"tsSpecConfig": {
|
||||
"type": "string",
|
||||
"description": "Spec tsconfig file"
|
||||
}
|
||||
},
|
||||
"required": ["pluginName", "npmPackageName"]
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "<%= offsetFromRoot %>node_modules/@angular-devkit/architect/src/builders-schema.json",
|
||||
"builders": {
|
||||
"build": {
|
||||
"implementation": "./src/builders/<%= fileName %>/builder",
|
||||
"schema": "./src/builders/<%= fileName %>/schema.json",
|
||||
"description": "<%= name %> builder"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "<%= offsetFromRoot %>node_modules/@angular-devkit/schematics/collection-schema.json",
|
||||
"name": "<%= name %>",
|
||||
"version": "0.0.1",
|
||||
"schematics": {
|
||||
"<%= propertyName %>": {
|
||||
"factory": "./src/schematics/<%= fileName %>/schematic",
|
||||
"schema": "./src/schematics/<%= fileName %>/schema.json",
|
||||
"description": "<%= name %> schematic"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "<%= npmPackageName %>",
|
||||
"version": "0.0.1",
|
||||
"main": "src/index.js",
|
||||
"schematics": "./collection.json",
|
||||
"builders": "./builders.json",
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
import { Architect } from '@angular-devkit/architect';
|
||||
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
|
||||
import { schema } from '@angular-devkit/core';
|
||||
import { join } from 'path';
|
||||
import { <%= className %>BuilderSchema } from './schema';
|
||||
|
||||
const options: <%= className %>BuilderSchema = {};
|
||||
|
||||
describe('Command Runner Builder', () => {
|
||||
let architect: Architect;
|
||||
let architectHost: TestingArchitectHost;
|
||||
|
||||
beforeEach(async () => {
|
||||
const registry = new schema.CoreSchemaRegistry();
|
||||
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
|
||||
|
||||
architectHost = new TestingArchitectHost('/root', '/root');
|
||||
architect = new Architect(architectHost, registry);
|
||||
|
||||
// This will either take a Node package name, or a path to the directory
|
||||
// for the package.json file.
|
||||
await architectHost.addBuilderFromPackage(join(__dirname, '../../..'));
|
||||
});
|
||||
|
||||
it('can run', async () => {
|
||||
// A "run" can have multiple outputs, and contains progress information.
|
||||
const run = await architect.scheduleBuilder('@<%= npmScope %>/<%= fileName %>:build', options); // We pass the logger for checking later.
|
||||
|
||||
// The "result" member (of type BuilderOutput) is the next output.
|
||||
const output = await run.result;
|
||||
|
||||
// Stop the builder from running. This stops Architect from keeping
|
||||
// the builder-associated states in memory, since builders keep waiting
|
||||
// to be scheduled.
|
||||
await run.stop();
|
||||
|
||||
// Expect that it succeeded.
|
||||
expect(output.success).toBe(true);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,19 @@
|
||||
import {
|
||||
BuilderContext,
|
||||
BuilderOutput,
|
||||
createBuilder
|
||||
} from '@angular-devkit/architect';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { <%= className %>BuilderSchema } from './schema';
|
||||
|
||||
export function runBuilder(
|
||||
options: <%= className %>BuilderSchema,
|
||||
context: BuilderContext
|
||||
): Observable<BuilderOutput> {
|
||||
return of({ success: true }).pipe(tap(() => {
|
||||
context.logger.info("Builder ran for <%= name %>");
|
||||
}));
|
||||
}
|
||||
|
||||
export default createBuilder(runBuilder);
|
||||
@ -0,0 +1,3 @@
|
||||
import { JsonObject } from '@angular-devkit/core';
|
||||
|
||||
export interface <%= className %>BuilderSchema extends JsonObject {}
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft-07/schema",
|
||||
"$id": "https://json-schema.org/draft-07/schema",
|
||||
"title": "<%= className %> builder",
|
||||
"description": "",
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
<%= fileTemplate %>
|
||||
@ -0,0 +1,5 @@
|
||||
export interface <%= className %>SchematicSchema {
|
||||
name: string;
|
||||
tags?: string;
|
||||
directory?: string;
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"id": "<%= className %>",
|
||||
"title": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
},
|
||||
"x-prompt": "What name would you like to use?"
|
||||
},
|
||||
"tags": {
|
||||
"type": "string",
|
||||
"description": "Add tags to the project (used for linting)",
|
||||
"alias": "t"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string",
|
||||
"description": "A directory where the project is placed",
|
||||
"alias": "d"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
import { Tree } from '@angular-devkit/schematics';
|
||||
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
import { join } from 'path'
|
||||
|
||||
import { <%= className %>SchematicSchema } from './schema';
|
||||
|
||||
describe('<%= name %> schematic', () => {
|
||||
let appTree: Tree;
|
||||
const options: <%= className %>SchematicSchema = { name: 'test' };
|
||||
|
||||
const testRunner = new SchematicTestRunner(
|
||||
'@<%= npmScope %>/<%= name %>',
|
||||
join(__dirname, '../../../collection.json')
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
appTree = createEmptyWorkspace(Tree.empty());
|
||||
});
|
||||
|
||||
it('should run successfully', async () => {
|
||||
await expect(testRunner.runSchematicAsync(
|
||||
'<%= propertyName %>',
|
||||
options,
|
||||
appTree
|
||||
).toPromise()
|
||||
).resolves.not.toThrowError();
|
||||
})
|
||||
});
|
||||
@ -0,0 +1,85 @@
|
||||
import {
|
||||
apply,
|
||||
applyTemplates,
|
||||
chain,
|
||||
mergeWith,
|
||||
move,
|
||||
Rule,
|
||||
url
|
||||
} from '@angular-devkit/schematics';
|
||||
import {
|
||||
addProjectToNxJsonInTree,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
projectRootDir,
|
||||
ProjectType,
|
||||
toFileName,
|
||||
updateWorkspace
|
||||
} from '@nrwl/workspace';
|
||||
import { <%= className %>SchematicSchema } from './schema';
|
||||
|
||||
/**
|
||||
* Depending on your needs, you can change this to either `Library` or `Application`
|
||||
*/
|
||||
const projectType = ProjectType.Library
|
||||
|
||||
interface NormalizedSchema extends <%= className %>SchematicSchema {
|
||||
projectName: string;
|
||||
projectRoot: string;
|
||||
projectDirectory: string;
|
||||
parsedTags: string[]
|
||||
}
|
||||
|
||||
function normalizeOptions(options: <%= className %>SchematicSchema): NormalizedSchema {
|
||||
const name = toFileName(options.name);
|
||||
const projectDirectory = options.directory
|
||||
? `${toFileName(options.directory)}/${name}`
|
||||
: name;
|
||||
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
const projectRoot = `${projectRootDir(projectType)}/${projectDirectory}`;
|
||||
const parsedTags = options.tags
|
||||
? options.tags.split(',').map(s => s.trim())
|
||||
: [];
|
||||
|
||||
return {
|
||||
...options,
|
||||
projectName,
|
||||
projectRoot,
|
||||
projectDirectory,
|
||||
parsedTags
|
||||
};
|
||||
}
|
||||
|
||||
function addFiles(options: NormalizedSchema): Rule {
|
||||
return mergeWith(
|
||||
apply(url(`./files`), [
|
||||
applyTemplates({
|
||||
...options,
|
||||
...names(options.name),
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot)
|
||||
}),
|
||||
move(options.projectRoot)
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
export default function(options: <%= className %>SchematicSchema): Rule {
|
||||
const normalizedOptions = normalizeOptions(options);
|
||||
return chain([
|
||||
updateWorkspace(workspace => {
|
||||
workspace.projects.add({
|
||||
name: normalizedOptions.projectName,
|
||||
root: normalizedOptions.projectRoot,
|
||||
sourceRoot: `${normalizedOptions.projectRoot}/src`,
|
||||
projectType
|
||||
}).targets.add({
|
||||
name: 'build',
|
||||
builder: '<%= npmPackageName %>:build'
|
||||
})
|
||||
}),
|
||||
addProjectToNxJsonInTree(normalizedOptions.projectName, { tags: normalizedOptions.parsedTags }),
|
||||
addFiles(normalizedOptions)
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
139
packages/nx-plugin/src/schematics/plugin/plugin.spec.ts
Normal file
139
packages/nx-plugin/src/schematics/plugin/plugin.spec.ts
Normal file
@ -0,0 +1,139 @@
|
||||
import * as ngSchematics from '@angular-devkit/schematics';
|
||||
import { readJsonInTree, readWorkspace } from '@nrwl/workspace';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
import { runSchematic } from '../../utils/testing';
|
||||
|
||||
describe('NxPlugin plugin', () => {
|
||||
let appTree: ngSchematics.Tree;
|
||||
beforeEach(() => {
|
||||
appTree = createEmptyWorkspace(ngSchematics.Tree.empty());
|
||||
});
|
||||
|
||||
it('should update the workspace.json file', async () => {
|
||||
const tree = await runSchematic('plugin', { name: 'myPlugin' }, appTree);
|
||||
const workspace = await readWorkspace(tree);
|
||||
const project = workspace.projects['my-plugin'];
|
||||
expect(project.root).toEqual('libs/my-plugin');
|
||||
expect(project.architect.build).toEqual({
|
||||
builder: '@nrwl/node:package',
|
||||
options: {
|
||||
outputPath: 'dist/libs/my-plugin',
|
||||
tsConfig: 'libs/my-plugin/tsconfig.lib.json',
|
||||
packageJson: 'libs/my-plugin/package.json',
|
||||
main: 'libs/my-plugin/src/index.ts',
|
||||
assets: [
|
||||
'libs/my-plugin/*.md',
|
||||
{
|
||||
input: './libs/my-plugin/src',
|
||||
glob: '**/*.!(ts)',
|
||||
output: './src'
|
||||
},
|
||||
{
|
||||
input: './libs/my-plugin',
|
||||
glob: 'collection.json',
|
||||
output: '.'
|
||||
},
|
||||
{
|
||||
input: './libs/my-plugin',
|
||||
glob: 'builders.json',
|
||||
output: '.'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
expect(project.architect.lint).toEqual({
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
options: {
|
||||
exclude: ['**/node_modules/**', '!libs/my-plugin/**'],
|
||||
tsConfig: [
|
||||
'libs/my-plugin/tsconfig.lib.json',
|
||||
'libs/my-plugin/tsconfig.spec.json'
|
||||
]
|
||||
}
|
||||
});
|
||||
expect(project.architect.test).toEqual({
|
||||
builder: '@nrwl/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'libs/my-plugin/jest.config.js',
|
||||
tsConfig: 'libs/my-plugin/tsconfig.spec.json'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should update the tsconfig.lib.json file', async () => {
|
||||
const tree = await runSchematic('plugin', { name: 'myPlugin' }, appTree);
|
||||
const tsLibConfig = readJsonInTree(
|
||||
tree,
|
||||
'libs/my-plugin/tsconfig.lib.json'
|
||||
);
|
||||
expect(tsLibConfig.compilerOptions.rootDir).toEqual('.');
|
||||
});
|
||||
|
||||
it('should create schematic and builder files', async () => {
|
||||
const tree = await runSchematic('plugin', { name: 'myPlugin' }, appTree);
|
||||
expect(tree.exists('libs/my-plugin/collection.json')).toBeTruthy();
|
||||
expect(tree.exists('libs/my-plugin/builders.json')).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('libs/my-plugin/src/schematics/my-plugin/schema.d.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('libs/my-plugin/src/schematics/my-plugin/schematic.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('libs/my-plugin/src/schematics/my-plugin/schematic.spec.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('libs/my-plugin/src/schematics/my-plugin/schema.json')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('libs/my-plugin/src/schematics/my-plugin/schema.d.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists(
|
||||
'libs/my-plugin/src/schematics/my-plugin/files/src/index.ts.template'
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.readContent(
|
||||
'libs/my-plugin/src/schematics/my-plugin/files/src/index.ts.template'
|
||||
)
|
||||
).toContain('const variable = "<%= projectName %>";');
|
||||
expect(
|
||||
tree.exists('libs/my-plugin/src/builders/my-plugin/builder.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('libs/my-plugin/src/builders/my-plugin/builder.spec.ts')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('libs/my-plugin/src/builders/my-plugin/schema.json')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
tree.exists('libs/my-plugin/src/builders/my-plugin/schema.d.ts')
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should call the @nrwl/node:lib schematic', async () => {
|
||||
const externalSchematicSpy = jest.spyOn(ngSchematics, 'externalSchematic');
|
||||
await runSchematic('plugin', { name: 'myPlugin' }, appTree);
|
||||
expect(externalSchematicSpy).toBeCalledWith(
|
||||
'@nrwl/node',
|
||||
'lib',
|
||||
expect.objectContaining({
|
||||
publishable: true
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should call the @nrwl/nx-plugin:e2e schematic', async () => {
|
||||
const schematicSpy = jest.spyOn(ngSchematics, 'schematic');
|
||||
const tree = await runSchematic('plugin', { name: 'myPlugin' }, appTree);
|
||||
expect(schematicSpy).toBeCalledWith(
|
||||
'e2e-project',
|
||||
expect.objectContaining({
|
||||
pluginName: 'my-plugin',
|
||||
pluginOutputPath: `dist/libs/my-plugin`,
|
||||
npmPackageName: '@proj/my-plugin'
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
165
packages/nx-plugin/src/schematics/plugin/plugin.ts
Normal file
165
packages/nx-plugin/src/schematics/plugin/plugin.ts
Normal file
@ -0,0 +1,165 @@
|
||||
import { JsonArray, normalize, Path } from '@angular-devkit/core';
|
||||
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||
import {
|
||||
apply,
|
||||
chain,
|
||||
externalSchematic,
|
||||
MergeStrategy,
|
||||
mergeWith,
|
||||
move,
|
||||
Rule,
|
||||
schematic,
|
||||
SchematicContext,
|
||||
template,
|
||||
Tree,
|
||||
url
|
||||
} from '@angular-devkit/schematics';
|
||||
import {
|
||||
formatFiles,
|
||||
getProjectConfig,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
readNxJsonInTree,
|
||||
toFileName,
|
||||
updateJsonInTree,
|
||||
updateWorkspace
|
||||
} from '@nrwl/workspace';
|
||||
import { allFilesInDirInHost } from '@nrwl/workspace/src/utils/ast-utils';
|
||||
import { Schema } from './schema';
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
fileName: string;
|
||||
projectRoot: Path;
|
||||
projectDirectory: string;
|
||||
parsedTags: string[];
|
||||
npmScope: string;
|
||||
npmPackageName: string;
|
||||
fileTemplate: string;
|
||||
}
|
||||
|
||||
export default function(schema: NormalizedSchema): Rule {
|
||||
return (host: Tree, context: SchematicContext) => {
|
||||
const options = normalizeOptions(host, schema);
|
||||
|
||||
return chain([
|
||||
externalSchematic('@nrwl/node', 'lib', {
|
||||
...schema,
|
||||
publishable: true
|
||||
}),
|
||||
addFiles(options),
|
||||
updateWorkspaceJson(options),
|
||||
updateTsConfig(options),
|
||||
schematic('e2e-project', {
|
||||
pluginName: options.name,
|
||||
pluginOutputPath: `dist/libs/${options.projectDirectory}`,
|
||||
npmPackageName: options.npmPackageName
|
||||
}),
|
||||
formatFiles(options)
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
||||
const nxJson = readNxJsonInTree(host);
|
||||
const npmScope = nxJson.npmScope;
|
||||
const name = toFileName(options.name);
|
||||
const projectDirectory = options.directory
|
||||
? `${toFileName(options.directory)}/${name}`
|
||||
: name;
|
||||
|
||||
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
const fileName = projectName;
|
||||
const projectRoot = normalize(`libs/${projectDirectory}`);
|
||||
|
||||
const parsedTags = options.tags
|
||||
? options.tags.split(',').map(s => s.trim())
|
||||
: [];
|
||||
const npmPackageName = `@${npmScope}/${name}`;
|
||||
|
||||
const fileTemplate = getFileTemplate();
|
||||
|
||||
const normalized: NormalizedSchema = {
|
||||
...options,
|
||||
fileName,
|
||||
npmScope,
|
||||
name: projectName,
|
||||
projectRoot,
|
||||
projectDirectory,
|
||||
parsedTags,
|
||||
npmPackageName,
|
||||
fileTemplate
|
||||
};
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function addFiles(options: NormalizedSchema): Rule {
|
||||
return chain([
|
||||
host => {
|
||||
allFilesInDirInHost(
|
||||
host,
|
||||
normalize(`${options.projectRoot}/src/lib`)
|
||||
).forEach(file => {
|
||||
host.delete(file);
|
||||
});
|
||||
|
||||
return host;
|
||||
},
|
||||
mergeWith(
|
||||
apply(url(`./files/plugin`), [
|
||||
template({
|
||||
...options,
|
||||
...names(options.name),
|
||||
tmpl: '',
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot)
|
||||
}),
|
||||
move(options.projectRoot)
|
||||
]),
|
||||
MergeStrategy.Overwrite
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
function updateWorkspaceJson(options: NormalizedSchema): Rule {
|
||||
return updateWorkspace(workspace => {
|
||||
const targets = workspace.projects.get(options.name).targets;
|
||||
const build = targets.get('build');
|
||||
if (build) {
|
||||
(build.options.assets as JsonArray).push(
|
||||
...[
|
||||
{
|
||||
input: `./${options.projectRoot}/src`,
|
||||
glob: '**/*.!(ts)',
|
||||
output: './src'
|
||||
},
|
||||
{
|
||||
input: `./${options.projectRoot}`,
|
||||
glob: 'collection.json',
|
||||
output: '.'
|
||||
},
|
||||
{
|
||||
input: `./${options.projectRoot}`,
|
||||
glob: 'builders.json',
|
||||
output: '.'
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateTsConfig(options: NormalizedSchema): Rule {
|
||||
return (host: Tree, context: SchematicContext) => {
|
||||
const projectConfig = getProjectConfig(host, options.name);
|
||||
return updateJsonInTree(`${projectConfig.root}/tsconfig.lib.json`, json => {
|
||||
json.compilerOptions.rootDir = '.';
|
||||
return json;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function getFileTemplate() {
|
||||
return stripIndents`
|
||||
const variable = "<%= projectName %>";
|
||||
`;
|
||||
}
|
||||
11
packages/nx-plugin/src/schematics/plugin/schema.d.ts
vendored
Normal file
11
packages/nx-plugin/src/schematics/plugin/schema.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
import { Linter } from '@nrwl/workspace';
|
||||
|
||||
export interface Schema {
|
||||
name: string;
|
||||
directory?: string;
|
||||
skipTsConfig: boolean;
|
||||
skipFormat: boolean;
|
||||
tags?: string;
|
||||
unitTestRunner: 'jest' | 'none';
|
||||
linter: Linter;
|
||||
}
|
||||
56
packages/nx-plugin/src/schematics/plugin/schema.json
Normal file
56
packages/nx-plugin/src/schematics/plugin/schema.json
Normal file
@ -0,0 +1,56 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"id": "NxPluginPlugin",
|
||||
"title": "Create a Plugin for Nx",
|
||||
"type": "object",
|
||||
"examples": [
|
||||
{
|
||||
"command": "g plugin my-plugin --directory=plugins",
|
||||
"description": "Generate libs/plugins/my-plugin"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Plugin name",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
},
|
||||
"x-prompt": "What name would you like to use for the plugin?"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string",
|
||||
"description": "A directory where the plugin is placed",
|
||||
"alias": "d"
|
||||
},
|
||||
"linter": {
|
||||
"description": "The tool to use for running lint checks.",
|
||||
"type": "string",
|
||||
"enum": ["eslint", "tslint"],
|
||||
"default": "tslint"
|
||||
},
|
||||
"unitTestRunner": {
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
"description": "Test runner to use for unit tests",
|
||||
"default": "jest"
|
||||
},
|
||||
"tags": {
|
||||
"type": "string",
|
||||
"description": "Add tags to the library (used for linting)",
|
||||
"alias": "t"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"skipTsConfig": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Do not update tsconfig.json for development experience."
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
46
packages/nx-plugin/src/utils/testing-utils/async-commands.ts
Normal file
46
packages/nx-plugin/src/utils/testing-utils/async-commands.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { exec } from 'child_process';
|
||||
import { tmpProjPath } from './paths';
|
||||
|
||||
/**
|
||||
* Run a command asynchronously
|
||||
* @param command
|
||||
* @param opts
|
||||
*/
|
||||
export function runCommandAsync(
|
||||
command: string,
|
||||
opts = {
|
||||
silenceError: false
|
||||
}
|
||||
): Promise<{ stdout: string; stderr: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(
|
||||
command,
|
||||
{
|
||||
cwd: tmpProjPath()
|
||||
},
|
||||
(err, stdout, stderr) => {
|
||||
if (!opts.silenceError && err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve({ stdout, stderr });
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a nx command asynchronously
|
||||
* @param command
|
||||
* @param opts
|
||||
*/
|
||||
export function runNxCommandAsync(
|
||||
command: string,
|
||||
opts = {
|
||||
silenceError: false
|
||||
}
|
||||
): Promise<{ stdout: string; stderr: string }> {
|
||||
return runCommandAsync(
|
||||
`node ./node_modules/@nrwl/cli/bin/nx.js ${command}`,
|
||||
opts
|
||||
);
|
||||
}
|
||||
43
packages/nx-plugin/src/utils/testing-utils/commands.ts
Normal file
43
packages/nx-plugin/src/utils/testing-utils/commands.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { execSync } from 'child_process';
|
||||
import { tmpProjPath } from './paths';
|
||||
|
||||
/**
|
||||
* Run a nx command
|
||||
* @param command
|
||||
* @param opts
|
||||
*/
|
||||
export function runNxCommand(
|
||||
command?: string,
|
||||
opts = {
|
||||
silenceError: false
|
||||
}
|
||||
): string {
|
||||
try {
|
||||
return execSync(`node ./node_modules/@nrwl/cli/bin/nx.js ${command}`, {
|
||||
cwd: tmpProjPath()
|
||||
})
|
||||
.toString()
|
||||
.replace(
|
||||
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
|
||||
''
|
||||
);
|
||||
} catch (e) {
|
||||
if (opts.silenceError) {
|
||||
return e.stdout.toString();
|
||||
} else {
|
||||
console.log(e.stdout.toString(), e.stderr.toString());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function runCommand(command: string): string {
|
||||
try {
|
||||
return execSync(command, {
|
||||
cwd: tmpProjPath(),
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
}).toString();
|
||||
} catch (e) {
|
||||
return e.stdout.toString() + e.stderr.toString();
|
||||
}
|
||||
}
|
||||
5
packages/nx-plugin/src/utils/testing-utils/index.ts
Normal file
5
packages/nx-plugin/src/utils/testing-utils/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export * from './async-commands';
|
||||
export * from './commands';
|
||||
export * from './paths';
|
||||
export * from './nx-project';
|
||||
export * from './utils';
|
||||
71
packages/nx-plugin/src/utils/testing-utils/nx-project.ts
Normal file
71
packages/nx-plugin/src/utils/testing-utils/nx-project.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { appRootPath } from '@nrwl/workspace/src/utils/app-root';
|
||||
import { execSync } from 'child_process';
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { ensureDirSync } from 'fs-extra';
|
||||
import { tmpProjPath } from './paths';
|
||||
import { cleanup, copyNodeModules } from './utils';
|
||||
|
||||
function runNxNewCommand(args?: string, silent?: boolean) {
|
||||
const localTmpDir = `./tmp/nx-e2e`;
|
||||
return execSync(
|
||||
`node ${require.resolve(
|
||||
'@nrwl/tao'
|
||||
)} new proj --no-interactive --skip-install --collection=@nrwl/workspace --npmScope=proj ${args ||
|
||||
''}`,
|
||||
{
|
||||
cwd: localTmpDir,
|
||||
...(silent && false ? { stdio: ['ignore', 'ignore', 'ignore'] } : {})
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function patchPackageJsonForPlugin(npmPackageName: string, distPath: string) {
|
||||
const p = JSON.parse(readFileSync(tmpProjPath('package.json')).toString());
|
||||
p.devDependencies[npmPackageName] = `file:${appRootPath}/${distPath}`;
|
||||
writeFileSync(tmpProjPath('package.json'), JSON.stringify(p, null, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique name for running CLI commands
|
||||
* @param prefix
|
||||
*/
|
||||
export function uniq(prefix: string) {
|
||||
return `${prefix}${Math.floor(Math.random() * 10000000)}`;
|
||||
}
|
||||
|
||||
export function runYarnInstall(silent: boolean = true) {
|
||||
const install = execSync('yarn install', {
|
||||
cwd: tmpProjPath(),
|
||||
...(silent ? { stdio: ['ignore', 'ignore', 'ignore'] } : {})
|
||||
});
|
||||
return install ? install.toString() : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a new project in the temporary project path
|
||||
* for the currently selected CLI.
|
||||
*/
|
||||
export function newNxProject(
|
||||
npmPackageName: string,
|
||||
pluginDistPath: string
|
||||
): void {
|
||||
cleanup();
|
||||
runNxNewCommand('', true);
|
||||
patchPackageJsonForPlugin(npmPackageName, pluginDistPath);
|
||||
runYarnInstall();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that a project has been setup
|
||||
* in the temporary project path
|
||||
*
|
||||
* If one is not found, it creates a new project.
|
||||
*/
|
||||
export function ensureNxProject(
|
||||
npmPackageName?: string,
|
||||
pluginDistPath?: string
|
||||
): void {
|
||||
ensureDirSync(tmpProjPath());
|
||||
newNxProject(npmPackageName, pluginDistPath);
|
||||
copyNodeModules(['@nrwl']);
|
||||
}
|
||||
11
packages/nx-plugin/src/utils/testing-utils/paths.ts
Normal file
11
packages/nx-plugin/src/utils/testing-utils/paths.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export function tmpProjPath(path?: string) {
|
||||
return path
|
||||
? `${process.cwd()}/tmp/nx-e2e/proj/${path}`
|
||||
: `${process.cwd()}/tmp/nx-e2e/proj`;
|
||||
}
|
||||
|
||||
export function tmpBackupProjPath(path?: string) {
|
||||
return path
|
||||
? `${process.cwd()}/tmp/nx-e2e/proj-backup/${path}`
|
||||
: `${process.cwd()}/tmp/nx-e2e/proj-backup`;
|
||||
}
|
||||
110
packages/nx-plugin/src/utils/testing-utils/utils.ts
Normal file
110
packages/nx-plugin/src/utils/testing-utils/utils.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import {
|
||||
ensureDirSync,
|
||||
readdirSync,
|
||||
readFileSync,
|
||||
removeSync,
|
||||
renameSync,
|
||||
statSync,
|
||||
writeFileSync,
|
||||
copySync
|
||||
} from 'fs-extra';
|
||||
import { dirname } from 'path';
|
||||
import { tmpProjPath } from './paths';
|
||||
|
||||
/**
|
||||
* Copies module folders from the working directory to the e2e directory
|
||||
* @param modules a list of module names or scopes to copy
|
||||
*/
|
||||
export function copyNodeModules(modules: string[]) {
|
||||
modules.forEach(module => {
|
||||
removeSync(`${tmpProjPath()}/node_modules/${module}`);
|
||||
copySync(
|
||||
`./node_modules/${module}`,
|
||||
`${tmpProjPath()}/node_modules/${module}`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert output from a asynchronous CLI command
|
||||
* @param output: Output from an asynchronous command
|
||||
*/
|
||||
export function expectTestsPass(v: { stdout: string; stderr: string }) {
|
||||
expect(v.stderr).toContain('Ran all test suites');
|
||||
expect(v.stderr).not.toContain('fail');
|
||||
}
|
||||
|
||||
export function updateFile(f: string, content: string | Function): void {
|
||||
ensureDirSync(dirname(tmpProjPath(f)));
|
||||
if (typeof content === 'string') {
|
||||
writeFileSync(tmpProjPath(f), content);
|
||||
} else {
|
||||
writeFileSync(
|
||||
tmpProjPath(f),
|
||||
content(readFileSync(tmpProjPath(f)).toString())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function renameFile(f: string, newPath: string): void {
|
||||
ensureDirSync(dirname(tmpProjPath(newPath)));
|
||||
renameSync(tmpProjPath(f), tmpProjPath(newPath));
|
||||
}
|
||||
|
||||
export function checkFilesExist(...expectedFiles: string[]) {
|
||||
expectedFiles.forEach(f => {
|
||||
const ff = f.startsWith('/') ? f : tmpProjPath(f);
|
||||
if (!exists(ff)) {
|
||||
throw new Error(`File '${ff}' does not exist`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function listFiles(dirName: string) {
|
||||
return readdirSync(tmpProjPath(dirName));
|
||||
}
|
||||
|
||||
export function readJson(f: string): any {
|
||||
return JSON.parse(readFile(f));
|
||||
}
|
||||
|
||||
export function readFile(f: string) {
|
||||
const ff = f.startsWith('/') ? f : tmpProjPath(f);
|
||||
return readFileSync(ff).toString();
|
||||
}
|
||||
|
||||
export function cleanup() {
|
||||
removeSync(tmpProjPath());
|
||||
}
|
||||
|
||||
export function rmDist() {
|
||||
removeSync(`${tmpProjPath()}/dist`);
|
||||
}
|
||||
|
||||
export function getCwd(): string {
|
||||
return process.cwd();
|
||||
}
|
||||
|
||||
export function directoryExists(filePath: string): boolean {
|
||||
try {
|
||||
return statSync(filePath).isDirectory();
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function fileExists(filePath: string): boolean {
|
||||
try {
|
||||
return statSync(filePath).isFile();
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function exists(filePath: string): boolean {
|
||||
return directoryExists(filePath) || fileExists(filePath);
|
||||
}
|
||||
|
||||
export function getSize(filePath: string): number {
|
||||
return statSync(filePath).size;
|
||||
}
|
||||
40
packages/nx-plugin/src/utils/testing.ts
Normal file
40
packages/nx-plugin/src/utils/testing.ts
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Testing file for internal schematics
|
||||
*/
|
||||
|
||||
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||
import { join } from 'path';
|
||||
import { Tree } from '@angular-devkit/schematics';
|
||||
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
|
||||
import { schema } from '@angular-devkit/core';
|
||||
import { Architect } from '@angular-devkit/architect';
|
||||
import { MockBuilderContext } from '@nrwl/workspace/testing';
|
||||
|
||||
const testRunner = new SchematicTestRunner(
|
||||
'@nrwl/nx-plugin',
|
||||
join(__dirname, '../../collection.json')
|
||||
);
|
||||
|
||||
export function runSchematic<T>(schematicName: string, options: T, tree: Tree) {
|
||||
return testRunner.runSchematicAsync(schematicName, options, tree).toPromise();
|
||||
}
|
||||
|
||||
export async function getTestArchitect() {
|
||||
const architectHost = new TestingArchitectHost('/root', '/root');
|
||||
const registry = new schema.CoreSchemaRegistry();
|
||||
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
|
||||
|
||||
const architect = new Architect(architectHost, registry);
|
||||
|
||||
await architectHost.addBuilderFromPackage(join(__dirname, '../..'));
|
||||
|
||||
return [architect, architectHost] as [Architect, TestingArchitectHost];
|
||||
}
|
||||
|
||||
export async function getMockContext() {
|
||||
const [architect, architectHost] = await getTestArchitect();
|
||||
|
||||
const context = new MockBuilderContext(architect, architectHost);
|
||||
await context.addBuilderFromPackage(join(__dirname, '../..'));
|
||||
return context;
|
||||
}
|
||||
1
packages/nx-plugin/src/utils/versions.ts
Normal file
1
packages/nx-plugin/src/utils/versions.ts
Normal file
@ -0,0 +1 @@
|
||||
export const nxVersion = '*';
|
||||
1
packages/nx-plugin/testing.ts
Normal file
1
packages/nx-plugin/testing.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './src/utils/testing-utils';
|
||||
@ -6,6 +6,7 @@ export {
|
||||
names,
|
||||
findModuleParent
|
||||
} from './src/utils/name-utils';
|
||||
export { ProjectType, projectRootDir } from './src/utils/project-type';
|
||||
export {
|
||||
serializeJson,
|
||||
renameSync,
|
||||
@ -42,7 +43,10 @@ export {
|
||||
getProjectGraphFromHost,
|
||||
readWorkspace,
|
||||
renameSyncInTree,
|
||||
renameDirSyncInTree
|
||||
renameDirSyncInTree,
|
||||
updateNxJsonInTree,
|
||||
addProjectToNxJsonInTree,
|
||||
readNxJsonInTree
|
||||
} from './src/utils/ast-utils';
|
||||
|
||||
export {
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
"@nrwl/nest",
|
||||
"@nrwl/next",
|
||||
"@nrwl/node",
|
||||
"@nrwl/nx-plugin",
|
||||
"@nrwl/react",
|
||||
"@nrwl/storybook",
|
||||
"@nrwl/web"
|
||||
|
||||
@ -20,6 +20,7 @@ import { toFileName, names } from '@nrwl/workspace';
|
||||
import { formatFiles } from '@nrwl/workspace';
|
||||
import { offsetFromRoot } from '@nrwl/workspace';
|
||||
import { generateProjectLint, addLintFiles } from '../../utils/lint';
|
||||
import { addProjectToNxJsonInTree } from '../../utils/ast-utils';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
@ -81,10 +82,7 @@ function createFiles(options: NormalizedSchema): Rule {
|
||||
}
|
||||
|
||||
function updateNxJson(options: NormalizedSchema): Rule {
|
||||
return updateJsonInTree<NxJson>('nx.json', json => {
|
||||
json.projects[options.name] = { tags: options.parsedTags };
|
||||
return json;
|
||||
});
|
||||
return addProjectToNxJsonInTree(options.name, { tags: options.parsedTags });
|
||||
}
|
||||
|
||||
export default function(schema: Schema): Rule {
|
||||
@ -117,6 +115,8 @@ function normalizeOptions(options: Schema): NormalizedSchema {
|
||||
|
||||
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
const fileName = options.simpleModuleName ? name : projectName;
|
||||
|
||||
// const projectRoot = `libs/${projectDirectory}`;
|
||||
const projectRoot = `libs/${projectDirectory}`;
|
||||
|
||||
const parsedTags = options.tags
|
||||
|
||||
@ -23,7 +23,10 @@ import {
|
||||
} from '../core/project-graph';
|
||||
import { FileData } from '../core/file-utils';
|
||||
import { extname, join, normalize, Path } from '@angular-devkit/core';
|
||||
import { NxJson } from '@nrwl/workspace/src/core/shared-interfaces';
|
||||
import {
|
||||
NxJson,
|
||||
NxJsonProjectConfig
|
||||
} from '@nrwl/workspace/src/core/shared-interfaces';
|
||||
|
||||
function nodesByPosition(first: ts.Node, second: ts.Node): number {
|
||||
return first.getStart() - second.getStart();
|
||||
@ -497,6 +500,35 @@ export function updateWorkspaceInTree<T = any, O = T>(
|
||||
};
|
||||
}
|
||||
|
||||
export function readNxJsonInTree(host: Tree) {
|
||||
return readJsonInTree<NxJson>(host, 'nx.json');
|
||||
}
|
||||
|
||||
export function updateNxJsonInTree(
|
||||
callback: (json: NxJson, context: SchematicContext) => NxJson
|
||||
): Rule {
|
||||
return (host: Tree, context: SchematicContext): Tree => {
|
||||
host.overwrite(
|
||||
'nx.json',
|
||||
serializeJson(callback(readJsonInTree(host, 'nx.json'), context))
|
||||
);
|
||||
return host;
|
||||
};
|
||||
}
|
||||
|
||||
export function addProjectToNxJsonInTree(
|
||||
projectName: string,
|
||||
options: NxJsonProjectConfig
|
||||
): Rule {
|
||||
const defaultOptions = {
|
||||
tags: []
|
||||
};
|
||||
return updateNxJsonInTree(json => {
|
||||
json.projects[projectName] = { ...defaultOptions, ...options };
|
||||
return json;
|
||||
});
|
||||
}
|
||||
|
||||
export function readWorkspace(host: Tree): any {
|
||||
const path = getWorkspacePath(host);
|
||||
return readJsonInTree(host, path);
|
||||
|
||||
12
packages/workspace/src/utils/project-type.ts
Normal file
12
packages/workspace/src/utils/project-type.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export enum ProjectType {
|
||||
Application = 'application',
|
||||
Library = 'library'
|
||||
}
|
||||
|
||||
export function projectRootDir(projectType: ProjectType) {
|
||||
if (projectType == ProjectType.Application) {
|
||||
return 'apps';
|
||||
} else if (projectType == ProjectType.Library) {
|
||||
return 'libs';
|
||||
}
|
||||
}
|
||||
@ -29,6 +29,7 @@ rm -rf build/packages/angular/bundles/nrwl-angular-testing.umd.min.js.bak
|
||||
|
||||
rsync -a --exclude=*.ts packages/ build/packages
|
||||
chmod +x build/packages/create-nx-workspace/bin/create-nx-workspace.js
|
||||
chmod +x build/packages/nx-plugin/bin/create.js
|
||||
chmod +x build/packages/cli/bin/nx.js
|
||||
chmod +x build/packages/tao/index.js
|
||||
|
||||
@ -58,6 +59,7 @@ cp README.md build/packages/tao
|
||||
cp README.md build/packages/eslint-plugin-nx
|
||||
cp README.md build/packages/linter
|
||||
cp README.md build/packages/bazel
|
||||
cp README.md build/packages/nx-plugin
|
||||
|
||||
cp LICENSE build/packages/builders
|
||||
cp LICENSE build/packages/schematics
|
||||
@ -79,6 +81,7 @@ cp LICENSE build/packages/tao
|
||||
cp LICENSE build/packages/eslint-plugin-nx
|
||||
cp LICENSE build/packages/linter
|
||||
cp LICENSE build/packages/bazel
|
||||
cp LICENSE build/packages/nx-plugin
|
||||
|
||||
echo "Nx libraries available at build/packages:"
|
||||
ls build/packages
|
||||
|
||||
@ -6,7 +6,7 @@ const gitMessage = require('child_process')
|
||||
.toString()
|
||||
.trim();
|
||||
|
||||
const matchCommit = /(chore|feat|fix|cleanup|docs)\((angular|bazel|core|docs|nextjs|node|react|storybook|testing|repo|misc)\):\s(([a-z0-9:\-\s])+)/g.test(
|
||||
const matchCommit = /(chore|feat|fix|cleanup|docs)\((angular|bazel|core|docs|nextjs|node|nx-plugin|react|storybook|testing|repo|misc)\):\s(([a-z0-9:\-\s])+)/g.test(
|
||||
gitMessage
|
||||
);
|
||||
const matchRevert = /Revert/gi.test(gitMessage);
|
||||
|
||||
@ -12,6 +12,7 @@ export SELECTED_CLI=$1
|
||||
jest --maxWorkers=1 ./build/e2e/ng-add.test.js &&
|
||||
jest --maxWorkers=1 ./build/e2e/ngrx.test.js &&
|
||||
jest --maxWorkers=1 ./build/e2e/node.test.js &&
|
||||
jest --maxWorkers=1 ./build/e2e/nx-plugin.test.js &&
|
||||
jest --maxWorkers=1 ./build/e2e/print-affected.test.js &&
|
||||
jest --maxWorkers=1 ./build/e2e/react.test.js &&
|
||||
jest --maxWorkers=1 ./build/e2e/report.test.js &&
|
||||
|
||||
@ -165,7 +165,8 @@ const options = {
|
||||
'build/npm/cli/package.json',
|
||||
'build/npm/tao/package.json',
|
||||
'build/npm/eslint-plugin-nx/package.json',
|
||||
'build/npm/linter/package.json'
|
||||
'build/npm/linter/package.json',
|
||||
'build/npm/nx-plugin/package.json'
|
||||
],
|
||||
increment: parsedVersion.version,
|
||||
requireUpstream: false,
|
||||
|
||||
@ -18,25 +18,33 @@ cd build/packages
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i "" "s|exports.nxVersion = '\*';|exports.nxVersion = '$NX_VERSION';|g" {react,next,web,jest,node,express,nest,cypress,storybook,angular,workspace}/src/utils/versions.js
|
||||
sed -i "" "s|\*|$NX_VERSION|g" {schematics,react,next,web,jest,node,express,nest,cypress,storybook,angular,workspace,cli,linter,bazel,tao,eslint-plugin-nx,create-nx-workspace}/package.json
|
||||
sed -i "" "s|\*|$NX_VERSION|g" {schematics,react,next,web,jest,node,express,nest,cypress,storybook,angular,workspace,cli,linter,bazel,tao,eslint-plugin-nx,create-nx-workspace,nx-plugin}/package.json
|
||||
sed -i "" "s|NX_VERSION|$NX_VERSION|g" create-nx-workspace/bin/create-nx-workspace.js
|
||||
sed -i "" "s|ANGULAR_CLI_VERSION|$ANGULAR_CLI_VERSION|g" create-nx-workspace/bin/create-nx-workspace.js
|
||||
sed -i "" "s|TYPESCRIPT_VERSION|$TYPESCRIPT_VERSION|g" create-nx-workspace/bin/create-nx-workspace.js
|
||||
sed -i "" "s|PRETTIER_VERSION|$PRETTIER_VERSION|g" create-nx-workspace/bin/create-nx-workspace.js
|
||||
sed -i "" "s|NX_VERSION|$NX_VERSION|g" nx-plugin/bin/create.js
|
||||
sed -i "" "s|ANGULAR_CLI_VERSION|$ANGULAR_CLI_VERSION|g" nx-plugin/bin/create.js
|
||||
sed -i "" "s|TYPESCRIPT_VERSION|$TYPESCRIPT_VERSION|g" nx-plugin/bin/create.js
|
||||
sed -i "" "s|PRETTIER_VERSION|$PRETTIER_VERSION|g" nx-plugin/bin/create.js
|
||||
else
|
||||
sed -i "s|exports.nxVersion = '\*';|exports.nxVersion = '$NX_VERSION';|g" {react,next,web,jest,node,express,nest,cypress,storybook,angular,workspace}/src/utils/versions.js
|
||||
sed -i "s|\*|$NX_VERSION|g" {schematics,react,next,web,jest,node,express,nest,cypress,storybook,angular,workspace,cli,linter,bazel,tao,eslint-plugin-nx,create-nx-workspace}/package.json
|
||||
sed -i "s|\*|$NX_VERSION|g" {schematics,react,next,web,jest,node,express,nest,cypress,storybook,angular,workspace,cli,linter,bazel,tao,eslint-plugin-nx,create-nx-workspace,nx-plugin}/package.json
|
||||
sed -i "s|NX_VERSION|$NX_VERSION|g" create-nx-workspace/bin/create-nx-workspace.js
|
||||
sed -i "s|ANGULAR_CLI_VERSION|$ANGULAR_CLI_VERSION|g" create-nx-workspace/bin/create-nx-workspace.js
|
||||
sed -i "s|TYPESCRIPT_VERSION|$TYPESCRIPT_VERSION|g" create-nx-workspace/bin/create-nx-workspace.js
|
||||
sed -i "s|PRETTIER_VERSION|$PRETTIER_VERSION|g" create-nx-workspace/bin/create-nx-workspace.js
|
||||
sed -i "s|NX_VERSION|$NX_VERSION|g" nx-plugin/bin/create.js
|
||||
sed -i "s|ANGULAR_CLI_VERSION|$ANGULAR_CLI_VERSION|g" nx-plugin/bin/create.js
|
||||
sed -i "s|TYPESCRIPT_VERSION|$TYPESCRIPT_VERSION|g" nx-plugin/bin/create.js
|
||||
sed -i "s|PRETTIER_VERSION|$PRETTIER_VERSION|g" nx-plugin/bin/create.js
|
||||
fi
|
||||
|
||||
if [[ $NX_VERSION == "*" ]]; then
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -E -i "" "s|\"@nrwl\/([^\"]+)\": \"\\*\"|\"@nrwl\/\1\": \"file:$PWD\/\1\"|" {schematics,jest,web,react,next,node,express,nest,cypress,storybook,angular,workspace,linter,bazel,cli,tao,eslint-plugin-nx,create-nx-workspace}/package.json
|
||||
sed -E -i "" "s|\"@nrwl\/([^\"]+)\": \"\\*\"|\"@nrwl\/\1\": \"file:$PWD\/\1\"|" {schematics,jest,web,react,next,node,express,nest,cypress,storybook,angular,workspace,linter,bazel,cli,tao,eslint-plugin-nx,create-nx-workspace,nx-plugin}/package.json
|
||||
else
|
||||
echo $PWD
|
||||
sed -E -i "s|\"@nrwl\/([^\"]+)\": \"\\*\"|\"@nrwl\/\1\": \"file:$PWD\/\1\"|" {schematics,jest,web,react,next,node,express,nest,cypress,storybook,angular,workspace,linter,bazel,cli,tao,eslint-plugin-nx,create-nx-workspace}/package.json
|
||||
sed -E -i "s|\"@nrwl\/([^\"]+)\": \"\\*\"|\"@nrwl\/\1\": \"file:$PWD\/\1\"|" {schematics,jest,web,react,next,node,express,nest,cypress,storybook,angular,workspace,linter,bazel,cli,tao,eslint-plugin-nx,create-nx-workspace,nx-plugin}/package.json
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -3,5 +3,5 @@
|
||||
if [ -n "$1" ]; then
|
||||
jest --maxWorkers=1 ./build/packages/$1.spec.js
|
||||
else
|
||||
jest --maxWorkers=1 ./build/packages/{schematics,bazel,builders,react,jest,web,node,express,nest,cypress,storybook,angular,workspace,tao,eslint-plugin-nx,next} --passWithNoTests
|
||||
jest --maxWorkers=1 ./build/packages/{schematics,bazel,builders,react,jest,web,node,express,nest,cypress,storybook,angular,workspace,tao,eslint-plugin-nx,next,nx-plugin} --passWithNoTests
|
||||
fi
|
||||
|
||||
@ -4167,6 +4167,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/fast-levenshtein/-/fast-levenshtein-0.0.1.tgz#3a3615cf173645c8fca58d051e4e32824e4bd286"
|
||||
integrity sha1-OjYVzxc2Rcj8pY0FHk4ygk5L0oY=
|
||||
|
||||
"@types/fs-extra@7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-7.0.0.tgz#9c4ad9e1339e7448a76698829def1f159c1b636c"
|
||||
integrity sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/glob@^7.1.1":
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user