feat(core): migrate create-nx-workspace to devkit
This commit is contained in:
parent
764f580e99
commit
09c78c4750
@ -11,6 +11,7 @@ export {
|
|||||||
NxJsonProjectConfiguration,
|
NxJsonProjectConfiguration,
|
||||||
} from '@nrwl/tao/src/shared/nx';
|
} from '@nrwl/tao/src/shared/nx';
|
||||||
export { logger } from '@nrwl/tao/src/shared/logger';
|
export { logger } from '@nrwl/tao/src/shared/logger';
|
||||||
|
export { getPackageManagerCommand } from '@nrwl/tao/src/shared/package-manager';
|
||||||
export { TargetContext } from '@nrwl/tao/src/commands/run';
|
export { TargetContext } from '@nrwl/tao/src/commands/run';
|
||||||
|
|
||||||
export { formatFiles } from './src/generators/format-files';
|
export { formatFiles } from './src/generators/format-files';
|
||||||
@ -25,7 +26,10 @@ export { readJson, writeJson, updateJson } from './src/utils/json';
|
|||||||
export { addDependenciesToPackageJson } from './src/utils/package-json';
|
export { addDependenciesToPackageJson } from './src/utils/package-json';
|
||||||
export { installPackagesTask } from './src/tasks/install-packages-task';
|
export { installPackagesTask } from './src/tasks/install-packages-task';
|
||||||
export { names } from './src/utils/names';
|
export { names } from './src/utils/names';
|
||||||
export { getWorkspaceLayout } from './src/utils/get-workspace-layout';
|
export {
|
||||||
|
getWorkspaceLayout,
|
||||||
|
getWorkspacePath,
|
||||||
|
} from './src/utils/get-workspace-layout';
|
||||||
export {
|
export {
|
||||||
applyChangesToString,
|
applyChangesToString,
|
||||||
ChangeType,
|
ChangeType,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { Tree } from '@nrwl/tao/src/shared/tree';
|
import { Tree } from '@nrwl/tao/src/shared/tree';
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import { getPackageManagerCommand } from '@nrwl/tao/src/shared/package-manager';
|
import { getPackageManagerCommand } from '@nrwl/tao/src/shared/package-manager';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
let storedPackageJsonValue;
|
let storedPackageJsonValue;
|
||||||
|
|
||||||
@ -11,14 +12,21 @@ let storedPackageJsonValue;
|
|||||||
* @param host - the file system tree
|
* @param host - the file system tree
|
||||||
* @param alwaysRun - always run the command even if `package.json` hasn't changed.
|
* @param alwaysRun - always run the command even if `package.json` hasn't changed.
|
||||||
*/
|
*/
|
||||||
export function installPackagesTask(host: Tree, alwaysRun: boolean = false) {
|
export function installPackagesTask(
|
||||||
const packageJsonValue = host.read('package.json').toString();
|
host: Tree,
|
||||||
if (host.listChanges().find((f) => f.path === 'package.json') || alwaysRun) {
|
alwaysRun: boolean = false,
|
||||||
|
cwd: string = ''
|
||||||
|
) {
|
||||||
|
const packageJsonValue = host.read(join(cwd, 'package.json')).toString();
|
||||||
|
if (
|
||||||
|
host.listChanges().find((f) => f.path === join(cwd, 'package.json')) ||
|
||||||
|
alwaysRun
|
||||||
|
) {
|
||||||
if (storedPackageJsonValue != packageJsonValue || alwaysRun) {
|
if (storedPackageJsonValue != packageJsonValue || alwaysRun) {
|
||||||
storedPackageJsonValue = host.read('package.json').toString();
|
storedPackageJsonValue = host.read(join(cwd, 'package.json')).toString();
|
||||||
const pmc = getPackageManagerCommand();
|
const pmc = getPackageManagerCommand();
|
||||||
execSync(pmc.install, {
|
execSync(pmc.install, {
|
||||||
cwd: host.root,
|
cwd: join(host.root, cwd),
|
||||||
stdio: [0, 1, 2],
|
stdio: [0, 1, 2],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -179,7 +179,23 @@ export async function taoNew(cwd: string, args: string[], isVerbose = false) {
|
|||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
return (await import('./ngcli-adapter')).invokeNew(
|
|
||||||
|
if (ws.isNxGenerator(opts.collectionName, normalizedGeneratorName)) {
|
||||||
|
const host = new FsTree(cwd, isVerbose);
|
||||||
|
const task = await implementation(host, combinedOpts);
|
||||||
|
const changes = host.listChanges();
|
||||||
|
|
||||||
|
printChanges(changes);
|
||||||
|
if (!opts.dryRun) {
|
||||||
|
flushChanges(cwd, changes);
|
||||||
|
if (task) {
|
||||||
|
await task();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warn(`\nNOTE: The "dryRun" flag means no changes were made.`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (await import('./ngcli-adapter')).generate(
|
||||||
cwd,
|
cwd,
|
||||||
{
|
{
|
||||||
...opts,
|
...opts,
|
||||||
@ -187,6 +203,7 @@ export async function taoNew(cwd: string, args: string[], isVerbose = false) {
|
|||||||
},
|
},
|
||||||
isVerbose
|
isVerbose
|
||||||
);
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -95,6 +95,42 @@ describe('tree', () => {
|
|||||||
).toEqual('new child content');
|
).toEqual('new child content');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should normalize paths', () => {
|
||||||
|
tree.write('dir/file1', 'File 1 Contents');
|
||||||
|
tree.write('/dir/file2', 'File 2 Contents');
|
||||||
|
tree.write('./dir/file3', 'File 3 Contents');
|
||||||
|
|
||||||
|
expect(tree.read('dir/file1').toString()).toEqual('File 1 Contents');
|
||||||
|
expect(tree.read('/dir/file1').toString()).toEqual('File 1 Contents');
|
||||||
|
expect(tree.read('./dir/file1').toString()).toEqual('File 1 Contents');
|
||||||
|
|
||||||
|
expect(tree.read('dir/file2').toString()).toEqual('File 2 Contents');
|
||||||
|
expect(tree.read('/dir/file2').toString()).toEqual('File 2 Contents');
|
||||||
|
expect(tree.read('./dir/file2').toString()).toEqual('File 2 Contents');
|
||||||
|
|
||||||
|
expect(tree.read('dir/file3').toString()).toEqual('File 3 Contents');
|
||||||
|
expect(tree.read('/dir/file3').toString()).toEqual('File 3 Contents');
|
||||||
|
expect(tree.read('./dir/file3').toString()).toEqual('File 3 Contents');
|
||||||
|
|
||||||
|
tree.rename('dir/file1', 'dir/file-a');
|
||||||
|
|
||||||
|
expect(tree.read('dir/file-a').toString()).toEqual('File 1 Contents');
|
||||||
|
expect(tree.read('/dir/file-a').toString()).toEqual('File 1 Contents');
|
||||||
|
expect(tree.read('./dir/file-a').toString()).toEqual('File 1 Contents');
|
||||||
|
|
||||||
|
tree.rename('/dir/file2', '/dir/file-b');
|
||||||
|
|
||||||
|
expect(tree.read('dir/file-b').toString()).toEqual('File 2 Contents');
|
||||||
|
expect(tree.read('/dir/file-b').toString()).toEqual('File 2 Contents');
|
||||||
|
expect(tree.read('./dir/file-b').toString()).toEqual('File 2 Contents');
|
||||||
|
|
||||||
|
tree.rename('./dir/file3', './dir/file-c');
|
||||||
|
|
||||||
|
expect(tree.read('dir/file-c').toString()).toEqual('File 3 Contents');
|
||||||
|
expect(tree.read('/dir/file-c').toString()).toEqual('File 3 Contents');
|
||||||
|
expect(tree.read('./dir/file-c').toString()).toEqual('File 3 Contents');
|
||||||
|
});
|
||||||
|
|
||||||
it('should be able to delete files', () => {
|
it('should be able to delete files', () => {
|
||||||
tree.delete('parent/parent-file.txt');
|
tree.delete('parent/parent-file.txt');
|
||||||
tree.write('parent/new-child/new-child-file.txt', 'new child content');
|
tree.write('parent/new-child/new-child-file.txt', 'new child content');
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import * as path from 'path';
|
|
||||||
import {
|
import {
|
||||||
readdirSync,
|
readdirSync,
|
||||||
readFileSync,
|
readFileSync,
|
||||||
@ -8,6 +7,7 @@ import {
|
|||||||
} from 'fs';
|
} from 'fs';
|
||||||
import { mkdirpSync, rmdirSync } from 'fs-extra';
|
import { mkdirpSync, rmdirSync } from 'fs-extra';
|
||||||
import { logger } from './logger';
|
import { logger } from './logger';
|
||||||
|
import { dirname, join, relative } from 'path';
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,6 +88,7 @@ export class FsTree implements Tree {
|
|||||||
constructor(readonly root: string, private readonly isVerbose: boolean) {}
|
constructor(readonly root: string, private readonly isVerbose: boolean) {}
|
||||||
|
|
||||||
read(filePath: string): Buffer | null {
|
read(filePath: string): Buffer | null {
|
||||||
|
filePath = this.normalize(filePath);
|
||||||
try {
|
try {
|
||||||
if (this.recordedChanges[this.rp(filePath)]) {
|
if (this.recordedChanges[this.rp(filePath)]) {
|
||||||
return this.recordedChanges[this.rp(filePath)].content;
|
return this.recordedChanges[this.rp(filePath)].content;
|
||||||
@ -103,6 +104,7 @@ export class FsTree implements Tree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
write(filePath: string, content: Buffer | string): void {
|
write(filePath: string, content: Buffer | string): void {
|
||||||
|
filePath = this.normalize(filePath);
|
||||||
try {
|
try {
|
||||||
this.recordedChanges[this.rp(filePath)] = {
|
this.recordedChanges[this.rp(filePath)] = {
|
||||||
content: Buffer.from(content),
|
content: Buffer.from(content),
|
||||||
@ -116,10 +118,12 @@ export class FsTree implements Tree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
overwrite(filePath: string, content: Buffer | string): void {
|
overwrite(filePath: string, content: Buffer | string): void {
|
||||||
|
filePath = this.normalize(filePath);
|
||||||
this.write(filePath, content);
|
this.write(filePath, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
exists(filePath: string): boolean {
|
exists(filePath: string): boolean {
|
||||||
|
filePath = this.normalize(filePath);
|
||||||
try {
|
try {
|
||||||
if (this.recordedChanges[this.rp(filePath)]) {
|
if (this.recordedChanges[this.rp(filePath)]) {
|
||||||
return !this.recordedChanges[this.rp(filePath)].isDeleted;
|
return !this.recordedChanges[this.rp(filePath)].isDeleted;
|
||||||
@ -134,6 +138,7 @@ export class FsTree implements Tree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete(filePath: string): void {
|
delete(filePath: string): void {
|
||||||
|
filePath = this.normalize(filePath);
|
||||||
if (this.filesForDir(this.rp(filePath)).length > 0) {
|
if (this.filesForDir(this.rp(filePath)).length > 0) {
|
||||||
this.filesForDir(this.rp(filePath)).forEach(
|
this.filesForDir(this.rp(filePath)).forEach(
|
||||||
(f) => (this.recordedChanges[f] = { content: null, isDeleted: true })
|
(f) => (this.recordedChanges[f] = { content: null, isDeleted: true })
|
||||||
@ -146,12 +151,15 @@ export class FsTree implements Tree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rename(from: string, to: string): void {
|
rename(from: string, to: string): void {
|
||||||
|
from = this.normalize(from);
|
||||||
|
to = this.normalize(to);
|
||||||
const content = this.read(this.rp(from));
|
const content = this.read(this.rp(from));
|
||||||
this.recordedChanges[this.rp(from)] = { content: null, isDeleted: true };
|
this.recordedChanges[this.rp(from)] = { content: null, isDeleted: true };
|
||||||
this.recordedChanges[this.rp(to)] = { content: content, isDeleted: false };
|
this.recordedChanges[this.rp(to)] = { content: content, isDeleted: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
isFile(filePath: string): boolean {
|
isFile(filePath: string): boolean {
|
||||||
|
filePath = this.normalize(filePath);
|
||||||
try {
|
try {
|
||||||
if (this.recordedChanges[this.rp(filePath)]) {
|
if (this.recordedChanges[this.rp(filePath)]) {
|
||||||
return !this.recordedChanges[this.rp(filePath)].isDeleted;
|
return !this.recordedChanges[this.rp(filePath)].isDeleted;
|
||||||
@ -164,11 +172,12 @@ export class FsTree implements Tree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
children(dirPath: string): string[] {
|
children(dirPath: string): string[] {
|
||||||
|
dirPath = this.normalize(dirPath);
|
||||||
let res = this.fsReadDir(dirPath);
|
let res = this.fsReadDir(dirPath);
|
||||||
|
|
||||||
res = [...res, ...this.directChildrenOfDir(this.rp(dirPath))];
|
res = [...res, ...this.directChildrenOfDir(this.rp(dirPath))];
|
||||||
return res.filter((q) => {
|
return res.filter((q) => {
|
||||||
const r = this.recordedChanges[path.join(this.rp(dirPath), q)];
|
const r = this.recordedChanges[join(this.rp(dirPath), q)];
|
||||||
if (r && r.isDeleted) return false;
|
if (r && r.isDeleted) return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@ -200,10 +209,14 @@ export class FsTree implements Tree {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private normalize(path: string) {
|
||||||
|
return relative(this.root, join(this.root, path));
|
||||||
|
}
|
||||||
|
|
||||||
private fsReadDir(dirPath: string) {
|
private fsReadDir(dirPath: string) {
|
||||||
if (!this.delegateToFs) return [];
|
if (!this.delegateToFs) return [];
|
||||||
try {
|
try {
|
||||||
return readdirSync(path.join(this.root, dirPath));
|
return readdirSync(join(this.root, dirPath));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -211,19 +224,19 @@ export class FsTree implements Tree {
|
|||||||
|
|
||||||
private fsIsFile(filePath: string) {
|
private fsIsFile(filePath: string) {
|
||||||
if (!this.delegateToFs) return false;
|
if (!this.delegateToFs) return false;
|
||||||
const stat = statSync(path.join(this.root, filePath));
|
const stat = statSync(join(this.root, filePath));
|
||||||
return stat.isFile();
|
return stat.isFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
private fsReadFile(filePath: string) {
|
private fsReadFile(filePath: string) {
|
||||||
if (!this.delegateToFs) return null;
|
if (!this.delegateToFs) return null;
|
||||||
return readFileSync(path.join(this.root, filePath));
|
return readFileSync(join(this.root, filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
private fsExists(filePath: string): boolean {
|
private fsExists(filePath: string): boolean {
|
||||||
if (!this.delegateToFs) return false;
|
if (!this.delegateToFs) return false;
|
||||||
try {
|
try {
|
||||||
const stat = statSync(path.join(this.root, filePath));
|
const stat = statSync(join(this.root, filePath));
|
||||||
return stat.isFile() || stat.isDirectory();
|
return stat.isFile() || stat.isDirectory();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
@ -258,9 +271,9 @@ export class FsTree implements Tree {
|
|||||||
|
|
||||||
export function flushChanges(root: string, fileChanges: FileChange[]) {
|
export function flushChanges(root: string, fileChanges: FileChange[]) {
|
||||||
fileChanges.forEach((f) => {
|
fileChanges.forEach((f) => {
|
||||||
const fpath = path.join(root, f.path);
|
const fpath = join(root, f.path);
|
||||||
if (f.type === 'CREATE') {
|
if (f.type === 'CREATE') {
|
||||||
mkdirpSync(path.dirname(fpath));
|
mkdirpSync(dirname(fpath));
|
||||||
writeFileSync(fpath, f.content);
|
writeFileSync(fpath, f.content);
|
||||||
} else if (f.type === 'UPDATE') {
|
} else if (f.type === 'UPDATE') {
|
||||||
writeFileSync(fpath, f.content);
|
writeFileSync(fpath, f.content);
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"version": "0.1",
|
"version": "0.1",
|
||||||
"schematics": {
|
"schematics": {
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"factory": "./src/schematics/workspace/workspace",
|
"factory": "./src/schematics/workspace/workspace#workspaceSchematic",
|
||||||
"schema": "./src/schematics/workspace/schema.json",
|
"schema": "./src/schematics/workspace/schema.json",
|
||||||
"description": "Create an empty workspace",
|
"description": "Create an empty workspace",
|
||||||
"hidden": true
|
"hidden": true
|
||||||
@ -38,7 +38,71 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"new": {
|
"new": {
|
||||||
"factory": "./src/schematics/new/new",
|
"factory": "./src/schematics/new/new#newSchematic",
|
||||||
|
"schema": "./src/schematics/new/schema.json",
|
||||||
|
"description": "Create a workspace",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"library": {
|
||||||
|
"factory": "./src/schematics/library/library",
|
||||||
|
"schema": "./src/schematics/library/schema.json",
|
||||||
|
"aliases": ["lib"],
|
||||||
|
"description": "Create a library"
|
||||||
|
},
|
||||||
|
|
||||||
|
"workspace-generator": {
|
||||||
|
"factory": "./src/schematics/workspace-generator/workspace-generator",
|
||||||
|
"schema": "./src/schematics/workspace-generator/schema.json",
|
||||||
|
"aliases": ["workspace-schematic"],
|
||||||
|
"description": "Generates a workspace generator"
|
||||||
|
},
|
||||||
|
|
||||||
|
"run-commands": {
|
||||||
|
"factory": "./src/schematics/run-commands/run-commands",
|
||||||
|
"schema": "./src/schematics/run-commands/schema.json",
|
||||||
|
"aliases": ["run-command", "target"],
|
||||||
|
"description": "Generates a target to run any command in the terminal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"generators": {
|
||||||
|
"workspace": {
|
||||||
|
"factory": "./src/schematics/workspace/workspace#workspaceGenerator",
|
||||||
|
"schema": "./src/schematics/workspace/schema.json",
|
||||||
|
"description": "Create an empty workspace",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"ng-add": {
|
||||||
|
"factory": "./src/schematics/init/init",
|
||||||
|
"schema": "./src/schematics/init/schema.json",
|
||||||
|
"description": "Convert an existing CLI project into an Nx Workspace",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"preset": {
|
||||||
|
"factory": "./src/schematics/preset/preset",
|
||||||
|
"schema": "./src/schematics/preset/schema.json",
|
||||||
|
"description": "Create application in an empty workspace",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"move": {
|
||||||
|
"factory": "./src/schematics/move/move",
|
||||||
|
"schema": "./src/schematics/move/schema.json",
|
||||||
|
"aliases": ["mv"],
|
||||||
|
"description": "Move an application or library to another folder"
|
||||||
|
},
|
||||||
|
|
||||||
|
"remove": {
|
||||||
|
"factory": "./src/schematics/remove/remove",
|
||||||
|
"schema": "./src/schematics/remove/schema.json",
|
||||||
|
"aliases": ["rm"],
|
||||||
|
"description": "Remove an application or library"
|
||||||
|
},
|
||||||
|
|
||||||
|
"new": {
|
||||||
|
"factory": "./src/schematics/new/new#newGenerator",
|
||||||
"schema": "./src/schematics/new/schema.json",
|
"schema": "./src/schematics/new/schema.json",
|
||||||
"description": "Create a workspace",
|
"description": "Create a workspace",
|
||||||
"hidden": true
|
"hidden": true
|
||||||
|
|||||||
@ -0,0 +1,383 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`new --preset angular should generate an empty nx.json 1`] = `
|
||||||
|
Object {
|
||||||
|
"affected": Object {
|
||||||
|
"defaultBase": "master",
|
||||||
|
},
|
||||||
|
"implicitDependencies": Object {
|
||||||
|
".eslintrc.json": "*",
|
||||||
|
"nx.json": "*",
|
||||||
|
"package.json": Object {
|
||||||
|
"dependencies": "*",
|
||||||
|
"devDependencies": "*",
|
||||||
|
},
|
||||||
|
"tsconfig.base.json": "*",
|
||||||
|
"tslint.json": "*",
|
||||||
|
"workspace.json": "*",
|
||||||
|
},
|
||||||
|
"npmScope": "npmScope",
|
||||||
|
"projects": Object {},
|
||||||
|
"tasksRunnerOptions": Object {
|
||||||
|
"default": Object {
|
||||||
|
"options": Object {
|
||||||
|
"cacheableOperations": Array [
|
||||||
|
"build",
|
||||||
|
"lint",
|
||||||
|
"test",
|
||||||
|
"e2e",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"runner": "@nrwl/workspace/tasks-runners/default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new --preset angular should generate an empty workspace.json 1`] = `
|
||||||
|
Object {
|
||||||
|
"cli": Object {
|
||||||
|
"defaultCollection": "@nrwl/workspace",
|
||||||
|
},
|
||||||
|
"generators": Object {
|
||||||
|
"@nrwl/angular": Object {
|
||||||
|
"application": Object {
|
||||||
|
"linter": "eslint",
|
||||||
|
},
|
||||||
|
"library": Object {
|
||||||
|
"linter": "eslint",
|
||||||
|
},
|
||||||
|
"storybook-configuration": Object {
|
||||||
|
"linter": "eslint",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"projects": Object {},
|
||||||
|
"version": 2,
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new --preset angular should generate necessary npm dependencies 1`] = `
|
||||||
|
Object {
|
||||||
|
"dependencies": Object {
|
||||||
|
"@nrwl/angular": "*",
|
||||||
|
},
|
||||||
|
"devDependencies": Object {
|
||||||
|
"@nrwl/cli": "*",
|
||||||
|
"@nrwl/tao": "*",
|
||||||
|
"@nrwl/workspace": "*",
|
||||||
|
"@types/node": "12.12.38",
|
||||||
|
"dotenv": "6.2.0",
|
||||||
|
"eslint": "7.10.0",
|
||||||
|
"prettier": "2.1.2",
|
||||||
|
"ts-node": "~9.1.1",
|
||||||
|
"tslint": "~6.1.0",
|
||||||
|
"typescript": "~4.0.3",
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"name": "my-workspace",
|
||||||
|
"private": true,
|
||||||
|
"scripts": Object {
|
||||||
|
"affected": "nx affected",
|
||||||
|
"affected:apps": "nx affected:apps",
|
||||||
|
"affected:build": "nx affected:build",
|
||||||
|
"affected:dep-graph": "nx affected:dep-graph",
|
||||||
|
"affected:e2e": "nx affected:e2e",
|
||||||
|
"affected:libs": "nx affected:libs",
|
||||||
|
"affected:lint": "nx affected:lint",
|
||||||
|
"affected:test": "nx affected:test",
|
||||||
|
"build": "nx build",
|
||||||
|
"dep-graph": "nx dep-graph",
|
||||||
|
"e2e": "nx e2e",
|
||||||
|
"format": "nx format:write",
|
||||||
|
"format:check": "nx format:check",
|
||||||
|
"format:write": "nx format:write",
|
||||||
|
"help": "nx help",
|
||||||
|
"lint": "nx workspace-lint && nx lint",
|
||||||
|
"nx": "nx",
|
||||||
|
"start": "nx serve",
|
||||||
|
"test": "nx test",
|
||||||
|
"update": "nx migrate latest",
|
||||||
|
"workspace-generator": "nx workspace-generator",
|
||||||
|
},
|
||||||
|
"version": "0.0.0",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new --preset empty should generate an empty nx.json 1`] = `
|
||||||
|
Object {
|
||||||
|
"affected": Object {
|
||||||
|
"defaultBase": "master",
|
||||||
|
},
|
||||||
|
"implicitDependencies": Object {
|
||||||
|
".eslintrc.json": "*",
|
||||||
|
"nx.json": "*",
|
||||||
|
"package.json": Object {
|
||||||
|
"dependencies": "*",
|
||||||
|
"devDependencies": "*",
|
||||||
|
},
|
||||||
|
"tsconfig.base.json": "*",
|
||||||
|
"tslint.json": "*",
|
||||||
|
"workspace.json": "*",
|
||||||
|
},
|
||||||
|
"npmScope": "npmScope",
|
||||||
|
"projects": Object {},
|
||||||
|
"tasksRunnerOptions": Object {
|
||||||
|
"default": Object {
|
||||||
|
"options": Object {
|
||||||
|
"cacheableOperations": Array [
|
||||||
|
"build",
|
||||||
|
"lint",
|
||||||
|
"test",
|
||||||
|
"e2e",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"runner": "@nrwl/workspace/tasks-runners/default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new --preset empty should generate an empty workspace.json 1`] = `
|
||||||
|
Object {
|
||||||
|
"cli": Object {
|
||||||
|
"defaultCollection": "@nrwl/workspace",
|
||||||
|
},
|
||||||
|
"projects": Object {},
|
||||||
|
"version": 2,
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new --preset empty should generate an necessary npm dependencies 1`] = `
|
||||||
|
Object {
|
||||||
|
"dependencies": Object {},
|
||||||
|
"devDependencies": Object {
|
||||||
|
"@nrwl/cli": "*",
|
||||||
|
"@nrwl/tao": "*",
|
||||||
|
"@nrwl/workspace": "*",
|
||||||
|
"@types/node": "12.12.38",
|
||||||
|
"dotenv": "6.2.0",
|
||||||
|
"eslint": "7.10.0",
|
||||||
|
"prettier": "2.1.2",
|
||||||
|
"ts-node": "~9.1.1",
|
||||||
|
"tslint": "~6.1.0",
|
||||||
|
"typescript": "~4.0.3",
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"name": "my-workspace",
|
||||||
|
"private": true,
|
||||||
|
"scripts": Object {
|
||||||
|
"affected": "nx affected",
|
||||||
|
"affected:apps": "nx affected:apps",
|
||||||
|
"affected:build": "nx affected:build",
|
||||||
|
"affected:dep-graph": "nx affected:dep-graph",
|
||||||
|
"affected:e2e": "nx affected:e2e",
|
||||||
|
"affected:libs": "nx affected:libs",
|
||||||
|
"affected:lint": "nx affected:lint",
|
||||||
|
"affected:test": "nx affected:test",
|
||||||
|
"build": "nx build",
|
||||||
|
"dep-graph": "nx dep-graph",
|
||||||
|
"e2e": "nx e2e",
|
||||||
|
"format": "nx format:write",
|
||||||
|
"format:check": "nx format:check",
|
||||||
|
"format:write": "nx format:write",
|
||||||
|
"help": "nx help",
|
||||||
|
"lint": "nx workspace-lint && nx lint",
|
||||||
|
"nx": "nx",
|
||||||
|
"start": "nx serve",
|
||||||
|
"test": "nx test",
|
||||||
|
"update": "nx migrate latest",
|
||||||
|
"workspace-generator": "nx workspace-generator",
|
||||||
|
},
|
||||||
|
"version": "0.0.0",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new --preset empty should generate necessary npm dependencies 1`] = `
|
||||||
|
Object {
|
||||||
|
"dependencies": Object {},
|
||||||
|
"devDependencies": Object {
|
||||||
|
"@nrwl/cli": "*",
|
||||||
|
"@nrwl/tao": "*",
|
||||||
|
"@nrwl/workspace": "*",
|
||||||
|
"@types/node": "12.12.38",
|
||||||
|
"dotenv": "6.2.0",
|
||||||
|
"eslint": "7.10.0",
|
||||||
|
"prettier": "2.1.2",
|
||||||
|
"ts-node": "~9.1.1",
|
||||||
|
"tslint": "~6.1.0",
|
||||||
|
"typescript": "~4.0.3",
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"name": "my-workspace",
|
||||||
|
"private": true,
|
||||||
|
"scripts": Object {
|
||||||
|
"affected": "nx affected",
|
||||||
|
"affected:apps": "nx affected:apps",
|
||||||
|
"affected:build": "nx affected:build",
|
||||||
|
"affected:dep-graph": "nx affected:dep-graph",
|
||||||
|
"affected:e2e": "nx affected:e2e",
|
||||||
|
"affected:libs": "nx affected:libs",
|
||||||
|
"affected:lint": "nx affected:lint",
|
||||||
|
"affected:test": "nx affected:test",
|
||||||
|
"build": "nx build",
|
||||||
|
"dep-graph": "nx dep-graph",
|
||||||
|
"e2e": "nx e2e",
|
||||||
|
"format": "nx format:write",
|
||||||
|
"format:check": "nx format:check",
|
||||||
|
"format:write": "nx format:write",
|
||||||
|
"help": "nx help",
|
||||||
|
"lint": "nx workspace-lint && nx lint",
|
||||||
|
"nx": "nx",
|
||||||
|
"start": "nx serve",
|
||||||
|
"test": "nx test",
|
||||||
|
"update": "nx migrate latest",
|
||||||
|
"workspace-generator": "nx workspace-generator",
|
||||||
|
},
|
||||||
|
"version": "0.0.0",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new --preset react should generate an empty nx.json 1`] = `
|
||||||
|
Object {
|
||||||
|
"affected": Object {
|
||||||
|
"defaultBase": "master",
|
||||||
|
},
|
||||||
|
"implicitDependencies": Object {
|
||||||
|
".eslintrc.json": "*",
|
||||||
|
"nx.json": "*",
|
||||||
|
"package.json": Object {
|
||||||
|
"dependencies": "*",
|
||||||
|
"devDependencies": "*",
|
||||||
|
},
|
||||||
|
"tsconfig.base.json": "*",
|
||||||
|
"tslint.json": "*",
|
||||||
|
"workspace.json": "*",
|
||||||
|
},
|
||||||
|
"npmScope": "npmScope",
|
||||||
|
"projects": Object {},
|
||||||
|
"tasksRunnerOptions": Object {
|
||||||
|
"default": Object {
|
||||||
|
"options": Object {
|
||||||
|
"cacheableOperations": Array [
|
||||||
|
"build",
|
||||||
|
"lint",
|
||||||
|
"test",
|
||||||
|
"e2e",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"runner": "@nrwl/workspace/tasks-runners/default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new --preset react should generate an empty workspace.json 1`] = `
|
||||||
|
Object {
|
||||||
|
"cli": Object {
|
||||||
|
"defaultCollection": "@nrwl/workspace",
|
||||||
|
},
|
||||||
|
"projects": Object {},
|
||||||
|
"version": 2,
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new --preset react should generate necessary npm dependencies 1`] = `
|
||||||
|
Object {
|
||||||
|
"dependencies": Object {},
|
||||||
|
"devDependencies": Object {
|
||||||
|
"@nrwl/cli": "*",
|
||||||
|
"@nrwl/react": "*",
|
||||||
|
"@nrwl/tao": "*",
|
||||||
|
"@nrwl/workspace": "*",
|
||||||
|
"@types/node": "12.12.38",
|
||||||
|
"dotenv": "6.2.0",
|
||||||
|
"eslint": "7.10.0",
|
||||||
|
"prettier": "2.1.2",
|
||||||
|
"ts-node": "~9.1.1",
|
||||||
|
"tslint": "~6.1.0",
|
||||||
|
"typescript": "~4.0.3",
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"name": "my-workspace",
|
||||||
|
"private": true,
|
||||||
|
"scripts": Object {
|
||||||
|
"affected": "nx affected",
|
||||||
|
"affected:apps": "nx affected:apps",
|
||||||
|
"affected:build": "nx affected:build",
|
||||||
|
"affected:dep-graph": "nx affected:dep-graph",
|
||||||
|
"affected:e2e": "nx affected:e2e",
|
||||||
|
"affected:libs": "nx affected:libs",
|
||||||
|
"affected:lint": "nx affected:lint",
|
||||||
|
"affected:test": "nx affected:test",
|
||||||
|
"build": "nx build",
|
||||||
|
"dep-graph": "nx dep-graph",
|
||||||
|
"e2e": "nx e2e",
|
||||||
|
"format": "nx format:write",
|
||||||
|
"format:check": "nx format:check",
|
||||||
|
"format:write": "nx format:write",
|
||||||
|
"help": "nx help",
|
||||||
|
"lint": "nx workspace-lint && nx lint",
|
||||||
|
"nx": "nx",
|
||||||
|
"start": "nx serve",
|
||||||
|
"test": "nx test",
|
||||||
|
"update": "nx migrate latest",
|
||||||
|
"workspace-generator": "nx workspace-generator",
|
||||||
|
},
|
||||||
|
"version": "0.0.0",
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new should 1`] = `
|
||||||
|
Object {
|
||||||
|
"cli": Object {
|
||||||
|
"defaultCollection": "@nrwl/workspace",
|
||||||
|
},
|
||||||
|
"projects": Object {},
|
||||||
|
"version": 2,
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new should generate an empty nx.json 1`] = `
|
||||||
|
Object {
|
||||||
|
"affected": Object {
|
||||||
|
"defaultBase": "master",
|
||||||
|
},
|
||||||
|
"implicitDependencies": Object {
|
||||||
|
".eslintrc.json": "*",
|
||||||
|
"nx.json": "*",
|
||||||
|
"package.json": Object {
|
||||||
|
"dependencies": "*",
|
||||||
|
"devDependencies": "*",
|
||||||
|
},
|
||||||
|
"tsconfig.base.json": "*",
|
||||||
|
"tslint.json": "*",
|
||||||
|
"workspace.json": "*",
|
||||||
|
},
|
||||||
|
"npmScope": "npmScope",
|
||||||
|
"projects": Object {},
|
||||||
|
"tasksRunnerOptions": Object {
|
||||||
|
"default": Object {
|
||||||
|
"options": Object {
|
||||||
|
"cacheableOperations": Array [
|
||||||
|
"build",
|
||||||
|
"lint",
|
||||||
|
"test",
|
||||||
|
"e2e",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"runner": "@nrwl/workspace/tasks-runners/default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`new should generate an empty workspace.json 1`] = `
|
||||||
|
Object {
|
||||||
|
"cli": Object {
|
||||||
|
"defaultCollection": "@nrwl/workspace",
|
||||||
|
},
|
||||||
|
"projects": Object {},
|
||||||
|
"version": 2,
|
||||||
|
}
|
||||||
|
`;
|
||||||
65
packages/workspace/src/schematics/new/new.spec.ts
Normal file
65
packages/workspace/src/schematics/new/new.spec.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { createTree } from '@nrwl/devkit/testing';
|
||||||
|
import { readJson, Tree } from '@nrwl/devkit';
|
||||||
|
import { newGenerator, Preset, Schema } from './new';
|
||||||
|
import { Linter } from '../../utils/lint';
|
||||||
|
|
||||||
|
const defaultOptions: Omit<Schema, 'name' | 'directory' | 'appName'> = {
|
||||||
|
cli: 'nx',
|
||||||
|
preset: Preset.Empty,
|
||||||
|
skipInstall: false,
|
||||||
|
skipGit: false,
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
defaultBase: 'master',
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('new', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTree();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate an empty workspace.json', async () => {
|
||||||
|
await newGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-workspace',
|
||||||
|
directory: 'my-workspace',
|
||||||
|
npmScope: 'npmScope',
|
||||||
|
appName: 'app',
|
||||||
|
});
|
||||||
|
expect(readJson(tree, 'my-workspace/workspace.json')).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate an empty nx.json', async () => {
|
||||||
|
await newGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-workspace',
|
||||||
|
directory: 'my-workspace',
|
||||||
|
npmScope: 'npmScope',
|
||||||
|
appName: 'app',
|
||||||
|
});
|
||||||
|
expect(readJson(tree, 'my-workspace/nx.json')).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('--preset', () => {
|
||||||
|
describe.each([[Preset.Empty], [Preset.Angular], [Preset.React]])(
|
||||||
|
'%s',
|
||||||
|
(preset) => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await newGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
name: 'my-workspace',
|
||||||
|
directory: 'my-workspace',
|
||||||
|
npmScope: 'npmScope',
|
||||||
|
appName: 'app',
|
||||||
|
preset,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate necessary npm dependencies', () => {
|
||||||
|
expect(readJson(tree, 'my-workspace/package.json')).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,31 +1,21 @@
|
|||||||
import {
|
import {
|
||||||
chain,
|
|
||||||
move,
|
|
||||||
noop,
|
|
||||||
Rule,
|
|
||||||
schematic,
|
|
||||||
SchematicContext,
|
|
||||||
Tree,
|
Tree,
|
||||||
} from '@angular-devkit/schematics';
|
formatFiles,
|
||||||
import {
|
updateJson,
|
||||||
NodePackageInstallTask,
|
addDependenciesToPackageJson,
|
||||||
RepositoryInitializerTask,
|
installPackagesTask,
|
||||||
} from '@angular-devkit/schematics/tasks';
|
getWorkspacePath,
|
||||||
|
convertNxGenerator,
|
||||||
|
names,
|
||||||
|
getPackageManagerCommand,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
|
||||||
import {
|
import { join } from 'path';
|
||||||
addDepsToPackageJson,
|
|
||||||
updateWorkspaceInTree,
|
|
||||||
} from '../../utils/ast-utils';
|
|
||||||
|
|
||||||
import { formatFiles } from '../../utils/rules/format-files';
|
|
||||||
|
|
||||||
import { nxVersion } from '../../utils/versions';
|
|
||||||
import * as path from 'path';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { spawn } from 'child_process';
|
|
||||||
import { getPackageManagerCommand } from '@nrwl/tao/src/shared/package-manager';
|
|
||||||
import * as yargsParser from 'yargs-parser';
|
import * as yargsParser from 'yargs-parser';
|
||||||
import { names } from '@nrwl/devkit';
|
import { spawn, SpawnOptions } from 'child_process';
|
||||||
|
|
||||||
|
import { workspaceGenerator } from '../workspace/workspace';
|
||||||
|
import { nxVersion } from '../../utils/versions';
|
||||||
|
|
||||||
export enum Preset {
|
export enum Preset {
|
||||||
Empty = 'empty',
|
Empty = 'empty',
|
||||||
@ -51,34 +41,20 @@ export interface Schema {
|
|||||||
nxCloud?: boolean;
|
nxCloud?: boolean;
|
||||||
preset: Preset;
|
preset: Preset;
|
||||||
commit?: { name: string; email: string; message?: string };
|
commit?: { name: string; email: string; message?: string };
|
||||||
defaultBase?: string;
|
defaultBase: string;
|
||||||
nxWorkspaceRoot?: string;
|
|
||||||
linter: 'tslint' | 'eslint';
|
linter: 'tslint' | 'eslint';
|
||||||
packageManager?: string;
|
packageManager?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RunPresetTask {
|
function generatePreset(host: Tree, opts: Schema) {
|
||||||
toConfiguration() {
|
|
||||||
return {
|
|
||||||
name: 'RunPreset',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createPresetTaskExecutor(opts: Schema) {
|
|
||||||
const cliCommand = opts.cli === 'angular' ? 'ng' : 'nx';
|
const cliCommand = opts.cli === 'angular' ? 'ng' : 'nx';
|
||||||
const parsedArgs = yargsParser(process.argv, {
|
const parsedArgs = yargsParser(process.argv, {
|
||||||
boolean: ['interactive'],
|
boolean: ['interactive'],
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
|
||||||
name: 'RunPreset',
|
|
||||||
create: () => {
|
|
||||||
return Promise.resolve(() => {
|
|
||||||
const spawnOptions = {
|
const spawnOptions = {
|
||||||
stdio: [process.stdin, process.stdout, process.stderr],
|
stdio: [process.stdin, process.stdout, process.stderr],
|
||||||
shell: true,
|
shell: true,
|
||||||
cwd: path.join(opts.nxWorkspaceRoot || process.cwd(), opts.directory),
|
cwd: join(host.root, opts.directory),
|
||||||
};
|
};
|
||||||
const pmc = getPackageManagerCommand();
|
const pmc = getPackageManagerCommand();
|
||||||
const executable = `${pmc.exec} ${cliCommand}`;
|
const executable = `${pmc.exec} ${cliCommand}`;
|
||||||
@ -88,30 +64,91 @@ function createPresetTaskExecutor(opts: Schema) {
|
|||||||
`--name=${opts.appName}`,
|
`--name=${opts.appName}`,
|
||||||
opts.style ? `--style=${opts.style}` : null,
|
opts.style ? `--style=${opts.style}` : null,
|
||||||
opts.linter ? `--linter=${opts.linter}` : null,
|
opts.linter ? `--linter=${opts.linter}` : null,
|
||||||
opts.npmScope
|
opts.npmScope ? `--npmScope=${opts.npmScope}` : `--npmScope=${opts.name}`,
|
||||||
? `--npmScope=${opts.npmScope}`
|
|
||||||
: `--npmScope=${opts.name}`,
|
|
||||||
opts.preset ? `--preset=${opts.preset}` : null,
|
opts.preset ? `--preset=${opts.preset}` : null,
|
||||||
`--cli=${cliCommand}`,
|
`--cli=${cliCommand}`,
|
||||||
parsedArgs.interactive ? '--interactive=true' : '--interactive=false',
|
parsedArgs.interactive ? '--interactive=true' : '--interactive=false',
|
||||||
].filter((e) => !!e);
|
].filter((e) => !!e);
|
||||||
return new Observable((obs) => {
|
return new Promise((resolve, reject) => {
|
||||||
spawn(executable, args, spawnOptions).on('close', (code: number) => {
|
spawn(executable, args, spawnOptions).on('close', (code: number) => {
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
obs.next();
|
resolve();
|
||||||
obs.complete();
|
|
||||||
} else {
|
} else {
|
||||||
const message = 'Workspace creation failed, see above.';
|
const message = 'Workspace creation failed, see above.';
|
||||||
obs.error(new Error(message));
|
reject(new Error(message));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function (options: Schema): Rule {
|
async function initializeGitRepo(
|
||||||
|
host: Tree,
|
||||||
|
rootDirectory: string,
|
||||||
|
options: Schema
|
||||||
|
) {
|
||||||
|
const execute = (args: ReadonlyArray<string>, ignoreErrorStream = false) => {
|
||||||
|
const outputStream = 'ignore';
|
||||||
|
const errorStream = ignoreErrorStream ? 'ignore' : process.stderr;
|
||||||
|
const spawnOptions: SpawnOptions = {
|
||||||
|
stdio: [process.stdin, outputStream, errorStream],
|
||||||
|
shell: true,
|
||||||
|
cwd: join(host.root, rootDirectory),
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
...(options.commit.name
|
||||||
|
? {
|
||||||
|
GIT_AUTHOR_NAME: options.commit.name,
|
||||||
|
GIT_COMMITTER_NAME: options.commit.name,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
...(options.commit.email
|
||||||
|
? {
|
||||||
|
GIT_AUTHOR_EMAIL: options.commit.email,
|
||||||
|
GIT_COMMITTER_EMAIL: options.commit.email,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
spawn('git', args, spawnOptions).on('close', (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(code);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const hasCommand = await execute(['--version']).then(
|
||||||
|
() => true,
|
||||||
|
() => false
|
||||||
|
);
|
||||||
|
if (!hasCommand) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const insideRepo = await execute(
|
||||||
|
['rev-parse', '--is-inside-work-tree'],
|
||||||
|
true
|
||||||
|
).then(
|
||||||
|
() => true,
|
||||||
|
() => false
|
||||||
|
);
|
||||||
|
if (insideRepo) {
|
||||||
|
console.info(
|
||||||
|
`Directory is already under version control. Skipping initialization of git.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await execute(['init']);
|
||||||
|
await execute(['add', '.']);
|
||||||
|
if (options.commit) {
|
||||||
|
const message = options.commit.message || 'initial commit';
|
||||||
|
await execute(['commit', `-m "${message}"`]);
|
||||||
|
}
|
||||||
|
console.info('Successfully initialized git.');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function newGenerator(host: Tree, options: Schema) {
|
||||||
if (
|
if (
|
||||||
options.skipInstall &&
|
options.skipInstall &&
|
||||||
options.preset !== 'empty' &&
|
options.preset !== 'empty' &&
|
||||||
@ -125,139 +162,97 @@ export default function (options: Schema): Rule {
|
|||||||
|
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
|
|
||||||
const layout = options.preset === 'oss' ? 'packages' : 'apps-and-libs';
|
const layout: 'packages' | 'apps-and-libs' =
|
||||||
|
options.preset === 'oss' ? 'packages' : 'apps-and-libs';
|
||||||
const workspaceOpts = {
|
const workspaceOpts = {
|
||||||
...options,
|
...options,
|
||||||
layout,
|
layout,
|
||||||
preset: undefined,
|
preset: undefined,
|
||||||
nxCloud: undefined,
|
nxCloud: undefined,
|
||||||
};
|
};
|
||||||
return (host: Tree, context: SchematicContext) => {
|
workspaceGenerator(host, workspaceOpts);
|
||||||
const engineHost = (context.engine.workflow as any).engineHost;
|
|
||||||
engineHost.registerTaskExecutor(createPresetTaskExecutor(options));
|
|
||||||
|
|
||||||
return chain([
|
if (options.cli === 'angular') {
|
||||||
schematic('workspace', workspaceOpts),
|
setDefaultPackageManager(host, options);
|
||||||
options.cli === 'angular' ? setDefaultPackageManager(options) : noop(),
|
}
|
||||||
setDefaultLinter(options),
|
setDefaultLinter(host, options);
|
||||||
addPresetDependencies(options),
|
addPresetDependencies(host, options);
|
||||||
addCloudDependencies(options),
|
addCloudDependencies(host, options);
|
||||||
move('/', options.directory),
|
|
||||||
addTasks(options),
|
await formatFiles(host);
|
||||||
formatFiles({ skipFormat: false }, options.directory),
|
host.listChanges().forEach((change) => {
|
||||||
])(Tree.empty(), context);
|
if (change.type !== 'DELETE') {
|
||||||
|
host.rename(change.path, join(options.directory, change.path));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return async () => {
|
||||||
|
installPackagesTask(host, false, options.directory);
|
||||||
|
await generatePreset(host, options);
|
||||||
|
if (!options.skipGit) {
|
||||||
|
await initializeGitRepo(host, options.directory, options);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function addCloudDependencies(options: Schema) {
|
export default newGenerator;
|
||||||
return options.nxCloud
|
export const newSchematic = convertNxGenerator(newGenerator);
|
||||||
? addDepsToPackageJson({}, { '@nrwl/nx-cloud': 'latest' }, false)
|
|
||||||
: noop();
|
function addCloudDependencies(host: Tree, options: Schema) {
|
||||||
|
if (options.nxCloud) {
|
||||||
|
return addDependenciesToPackageJson(
|
||||||
|
host,
|
||||||
|
{},
|
||||||
|
{ '@nrwl/nx-cloud': 'latest' }
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPresetDependencies(options: Schema) {
|
const presetDependencies: Omit<
|
||||||
if (options.preset === 'empty') {
|
Record<
|
||||||
return noop();
|
Preset,
|
||||||
} else if (options.preset === 'web-components') {
|
{ dependencies: Record<string, string>; dev: Record<string, string> }
|
||||||
return addDepsToPackageJson(
|
>,
|
||||||
{},
|
Preset.Empty | Preset.OSS
|
||||||
{
|
> = {
|
||||||
'@nrwl/web': nxVersion,
|
[Preset.WebComponents]: { dependencies: {}, dev: { '@nrwl/web': nxVersion } },
|
||||||
|
[Preset.Angular]: { dependencies: { '@nrwl/angular': nxVersion }, dev: {} },
|
||||||
|
[Preset.AngularWithNest]: {
|
||||||
|
dependencies: { '@nrwl/angular': nxVersion },
|
||||||
|
dev: { '@nrwl/nest': nxVersion },
|
||||||
},
|
},
|
||||||
false
|
[Preset.React]: {
|
||||||
);
|
dependencies: {},
|
||||||
} else if (options.preset === 'angular') {
|
dev: {
|
||||||
return addDepsToPackageJson(
|
|
||||||
{
|
|
||||||
'@nrwl/angular': nxVersion,
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
} else if (options.preset === 'angular-nest') {
|
|
||||||
return addDepsToPackageJson(
|
|
||||||
{
|
|
||||||
'@nrwl/angular': nxVersion,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'@nrwl/nest': nxVersion,
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
} else if (options.preset === 'react') {
|
|
||||||
return addDepsToPackageJson(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
'@nrwl/react': nxVersion,
|
'@nrwl/react': nxVersion,
|
||||||
},
|
},
|
||||||
false
|
},
|
||||||
);
|
[Preset.ReactWithExpress]: {
|
||||||
} else if (options.preset === 'react-express') {
|
dependencies: {},
|
||||||
return addDepsToPackageJson(
|
dev: {
|
||||||
{},
|
|
||||||
{
|
|
||||||
'@nrwl/react': nxVersion,
|
'@nrwl/react': nxVersion,
|
||||||
'@nrwl/express': nxVersion,
|
'@nrwl/express': nxVersion,
|
||||||
},
|
},
|
||||||
false
|
|
||||||
);
|
|
||||||
} else if (options.preset === 'next') {
|
|
||||||
return addDepsToPackageJson(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
'@nrwl/next': nxVersion,
|
|
||||||
},
|
},
|
||||||
false
|
[Preset.Nest]: {
|
||||||
);
|
dependencies: {},
|
||||||
} else if (options.preset === 'nest') {
|
dev: {
|
||||||
return addDepsToPackageJson(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
'@nrwl/nest': nxVersion,
|
'@nrwl/nest': nxVersion,
|
||||||
},
|
},
|
||||||
false
|
},
|
||||||
);
|
[Preset.NextJs]: {
|
||||||
} else {
|
dependencies: {},
|
||||||
return noop();
|
dev: {
|
||||||
}
|
'@nrwl/next': nxVersion,
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
function addTasks(options: Schema) {
|
function addPresetDependencies(host: Tree, options: Schema) {
|
||||||
return (host: Tree, context: SchematicContext) => {
|
if (options.preset === Preset.Empty || options.preset === Preset.OSS) {
|
||||||
let packageTask;
|
return;
|
||||||
let presetInstallTask;
|
|
||||||
if (!options.skipInstall) {
|
|
||||||
packageTask = context.addTask(
|
|
||||||
new NodePackageInstallTask(options.directory)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (options.preset !== 'empty') {
|
const { dependencies, dev } = presetDependencies[options.preset];
|
||||||
const createPresetTask = context.addTask(new RunPresetTask(), [
|
return addDependenciesToPackageJson(host, dependencies, dev);
|
||||||
packageTask,
|
|
||||||
]);
|
|
||||||
|
|
||||||
presetInstallTask = context.addTask(
|
|
||||||
new NodePackageInstallTask(options.directory),
|
|
||||||
[createPresetTask]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!options.skipGit) {
|
|
||||||
const commit =
|
|
||||||
typeof options.commit == 'object'
|
|
||||||
? options.commit
|
|
||||||
: !!options.commit
|
|
||||||
? {}
|
|
||||||
: false;
|
|
||||||
context.addTask(
|
|
||||||
new RepositoryInitializerTask(options.directory, commit),
|
|
||||||
presetInstallTask
|
|
||||||
? [presetInstallTask]
|
|
||||||
: packageTask
|
|
||||||
? [packageTask]
|
|
||||||
: []
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOptions(options: Schema): Schema {
|
function normalizeOptions(options: Schema): Schema {
|
||||||
@ -269,30 +264,29 @@ function normalizeOptions(options: Schema): Schema {
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDefaultLinter({ linter, preset }: Schema): Rule {
|
function setDefaultLinter(host: Tree, { linter, preset }: Schema) {
|
||||||
// Don't do anything if someone doesn't pick angular
|
// Don't do anything if someone doesn't pick angular
|
||||||
if (preset === 'angular' || preset === 'angular-nest') {
|
if (preset !== 'angular' && preset !== 'angular-nest') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (linter) {
|
switch (linter) {
|
||||||
case 'eslint': {
|
case 'eslint': {
|
||||||
return setESLintDefault();
|
setESLintDefault(host);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case 'tslint': {
|
case 'tslint': {
|
||||||
return setTSLintDefault();
|
setTSLintDefault(host);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
|
||||||
return noop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return noop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This sets ESLint as the default for any schematics that default to TSLint
|
* This sets ESLint as the default for any schematics that default to TSLint
|
||||||
*/
|
*/
|
||||||
function setESLintDefault() {
|
function setESLintDefault(host: Tree) {
|
||||||
return updateWorkspaceInTree((json) => {
|
updateJson(host, getWorkspacePath(host), (json) => {
|
||||||
setDefault(json, '@nrwl/angular', 'application', 'linter', 'eslint');
|
setDefault(json, '@nrwl/angular', 'application', 'linter', 'eslint');
|
||||||
setDefault(json, '@nrwl/angular', 'library', 'linter', 'eslint');
|
setDefault(json, '@nrwl/angular', 'library', 'linter', 'eslint');
|
||||||
setDefault(
|
setDefault(
|
||||||
@ -309,8 +303,8 @@ function setESLintDefault() {
|
|||||||
/**
|
/**
|
||||||
* This sets TSLint as the default for any schematics that default to ESLint
|
* This sets TSLint as the default for any schematics that default to ESLint
|
||||||
*/
|
*/
|
||||||
function setTSLintDefault() {
|
function setTSLintDefault(host: Tree) {
|
||||||
return updateWorkspaceInTree((json) => {
|
updateJson(host, getWorkspacePath(host), (json) => {
|
||||||
setDefault(json, '@nrwl/workspace', 'library', 'linter', 'tslint');
|
setDefault(json, '@nrwl/workspace', 'library', 'linter', 'tslint');
|
||||||
setDefault(json, '@nrwl/cypress', 'cypress-project', 'linter', 'tslint');
|
setDefault(json, '@nrwl/cypress', 'cypress-project', 'linter', 'tslint');
|
||||||
setDefault(json, '@nrwl/cypress', 'cypress-project', 'linter', 'tslint');
|
setDefault(json, '@nrwl/cypress', 'cypress-project', 'linter', 'tslint');
|
||||||
@ -325,12 +319,12 @@ function setTSLintDefault() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDefaultPackageManager({ packageManager }: Schema) {
|
function setDefaultPackageManager(host: Tree, { packageManager }: Schema) {
|
||||||
if (!packageManager) {
|
if (!packageManager) {
|
||||||
return noop();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateWorkspaceInTree((json) => {
|
updateJson(host, getWorkspacePath(host), (json) => {
|
||||||
if (!json.cli) {
|
if (!json.cli) {
|
||||||
json.cli = {};
|
json.cli = {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
"id": "NxWorkspaceNew",
|
"id": "NxWorkspaceNew",
|
||||||
"title": "Create an empty workspace",
|
"title": "Create an empty workspace",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"cli": "nx",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"description": "The name of the workspace.",
|
"description": "The name of the workspace.",
|
||||||
@ -13,17 +14,17 @@
|
|||||||
},
|
},
|
||||||
"x-prompt": "What name would you like to use for the workspace?"
|
"x-prompt": "What name would you like to use for the workspace?"
|
||||||
},
|
},
|
||||||
|
"cli": {
|
||||||
|
"description": "CLI used for generating code and running tasks",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["nx", "angular"],
|
||||||
|
"default": "nx"
|
||||||
|
},
|
||||||
"style": {
|
"style": {
|
||||||
"description": "The file extension to be used for style files.",
|
"description": "The file extension to be used for style files.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "css"
|
"default": "css"
|
||||||
},
|
},
|
||||||
"directory": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "path",
|
|
||||||
"description": "The directory name to create the workspace in.",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"npmScope": {
|
"npmScope": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Npm scope for importing libs."
|
"description": "Npm scope for importing libs."
|
||||||
@ -82,11 +83,6 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"nxWorkspaceRoot": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Root directory.",
|
|
||||||
"hidden": true
|
|
||||||
},
|
|
||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`workspace should create a prettierrc file 1`] = `
|
||||||
|
"{
|
||||||
|
\\"singleQuote\\": true
|
||||||
|
}"
|
||||||
|
`;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<% if(cli === 'angular') { %>
|
<% if(cli === 'angular') { %>
|
||||||
|
|
||||||
# <%= utils.classify(name) %>
|
# <%= formattedNames.className %>
|
||||||
|
|
||||||
This project was generated using [Nx](https://nx.dev).
|
This project was generated using [Nx](https://nx.dev).
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ Visit the [Nx Documentation](https://nx.dev/angular) to learn more.
|
|||||||
|
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
|
|
||||||
# <%= utils.classify(name) %>
|
# <%= formattedNames.className %>
|
||||||
|
|
||||||
This project was generated using [Nx](https://nx.dev).
|
This project was generated using [Nx](https://nx.dev).
|
||||||
|
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
<%= defaultNrwlPrettierConfig %>
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "<%= utils.dasherize(name) %>",
|
"name": "<%= formattedNames.fileName %>",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
export interface Schema {
|
export interface Schema {
|
||||||
directory: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
npmScope?: string;
|
npmScope?: string;
|
||||||
skipInstall?: boolean;
|
skipInstall?: boolean;
|
||||||
@ -8,5 +7,5 @@ export interface Schema {
|
|||||||
commit?: { name: string; email: string; message?: string };
|
commit?: { name: string; email: string; message?: string };
|
||||||
cli: 'nx' | 'angular';
|
cli: 'nx' | 'angular';
|
||||||
layout: 'apps-and-libs' | 'packages';
|
layout: 'apps-and-libs' | 'packages';
|
||||||
defaultBase?: string;
|
defaultBase: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"id": "SchematicsNxNgNew",
|
"id": "SchematicsNxNgNew",
|
||||||
|
"cli": "nx",
|
||||||
"title": "Create an empty workspace",
|
"title": "Create an empty workspace",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -41,6 +42,7 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "path",
|
"format": "path",
|
||||||
"description": "The directory name to create the workspace in.",
|
"description": "The directory name to create the workspace in.",
|
||||||
|
"x-deprecated": "This option is no longer used.",
|
||||||
"default": ""
|
"default": ""
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
|
|||||||
@ -1,16 +1,22 @@
|
|||||||
import { Tree } from '@angular-devkit/schematics';
|
import { readJson, Tree } from '@nrwl/devkit';
|
||||||
import { NxJson, readJsonInTree } from '@nrwl/workspace';
|
import { workspaceGenerator } from './workspace';
|
||||||
import { runSchematic } from '../../utils/testing';
|
import { createTree } from '@nrwl/devkit/testing';
|
||||||
|
import { NxJson } from '../../core/shared-interfaces';
|
||||||
|
|
||||||
describe('workspace', () => {
|
describe('@nrwl/workspace:workspace', () => {
|
||||||
let projectTree: Tree;
|
let tree: Tree;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
projectTree = Tree.empty();
|
tree = createTree();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create files', async () => {
|
it('should create files', async () => {
|
||||||
const tree = await runSchematic('workspace', { name: 'proj' }, projectTree);
|
workspaceGenerator(tree, {
|
||||||
|
name: 'proj',
|
||||||
|
cli: 'nx',
|
||||||
|
layout: 'apps-and-libs',
|
||||||
|
defaultBase: 'main',
|
||||||
|
});
|
||||||
expect(tree.exists('/nx.json')).toBe(true);
|
expect(tree.exists('/nx.json')).toBe(true);
|
||||||
expect(tree.exists('/workspace.json')).toBe(true);
|
expect(tree.exists('/workspace.json')).toBe(true);
|
||||||
expect(tree.exists('/.prettierrc')).toBe(true);
|
expect(tree.exists('/.prettierrc')).toBe(true);
|
||||||
@ -18,8 +24,13 @@ describe('workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create nx.json', async () => {
|
it('should create nx.json', async () => {
|
||||||
const tree = await runSchematic('workspace', { name: 'proj' }, projectTree);
|
workspaceGenerator(tree, {
|
||||||
const nxJson = readJsonInTree<NxJson>(tree, '/nx.json');
|
name: 'proj',
|
||||||
|
cli: 'nx',
|
||||||
|
layout: 'apps-and-libs',
|
||||||
|
defaultBase: 'master',
|
||||||
|
});
|
||||||
|
const nxJson = readJson<NxJson>(tree, '/nx.json');
|
||||||
expect(nxJson).toEqual({
|
expect(nxJson).toEqual({
|
||||||
npmScope: 'proj',
|
npmScope: 'proj',
|
||||||
affected: {
|
affected: {
|
||||||
@ -48,9 +59,24 @@ describe('workspace', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a prettierrc file', async () => {
|
||||||
|
workspaceGenerator(tree, {
|
||||||
|
name: 'proj',
|
||||||
|
cli: 'nx',
|
||||||
|
layout: 'apps-and-libs',
|
||||||
|
defaultBase: 'main',
|
||||||
|
});
|
||||||
|
expect(tree.read('.prettierrc').toString()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
it('should recommend vscode extensions', async () => {
|
it('should recommend vscode extensions', async () => {
|
||||||
const tree = await runSchematic('workspace', { name: 'proj' }, projectTree);
|
workspaceGenerator(tree, {
|
||||||
const recommendations = readJsonInTree<{ recommendations: string[] }>(
|
name: 'proj',
|
||||||
|
cli: 'nx',
|
||||||
|
layout: 'apps-and-libs',
|
||||||
|
defaultBase: 'main',
|
||||||
|
});
|
||||||
|
const recommendations = readJson<{ recommendations: string[] }>(
|
||||||
tree,
|
tree,
|
||||||
'/.vscode/extensions.json'
|
'/.vscode/extensions.json'
|
||||||
).recommendations;
|
).recommendations;
|
||||||
@ -62,12 +88,13 @@ describe('workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should recommend vscode extensions (angular)', async () => {
|
it('should recommend vscode extensions (angular)', async () => {
|
||||||
const tree = await runSchematic(
|
workspaceGenerator(tree, {
|
||||||
'workspace',
|
name: 'proj',
|
||||||
{ name: 'proj', cli: 'angular' },
|
cli: 'angular',
|
||||||
projectTree
|
layout: 'apps-and-libs',
|
||||||
);
|
defaultBase: 'main',
|
||||||
const recommendations = readJsonInTree<{ recommendations: string[] }>(
|
});
|
||||||
|
const recommendations = readJson<{ recommendations: string[] }>(
|
||||||
tree,
|
tree,
|
||||||
'/.vscode/extensions.json'
|
'/.vscode/extensions.json'
|
||||||
).recommendations;
|
).recommendations;
|
||||||
@ -81,39 +108,42 @@ describe('workspace', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should add decorate-angular-cli when used with angular cli', async () => {
|
it('should add decorate-angular-cli when used with angular cli', async () => {
|
||||||
const tree = await runSchematic(
|
workspaceGenerator(tree, {
|
||||||
'workspace',
|
name: 'proj',
|
||||||
{ name: 'proj', cli: 'angular' },
|
cli: 'angular',
|
||||||
projectTree
|
layout: 'apps-and-libs',
|
||||||
);
|
defaultBase: 'main',
|
||||||
|
});
|
||||||
expect(tree.exists('/decorate-angular-cli.js')).toBe(true);
|
expect(tree.exists('/decorate-angular-cli.js')).toBe(true);
|
||||||
const packageJson = readJsonInTree(tree, '/package.json');
|
const packageJson = readJson(tree, '/package.json');
|
||||||
expect(packageJson.scripts.postinstall).toEqual(
|
expect(packageJson.scripts.postinstall).toEqual(
|
||||||
'node ./decorate-angular-cli.js'
|
'node ./decorate-angular-cli.js'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not add decorate-angular-cli when used with nx cli', async () => {
|
it('should not add decorate-angular-cli when used with nx cli', async () => {
|
||||||
const tree = await runSchematic(
|
workspaceGenerator(tree, {
|
||||||
'workspace',
|
name: 'proj',
|
||||||
{ name: 'proj', cli: 'nx' },
|
cli: 'nx',
|
||||||
projectTree
|
layout: 'apps-and-libs',
|
||||||
);
|
defaultBase: 'main',
|
||||||
|
});
|
||||||
expect(tree.exists('/decorate-angular-cli.js')).toBe(false);
|
expect(tree.exists('/decorate-angular-cli.js')).toBe(false);
|
||||||
const packageJson = readJsonInTree(tree, '/package.json');
|
const packageJson = readJson(tree, '/package.json');
|
||||||
expect(packageJson.scripts.postinstall).toBeUndefined();
|
expect(packageJson.scripts.postinstall).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a workspace using package layout', async () => {
|
it('should create a workspace using package layout', async () => {
|
||||||
const tree = await runSchematic(
|
workspaceGenerator(tree, {
|
||||||
'workspace',
|
name: 'proj',
|
||||||
{ name: 'proj', cli: 'nx', layout: 'packages' },
|
cli: 'nx',
|
||||||
projectTree
|
layout: 'packages',
|
||||||
);
|
defaultBase: 'main',
|
||||||
|
});
|
||||||
expect(tree.exists('/packages/.gitkeep')).toBe(true);
|
expect(tree.exists('/packages/.gitkeep')).toBe(true);
|
||||||
expect(tree.exists('/apps/.gitkeep')).toBe(false);
|
expect(tree.exists('/apps/.gitkeep')).toBe(false);
|
||||||
expect(tree.exists('/libs/.gitkeep')).toBe(false);
|
expect(tree.exists('/libs/.gitkeep')).toBe(false);
|
||||||
const nx = readJsonInTree(tree, '/nx.json');
|
const nx = readJson(tree, '/nx.json');
|
||||||
expect(nx.workspaceLayout).toEqual({
|
expect(nx.workspaceLayout).toEqual({
|
||||||
appsDir: 'packages',
|
appsDir: 'packages',
|
||||||
libsDir: 'packages',
|
libsDir: 'packages',
|
||||||
|
|||||||
@ -1,17 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
apply,
|
generateFiles,
|
||||||
branchAndMerge,
|
|
||||||
chain,
|
|
||||||
mergeWith,
|
|
||||||
noop,
|
|
||||||
Rule,
|
|
||||||
SchematicContext,
|
|
||||||
template,
|
|
||||||
Tree,
|
Tree,
|
||||||
url,
|
updateJson,
|
||||||
} from '@angular-devkit/schematics';
|
convertNxGenerator,
|
||||||
|
names,
|
||||||
|
writeJson,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { join, strings } from '@angular-devkit/core';
|
|
||||||
import {
|
import {
|
||||||
angularCliVersion,
|
angularCliVersion,
|
||||||
eslintVersion,
|
eslintVersion,
|
||||||
@ -21,7 +16,6 @@ import {
|
|||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { join as pathJoin } from 'path';
|
import { join as pathJoin } from 'path';
|
||||||
import { updateJsonInTree } from '@nrwl/workspace';
|
|
||||||
|
|
||||||
export const DEFAULT_NRWL_PRETTIER_CONFIG = {
|
export const DEFAULT_NRWL_PRETTIER_CONFIG = {
|
||||||
singleQuote: true,
|
singleQuote: true,
|
||||||
@ -31,11 +25,11 @@ const decorateAngularClI = (host: Tree) => {
|
|||||||
const decorateCli = readFileSync(
|
const decorateCli = readFileSync(
|
||||||
pathJoin(__dirname as any, '..', 'utils', 'decorate-angular-cli.js__tmpl__')
|
pathJoin(__dirname as any, '..', 'utils', 'decorate-angular-cli.js__tmpl__')
|
||||||
).toString();
|
).toString();
|
||||||
host.create('decorate-angular-cli.js', decorateCli);
|
host.write('decorate-angular-cli.js', decorateCli);
|
||||||
};
|
};
|
||||||
|
|
||||||
function setWorkspaceLayoutProperties(options: Schema) {
|
function setWorkspaceLayoutProperties(tree: Tree, options: Schema) {
|
||||||
return updateJsonInTree('nx.json', (json) => {
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
if (options.layout === 'packages') {
|
if (options.layout === 'packages') {
|
||||||
json.workspaceLayout = {
|
json.workspaceLayout = {
|
||||||
appsDir: 'packages',
|
appsDir: 'packages',
|
||||||
@ -46,27 +40,20 @@ function setWorkspaceLayoutProperties(options: Schema) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAppsAndLibsFolders(options: Schema) {
|
function createAppsAndLibsFolders(host: Tree, options: Schema) {
|
||||||
return (host: Tree) => {
|
|
||||||
if (options.layout === 'packages') {
|
if (options.layout === 'packages') {
|
||||||
host.create('packages/.gitkeep', '');
|
host.write('packages/.gitkeep', '');
|
||||||
} else {
|
} else {
|
||||||
host.create('apps/.gitkeep', '');
|
host.write('apps/.gitkeep', '');
|
||||||
host.create('libs/.gitkeep', '');
|
host.write('libs/.gitkeep', '');
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function (options: Schema): Rule {
|
function createFiles(host: Tree, options: Schema) {
|
||||||
if (!options.name) {
|
|
||||||
throw new Error(`Invalid options, "name" is required.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (host: Tree, context: SchematicContext) => {
|
|
||||||
const npmScope = options.npmScope ? options.npmScope : options.name;
|
const npmScope = options.npmScope ? options.npmScope : options.name;
|
||||||
const templateSource = apply(url('./files'), [
|
const formattedNames = names(options.name);
|
||||||
template({
|
generateFiles(host, pathJoin(__dirname, './files'), '', {
|
||||||
utils: strings,
|
formattedNames,
|
||||||
dot: '.',
|
dot: '.',
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
workspaceFile: options.cli === 'angular' ? 'angular' : 'workspace',
|
workspaceFile: options.cli === 'angular' ? 'angular' : 'workspace',
|
||||||
@ -80,22 +67,24 @@ export default function (options: Schema): Rule {
|
|||||||
...(options as object),
|
...(options as object),
|
||||||
nxVersion,
|
nxVersion,
|
||||||
npmScope,
|
npmScope,
|
||||||
defaultNrwlPrettierConfig: JSON.stringify(
|
});
|
||||||
DEFAULT_NRWL_PRETTIER_CONFIG,
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
return chain([
|
|
||||||
branchAndMerge(
|
|
||||||
chain([
|
|
||||||
mergeWith(templateSource),
|
|
||||||
options.cli === 'angular' ? decorateAngularClI : noop(),
|
|
||||||
setWorkspaceLayoutProperties(options),
|
|
||||||
createAppsAndLibsFolders(options),
|
|
||||||
])
|
|
||||||
),
|
|
||||||
])(host, context);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createPrettierrc(host: Tree) {
|
||||||
|
writeJson(host, '.prettierrc', DEFAULT_NRWL_PRETTIER_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function workspaceGenerator(host: Tree, options: Schema) {
|
||||||
|
if (!options.name) {
|
||||||
|
throw new Error(`Invalid options, "name" is required.`);
|
||||||
|
}
|
||||||
|
createFiles(host, options);
|
||||||
|
createPrettierrc(host);
|
||||||
|
if (options.cli === 'angular') {
|
||||||
|
decorateAngularClI(host);
|
||||||
|
}
|
||||||
|
setWorkspaceLayoutProperties(host, options);
|
||||||
|
createAppsAndLibsFolders(host, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const workspaceSchematic = convertNxGenerator(workspaceGenerator);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user