feat(nx): standalone version of nx
This commit is contained in:
parent
3a2c56f21a
commit
2b646f8eb4
18
.travis.yml
18
.travis.yml
@ -34,7 +34,23 @@ matrix:
|
|||||||
- yarn install --network-timeout 1000000
|
- yarn install --network-timeout 1000000
|
||||||
script:
|
script:
|
||||||
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then yarn checkformat --head=$TRAVIS_PULL_REQUEST_SHA --base=$(git merge-base HEAD $TRAVIS_BRANCH); fi'
|
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then yarn checkformat --head=$TRAVIS_PULL_REQUEST_SHA --base=$(git merge-base HEAD $TRAVIS_BRANCH); fi'
|
||||||
- yarn e2e
|
- yarn e2e --cli nx
|
||||||
|
- os: linux
|
||||||
|
language: node_js
|
||||||
|
node_js: 10
|
||||||
|
dist: trusty
|
||||||
|
sudo: required
|
||||||
|
cache:
|
||||||
|
npm: false
|
||||||
|
addons:
|
||||||
|
chrome: stable
|
||||||
|
before_install:
|
||||||
|
- export DISPLAY=:99.0; sh -e /etc/init.d/xvfb start;
|
||||||
|
install:
|
||||||
|
- yarn install --network-timeout 1000000
|
||||||
|
script:
|
||||||
|
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then yarn checkformat --head=$TRAVIS_PULL_REQUEST_SHA --base=$(git merge-base HEAD $TRAVIS_BRANCH); fi'
|
||||||
|
- yarn e2e --cli angular
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
|||||||
@ -17,6 +17,14 @@ Type: `string`
|
|||||||
|
|
||||||
A directory where the app is placed
|
A directory where the app is placed
|
||||||
|
|
||||||
|
### linter
|
||||||
|
|
||||||
|
Default: `tslint`
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
The tool to use for running lint checks.
|
||||||
|
|
||||||
### name
|
### name
|
||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|||||||
@ -23,6 +23,14 @@ Type: `string`
|
|||||||
|
|
||||||
Frontend project that needs to access this application. This sets up proxy configuration.
|
Frontend project that needs to access this application. This sets up proxy configuration.
|
||||||
|
|
||||||
|
### linter
|
||||||
|
|
||||||
|
Default: `tslint`
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
The tool to use for running lint checks.
|
||||||
|
|
||||||
### name
|
### name
|
||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|||||||
@ -33,6 +33,14 @@ Type: `string`
|
|||||||
|
|
||||||
Test runner to use for end to end (e2e) tests
|
Test runner to use for end to end (e2e) tests
|
||||||
|
|
||||||
|
### linter
|
||||||
|
|
||||||
|
Default: `tslint`
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
The tool to use for running lint checks.
|
||||||
|
|
||||||
### name
|
### name
|
||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|||||||
@ -45,7 +45,7 @@ Use pascal case component file name (e.g. App.tsx)
|
|||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|
||||||
The name of the project (as specified in angular.json).
|
The name of the project.
|
||||||
|
|
||||||
### routing
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,14 @@ Type: `string`
|
|||||||
|
|
||||||
A directory where the app is placed
|
A directory where the app is placed
|
||||||
|
|
||||||
|
### linter
|
||||||
|
|
||||||
|
Default: `tslint`
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
The tool to use for running lint checks.
|
||||||
|
|
||||||
### name
|
### name
|
||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|||||||
@ -25,6 +25,14 @@ Type: `string`
|
|||||||
|
|
||||||
Test runner to use for end to end (e2e) tests
|
Test runner to use for end to end (e2e) tests
|
||||||
|
|
||||||
|
### linter
|
||||||
|
|
||||||
|
Default: `tslint`
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
The tool to use for running lint checks.
|
||||||
|
|
||||||
### name
|
### name
|
||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|||||||
@ -8,7 +8,7 @@ Run commands
|
|||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|
||||||
Extra arguments. You can pass them as follows: ng run project:target --args='--wait=100'. You can them use {args.wait} syntax to interpolate them in angular.json
|
Extra arguments. You can pass them as follows: ng run project:target --args='--wait=100'. You can them use {args.wait} syntax to interpolate them in the workspace config file.
|
||||||
|
|
||||||
### commands
|
### commands
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,14 @@ Type: `string`
|
|||||||
|
|
||||||
A directory where the app is placed
|
A directory where the app is placed
|
||||||
|
|
||||||
|
### linter
|
||||||
|
|
||||||
|
Default: `tslint`
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
The tool to use for running lint checks.
|
||||||
|
|
||||||
### name
|
### name
|
||||||
|
|
||||||
Type: `string`
|
Type: `string`
|
||||||
|
|||||||
72
docs/api-workspace/schematics/tao-new.md
Normal file
72
docs/api-workspace/schematics/tao-new.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# tao-new [hidden]
|
||||||
|
|
||||||
|
Create a workspace
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng generate tao-new ...
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
### commit
|
||||||
|
|
||||||
|
Default: `true`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Initial repository commit information.
|
||||||
|
|
||||||
|
### directory
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
The directory name to create the workspace in.
|
||||||
|
|
||||||
|
### name
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
The name of the workspace.
|
||||||
|
|
||||||
|
### npmScope
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
Npm scope for importing libs.
|
||||||
|
|
||||||
|
### preset
|
||||||
|
|
||||||
|
Default: `empty`
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
What to create in the new workspace
|
||||||
|
|
||||||
|
### skipGit
|
||||||
|
|
||||||
|
Alias(es): g
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Skip initializing a git repository.
|
||||||
|
|
||||||
|
### skipInstall
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Skip installing dependency packages.
|
||||||
|
|
||||||
|
### style
|
||||||
|
|
||||||
|
Default: `css`
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
The file extension to be used for style files.
|
||||||
@ -11,6 +11,14 @@ ng generate workspace ...
|
|||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
|
### cli
|
||||||
|
|
||||||
|
Default: `nx`
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
CLI used for generating code and running tasks
|
||||||
|
|
||||||
### commit
|
### commit
|
||||||
|
|
||||||
Default: `true`
|
Default: `true`
|
||||||
|
|||||||
@ -3,15 +3,16 @@ import {
|
|||||||
readFile,
|
readFile,
|
||||||
readJson,
|
readJson,
|
||||||
runCommand,
|
runCommand,
|
||||||
runsInWSL,
|
|
||||||
uniq,
|
uniq,
|
||||||
updateFile,
|
updateFile,
|
||||||
runCLI
|
runCLI,
|
||||||
|
forEachCli,
|
||||||
|
supportUi
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
let originalCIValue;
|
let originalCIValue;
|
||||||
|
|
||||||
describe('Affected', () => {
|
forEachCli(() => {
|
||||||
/**
|
/**
|
||||||
* Setting CI=true makes it simpler to configure assertions around output, as there
|
* Setting CI=true makes it simpler to configure assertions around output, as there
|
||||||
* won't be any colors.
|
* won't be any colors.
|
||||||
@ -24,6 +25,7 @@ describe('Affected', () => {
|
|||||||
process.env.CI = originalCIValue;
|
process.env.CI = originalCIValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Affected', () => {
|
||||||
it('should print, build, and test affected apps', () => {
|
it('should print, build, and test affected apps', () => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
const myapp = uniq('myapp');
|
const myapp = uniq('myapp');
|
||||||
@ -104,9 +106,9 @@ describe('Affected', () => {
|
|||||||
`npm run affected:build -- --files="libs/${mylib}/src/index.ts"`
|
`npm run affected:build -- --files="libs/${mylib}/src/index.ts"`
|
||||||
);
|
);
|
||||||
expect(build).toContain(`Running target build for projects:`);
|
expect(build).toContain(`Running target build for projects:`);
|
||||||
expect(build).toContain(myapp);
|
|
||||||
expect(build).toContain(mypublishablelib);
|
|
||||||
|
|
||||||
|
expect(build).toContain(`- ${myapp}`);
|
||||||
|
expect(build).toContain(`- ${mypublishablelib}`);
|
||||||
expect(build).not.toContain('is not registered with the build command');
|
expect(build).not.toContain('is not registered with the build command');
|
||||||
expect(build).not.toContain('with flags:');
|
expect(build).not.toContain('with flags:');
|
||||||
|
|
||||||
@ -115,8 +117,8 @@ describe('Affected', () => {
|
|||||||
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --parallel`
|
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --parallel`
|
||||||
);
|
);
|
||||||
expect(buildParallel).toContain(`Running target build for projects:`);
|
expect(buildParallel).toContain(`Running target build for projects:`);
|
||||||
expect(buildParallel).toContain(myapp);
|
expect(buildParallel).toContain(`- ${myapp}`);
|
||||||
expect(buildParallel).toContain(mypublishablelib);
|
expect(buildParallel).toContain(`- ${mypublishablelib}`);
|
||||||
expect(buildParallel).toContain(
|
expect(buildParallel).toContain(
|
||||||
'Running target "build" for affected projects succeeded'
|
'Running target "build" for affected projects succeeded'
|
||||||
);
|
);
|
||||||
@ -125,20 +127,21 @@ describe('Affected', () => {
|
|||||||
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --exclude ${myapp}`
|
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --exclude ${myapp}`
|
||||||
);
|
);
|
||||||
expect(buildExcluded).toContain(`Running target build for projects:`);
|
expect(buildExcluded).toContain(`Running target build for projects:`);
|
||||||
expect(buildExcluded).toContain(mypublishablelib);
|
expect(buildExcluded).toContain(`- ${mypublishablelib}`);
|
||||||
|
|
||||||
// affected:build should pass non-nx flags to the CLI
|
// affected:build should pass non-nx flags to the CLI
|
||||||
const buildWithFlags = runCommand(
|
const buildWithFlags = runCommand(
|
||||||
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --stats-json`
|
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --stats-json`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(buildWithFlags).toContain(`Running target build for projects:`);
|
expect(buildWithFlags).toContain(`Running target build for projects:`);
|
||||||
expect(buildWithFlags).toContain(myapp);
|
expect(buildWithFlags).toContain(`- ${myapp}`);
|
||||||
expect(buildWithFlags).toContain(mypublishablelib);
|
expect(buildWithFlags).toContain(`- ${mypublishablelib}`);
|
||||||
expect(buildWithFlags).toContain('With flags: --stats-json=true');
|
expect(buildWithFlags).toContain('With flags: --stats-json=true');
|
||||||
|
|
||||||
if (!runsInWSL()) {
|
if (supportUi()) {
|
||||||
const e2e = runCommand(
|
const e2e = runCommand(
|
||||||
`npm run affected:e2e -- --files="libs/${mylib}/src/index.ts" --headless --no-watch`
|
`npm run affected:e2e -- --files="libs/${mylib}/src/index.ts" --headless`
|
||||||
);
|
);
|
||||||
expect(e2e).toContain('should display welcome message');
|
expect(e2e).toContain('should display welcome message');
|
||||||
}
|
}
|
||||||
@ -147,10 +150,9 @@ describe('Affected', () => {
|
|||||||
`npm run affected:test -- --files="libs/${mylib}/src/index.ts"`
|
`npm run affected:test -- --files="libs/${mylib}/src/index.ts"`
|
||||||
);
|
);
|
||||||
expect(unitTests).toContain(`Running target test for projects:`);
|
expect(unitTests).toContain(`Running target test for projects:`);
|
||||||
expect(unitTests).toContain(mylib);
|
expect(unitTests).toContain(`- ${mylib}`);
|
||||||
expect(unitTests).toContain(myapp);
|
expect(unitTests).toContain(`- ${myapp}`);
|
||||||
expect(unitTests).toContain(mypublishablelib);
|
expect(unitTests).toContain(`- ${mypublishablelib}`);
|
||||||
|
|
||||||
// Fail a Unit Test
|
// Fail a Unit Test
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${myapp}/src/app/app.component.spec.ts`,
|
`apps/${myapp}/src/app/app.component.spec.ts`,
|
||||||
@ -164,12 +166,10 @@ describe('Affected', () => {
|
|||||||
`npm run affected:test -- --files="libs/${mylib}/src/index.ts"`
|
`npm run affected:test -- --files="libs/${mylib}/src/index.ts"`
|
||||||
);
|
);
|
||||||
expect(failedTests).toContain(`Running target test for projects:`);
|
expect(failedTests).toContain(`Running target test for projects:`);
|
||||||
expect(failedTests).toContain(mylib);
|
expect(failedTests).toContain(`- ${mylib}`);
|
||||||
expect(failedTests).toContain(myapp);
|
expect(failedTests).toContain(`- ${myapp}`);
|
||||||
expect(failedTests).toContain(mypublishablelib);
|
expect(failedTests).toContain(`- ${mypublishablelib}`);
|
||||||
|
|
||||||
expect(failedTests).toContain(`Failed projects:`);
|
expect(failedTests).toContain(`Failed projects:`);
|
||||||
expect(failedTests).toContain(myapp);
|
|
||||||
expect(failedTests).toContain(
|
expect(failedTests).toContain(
|
||||||
'You can isolate the above projects by passing: --only-failed'
|
'You can isolate the above projects by passing: --only-failed'
|
||||||
);
|
);
|
||||||
@ -194,17 +194,17 @@ describe('Affected', () => {
|
|||||||
const isolatedTests = runCommand(
|
const isolatedTests = runCommand(
|
||||||
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --only-failed`
|
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --only-failed`
|
||||||
);
|
);
|
||||||
expect(isolatedTests).toContain(`Running target test for projects:`);
|
expect(isolatedTests).toContain(`Running target test for projects`);
|
||||||
expect(isolatedTests).toContain(myapp);
|
expect(isolatedTests).toContain(`- ${myapp}`);
|
||||||
|
|
||||||
const linting = runCommand(
|
const linting = runCommand(
|
||||||
`npm run affected:lint -- --files="libs/${mylib}/src/index.ts"`
|
`npm run affected:lint -- --files="libs/${mylib}/src/index.ts"`
|
||||||
);
|
);
|
||||||
expect(linting).toContain(`Running target lint for projects:`);
|
expect(linting).toContain(`Running target lint for projects:`);
|
||||||
expect(linting).toContain(mylib);
|
expect(linting).toContain(`- ${mylib}`);
|
||||||
expect(linting).toContain(myapp);
|
expect(linting).toContain(`- ${myapp}`);
|
||||||
expect(linting).toContain(`${myapp}-e2e`);
|
expect(linting).toContain(`- ${myapp}-e2e`);
|
||||||
expect(linting).toContain(mypublishablelib);
|
expect(linting).toContain(`- ${mypublishablelib}`);
|
||||||
|
|
||||||
const lintWithJsonFormating = runCommand(
|
const lintWithJsonFormating = runCommand(
|
||||||
`npm run affected:lint -- --files="libs/${mylib}/src/index.ts" -- --format json`
|
`npm run affected:lint -- --files="libs/${mylib}/src/index.ts" -- --format json`
|
||||||
@ -215,19 +215,20 @@ describe('Affected', () => {
|
|||||||
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --exclude=${myapp},${mypublishablelib}`
|
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --exclude=${myapp},${mypublishablelib}`
|
||||||
);
|
);
|
||||||
expect(unitTestsExcluded).toContain(`Running target test for projects:`);
|
expect(unitTestsExcluded).toContain(`Running target test for projects:`);
|
||||||
expect(unitTestsExcluded).toContain(mylib);
|
expect(unitTestsExcluded).toContain(`- ${mylib}`);
|
||||||
|
|
||||||
const i18n = runCommand(
|
const i18n = runCommand(
|
||||||
`npm run affected -- --target extract-i18n --files="libs/${mylib}/src/index.ts"`
|
`npm run affected -- --target extract-i18n --files="libs/${mylib}/src/index.ts"`
|
||||||
);
|
);
|
||||||
expect(i18n).toContain(`Running target extract-i18n for projects:`);
|
expect(i18n).toContain(`Running target extract-i18n for projects:`);
|
||||||
expect(i18n).toContain(myapp);
|
expect(i18n).toContain(`- ${myapp}`);
|
||||||
|
|
||||||
const interpolatedTests = runCommand(
|
const interpolatedTests = runCommand(
|
||||||
`npm run affected -- --target test --files="libs/${mylib}/src/index.ts" -- --jest-config {project.root}/jest.config.js`
|
`npm run affected -- --target test --files="libs/${mylib}/src/index.ts" -- --jest-config {project.root}/jest.config.js`
|
||||||
);
|
);
|
||||||
expect(interpolatedTests).toContain(
|
expect(interpolatedTests).toContain(
|
||||||
`Running target "test" for affected projects succeeded`
|
`Running target \"test\" for affected projects succeeded`
|
||||||
);
|
);
|
||||||
}, 1000000);
|
}, 1000000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -8,9 +8,12 @@ import {
|
|||||||
updateFile,
|
updateFile,
|
||||||
exists,
|
exists,
|
||||||
ensureProject,
|
ensureProject,
|
||||||
uniq
|
uniq,
|
||||||
|
forEachCli,
|
||||||
|
workspaceConfigName
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
|
forEachCli(() => {
|
||||||
describe('Command line', () => {
|
describe('Command line', () => {
|
||||||
it('lint should ensure module boundaries', () => {
|
it('lint should ensure module boundaries', () => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
@ -81,8 +84,12 @@ describe('Command line', () => {
|
|||||||
'The following file(s) do not belong to any projects:'
|
'The following file(s) do not belong to any projects:'
|
||||||
);
|
);
|
||||||
expect(stdout).toContain(`- apps/${appAfter}/browserslist`);
|
expect(stdout).toContain(`- apps/${appAfter}/browserslist`);
|
||||||
expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.css`);
|
expect(stdout).toContain(
|
||||||
expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.html`);
|
`- apps/${appAfter}/src/app/app.component.css`
|
||||||
|
);
|
||||||
|
expect(stdout).toContain(
|
||||||
|
`- apps/${appAfter}/src/app/app.component.html`
|
||||||
|
);
|
||||||
expect(stdout).toContain(
|
expect(stdout).toContain(
|
||||||
`- apps/${appAfter}/src/app/app.component.spec.ts`
|
`- apps/${appAfter}/src/app/app.component.spec.ts`
|
||||||
);
|
);
|
||||||
@ -169,7 +176,10 @@ describe('Command line', () => {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'lib directory'
|
description: 'lib directory'
|
||||||
};
|
};
|
||||||
updateFile(`tools/schematics/${custom}/schema.json`, JSON.stringify(json));
|
updateFile(
|
||||||
|
`tools/schematics/${custom}/schema.json`,
|
||||||
|
JSON.stringify(json)
|
||||||
|
);
|
||||||
|
|
||||||
const indexFile = readFile(`tools/schematics/${custom}/index.ts`);
|
const indexFile = readFile(`tools/schematics/${custom}/index.ts`);
|
||||||
updateFile(
|
updateFile(
|
||||||
@ -185,14 +195,14 @@ describe('Command line', () => {
|
|||||||
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir -d`
|
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir -d`
|
||||||
);
|
);
|
||||||
expect(exists(`libs/dir/${workspace}/src/index.ts`)).toEqual(false);
|
expect(exists(`libs/dir/${workspace}/src/index.ts`)).toEqual(false);
|
||||||
expect(dryRunOutput).toContain('update angular.json');
|
expect(dryRunOutput).toContain(`update ${workspaceConfigName()}`);
|
||||||
expect(dryRunOutput).toContain('update nx.json');
|
expect(dryRunOutput).toContain('update nx.json');
|
||||||
|
|
||||||
const output = runCommand(
|
const output = runCommand(
|
||||||
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir`
|
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir`
|
||||||
);
|
);
|
||||||
checkFilesExist(`libs/dir/${workspace}/src/index.ts`);
|
checkFilesExist(`libs/dir/${workspace}/src/index.ts`);
|
||||||
expect(output).toContain('update angular.json');
|
expect(output).toContain(`update ${workspaceConfigName()}`);
|
||||||
expect(output).toContain('update nx.json');
|
expect(output).toContain('update nx.json');
|
||||||
|
|
||||||
const another = uniq('another');
|
const another = uniq('another');
|
||||||
@ -350,3 +360,4 @@ describe('Command line', () => {
|
|||||||
}, 1000000);
|
}, 1000000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -6,10 +6,12 @@ import {
|
|||||||
readFile,
|
readFile,
|
||||||
ensureProject,
|
ensureProject,
|
||||||
uniq,
|
uniq,
|
||||||
runsInWSL,
|
newProject,
|
||||||
newProject
|
forEachCli,
|
||||||
|
supportUi
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
|
forEachCli(() => {
|
||||||
describe('Cypress E2E Test runner', () => {
|
describe('Cypress E2E Test runner', () => {
|
||||||
describe('project scaffolding', () => {
|
describe('project scaffolding', () => {
|
||||||
it('should generate an app with the Cypress as e2e test runner', () => {
|
it('should generate an app with the Cypress as e2e test runner', () => {
|
||||||
@ -34,16 +36,16 @@ describe('Cypress E2E Test runner', () => {
|
|||||||
}, 1000000);
|
}, 1000000);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!runsInWSL()) {
|
if (supportUi()) {
|
||||||
describe('running Cypress', () => {
|
describe('running Cypress', () => {
|
||||||
it('should execute e2e tests using Cypress', () => {
|
fit('should execute e2e tests using Cypress', () => {
|
||||||
newProject();
|
newProject();
|
||||||
const myapp = uniq('myapp');
|
const myapp = uniq('myapp');
|
||||||
runCLI(`generate @nrwl/angular:app ${myapp} --e2eTestRunner=cypress`);
|
runCLI(`generate @nrwl/angular:app ${myapp} --e2eTestRunner=cypress`);
|
||||||
|
|
||||||
expect(
|
expect(runCLI(`e2e ${myapp}-e2e --headless --no-watch`)).toContain(
|
||||||
runCLI(`e2e --project=${myapp}-e2e --headless --watch=false`)
|
'All specs passed!'
|
||||||
).toContain('All specs passed!');
|
);
|
||||||
|
|
||||||
const originalContents = JSON.parse(
|
const originalContents = JSON.parse(
|
||||||
readFile(`apps/${myapp}-e2e/cypress.json`)
|
readFile(`apps/${myapp}-e2e/cypress.json`)
|
||||||
@ -54,10 +56,11 @@ describe('Cypress E2E Test runner', () => {
|
|||||||
JSON.stringify(originalContents)
|
JSON.stringify(originalContents)
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(runCLI(`e2e ${myapp}-e2e --headless --no-watch`)).toContain(
|
||||||
runCLI(`e2e --project=${myapp}-e2e --headless --watch=false`)
|
'All specs passed!'
|
||||||
).toContain('All specs passed!');
|
);
|
||||||
}, 1000000);
|
}, 1000000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -1,11 +1,18 @@
|
|||||||
import { ensureProject, uniq, runCommand, checkFilesExist } from './utils';
|
import {
|
||||||
|
ensureProject,
|
||||||
|
uniq,
|
||||||
|
runCommand,
|
||||||
|
checkFilesExist,
|
||||||
|
forEachCli
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
|
forEachCli(() => {
|
||||||
describe('Delegate to CLI', () => {
|
describe('Delegate to CLI', () => {
|
||||||
it('should delegate to the Angular CLI all non-standard commands', async () => {
|
it('should delegate to the cli all non-standard commands', async () => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
|
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCommand(`npm run nx -- g app ${appName}`);
|
runCommand(`npm run nx -- g @nrwl/web:app ${appName}`);
|
||||||
runCommand(`npm run nx -- build ${appName}`);
|
runCommand(`npm run nx -- build ${appName}`);
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
@ -21,3 +28,4 @@ describe('Delegate to CLI', () => {
|
|||||||
);
|
);
|
||||||
}, 120000);
|
}, 120000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
import {
|
import {
|
||||||
ensureProject,
|
ensureProject,
|
||||||
patchKarmaToWorkOnWSL,
|
|
||||||
runCLI,
|
runCLI,
|
||||||
uniq,
|
uniq,
|
||||||
updateFile
|
updateFile,
|
||||||
|
forEachCli,
|
||||||
|
supportUi
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
describe('DowngradeModule', () => {
|
forEachCli(() => {
|
||||||
|
xdescribe('DowngradeModule', () => {
|
||||||
it('should generate a downgradeModule setup', async () => {
|
it('should generate a downgradeModule setup', async () => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
|
|
||||||
const myapp = uniq('myapp');
|
const myapp = uniq('myapp');
|
||||||
runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner=karma`);
|
runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner=karma`);
|
||||||
patchKarmaToWorkOnWSL();
|
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${myapp}/src/legacy.js`,
|
`apps/${myapp}/src/legacy.js`,
|
||||||
@ -24,6 +25,9 @@ describe('DowngradeModule', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`build ${myapp}`);
|
runCLI(`build ${myapp}`);
|
||||||
|
if (supportUi()) {
|
||||||
expect(runCLI(`test ${myapp} --no-watch`)).toContain('3 SUCCESS');
|
expect(runCLI(`test ${myapp} --no-watch`)).toContain('3 SUCCESS');
|
||||||
|
}
|
||||||
}, 1000000);
|
}, 1000000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
47
e2e/help.test.ts
Normal file
47
e2e/help.test.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { forEachCli, ensureProject, runCommand, runCLI, cli } from './utils';
|
||||||
|
|
||||||
|
forEachCli('nx', () => {
|
||||||
|
describe('Help', () => {
|
||||||
|
it('should should help', async () => {
|
||||||
|
ensureProject();
|
||||||
|
|
||||||
|
const mainHelp = runCLI(`--help`);
|
||||||
|
expect(mainHelp).toContain('Run a target for a project');
|
||||||
|
expect(mainHelp).toContain('Run task for affected projects');
|
||||||
|
|
||||||
|
const genHelp = runCLI(`g @nrwl/web:app --help`);
|
||||||
|
expect(genHelp).toContain(
|
||||||
|
'The file extension to be used for style files. (default: css)'
|
||||||
|
);
|
||||||
|
|
||||||
|
const affectedHelp = runCLI(`affected --help`);
|
||||||
|
expect(affectedHelp).toContain('Run task for affected projects');
|
||||||
|
|
||||||
|
const version = runCLI(`--version`);
|
||||||
|
expect(version).toContain('*'); // stub value
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachCli('angular', () => {
|
||||||
|
describe('Help', () => {
|
||||||
|
it('should should help', async () => {
|
||||||
|
ensureProject();
|
||||||
|
|
||||||
|
const mainHelp = runCLI(`--help`);
|
||||||
|
expect(mainHelp).toContain('Run a target for a project');
|
||||||
|
expect(mainHelp).toContain('Run task for affected projects');
|
||||||
|
|
||||||
|
const genHelp = runCLI(`g @nrwl/web:app --help`);
|
||||||
|
expect(genHelp).toContain(
|
||||||
|
'The file extension to be used for style files.'
|
||||||
|
);
|
||||||
|
|
||||||
|
const affectedHelp = runCLI(`affected --help`);
|
||||||
|
expect(affectedHelp).toContain('Run task for affected projects');
|
||||||
|
|
||||||
|
const version = runCLI(`--version`);
|
||||||
|
expect(version).toContain('*'); // stub value
|
||||||
|
}, 120000);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { runCLIAsync, ensureProject, uniq, runCLI } from './utils';
|
import { runCLIAsync, ensureProject, uniq, runCLI, forEachCli } from './utils';
|
||||||
|
|
||||||
|
forEachCli(() => {
|
||||||
describe('Jest', () => {
|
describe('Jest', () => {
|
||||||
it('should be able test projects using jest', async done => {
|
it('should be able test projects using jest', async done => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
@ -14,10 +15,11 @@ describe('Jest', () => {
|
|||||||
runCLIAsync(`generate @nrwl/angular:service test --project ${mylib}`),
|
runCLIAsync(`generate @nrwl/angular:service test --project ${mylib}`),
|
||||||
runCLIAsync(`generate @nrwl/angular:component test --project ${mylib}`)
|
runCLIAsync(`generate @nrwl/angular:component test --project ${mylib}`)
|
||||||
]);
|
]);
|
||||||
const appResult = await runCLIAsync(`test ${myapp}`);
|
const appResult = await runCLIAsync(`test ${myapp} --no-watch`);
|
||||||
expect(appResult.stderr).toContain('Test Suites: 3 passed, 3 total');
|
expect(appResult.stderr).toContain('Test Suites: 3 passed, 3 total');
|
||||||
const libResult = await runCLIAsync(`test ${mylib}`);
|
const libResult = await runCLIAsync(`test ${mylib}`);
|
||||||
expect(libResult.stderr).toContain('Test Suites: 3 passed, 3 total');
|
expect(libResult.stderr).toContain('Test Suites: 3 passed, 3 total');
|
||||||
done();
|
done();
|
||||||
}, 45000);
|
}, 45000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -3,22 +3,25 @@ import {
|
|||||||
runCLIAsync,
|
runCLIAsync,
|
||||||
ensureProject,
|
ensureProject,
|
||||||
uniq,
|
uniq,
|
||||||
patchKarmaToWorkOnWSL
|
forEachCli,
|
||||||
|
supportUi
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
describe('Karma', () => {
|
forEachCli(() => {
|
||||||
|
xdescribe('Karma', () => {
|
||||||
it('should be able to generate a testable library using karma', async done => {
|
it('should be able to generate a testable library using karma', async done => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
const mylib = uniq('mylib');
|
const mylib = uniq('mylib');
|
||||||
runCLI(`generate @nrwl/angular:lib ${mylib} --unit-test-runner karma`);
|
runCLI(`generate @nrwl/angular:lib ${mylib} --unit-test-runner karma`);
|
||||||
patchKarmaToWorkOnWSL();
|
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
runCLIAsync(`generate @nrwl/angular:service test --project ${mylib}`),
|
runCLIAsync(`generate @nrwl/angular:service test --project ${mylib}`),
|
||||||
runCLIAsync(`generate @nrwl/angular:component test --project ${mylib}`)
|
runCLIAsync(`generate @nrwl/angular:component test --project ${mylib}`)
|
||||||
]);
|
]);
|
||||||
|
if (supportUi()) {
|
||||||
const karmaResult = await runCLIAsync(`test ${mylib}`);
|
const karmaResult = await runCLIAsync(`test ${mylib}`);
|
||||||
expect(karmaResult.stdout).toContain('3 SUCCESS');
|
expect(karmaResult.stdout).toContain('3 SUCCESS');
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
}, 30000);
|
}, 30000);
|
||||||
|
|
||||||
@ -26,14 +29,16 @@ describe('Karma', () => {
|
|||||||
ensureProject();
|
ensureProject();
|
||||||
const myapp = uniq('myapp');
|
const myapp = uniq('myapp');
|
||||||
runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner karma`);
|
runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner karma`);
|
||||||
patchKarmaToWorkOnWSL();
|
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
runCLIAsync(`generate @nrwl/angular:service test --project ${myapp}`),
|
runCLIAsync(`generate @nrwl/angular:service test --project ${myapp}`),
|
||||||
runCLIAsync(`generate @nrwl/angular:component test --project ${myapp}`)
|
runCLIAsync(`generate @nrwl/angular:component test --project ${myapp}`)
|
||||||
]);
|
]);
|
||||||
|
if (supportUi()) {
|
||||||
const karmaResult = await runCLIAsync(`test ${myapp}`);
|
const karmaResult = await runCLIAsync(`test ${myapp}`);
|
||||||
expect(karmaResult.stdout).toContain('5 SUCCESS');
|
expect(karmaResult.stdout).toContain('5 SUCCESS');
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
}, 30000);
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
111
e2e/new.test.ts
Normal file
111
e2e/new.test.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import {
|
||||||
|
ensureProject,
|
||||||
|
exists,
|
||||||
|
expectTestsPass,
|
||||||
|
getSize,
|
||||||
|
runCLI,
|
||||||
|
runCLIAsync,
|
||||||
|
uniq,
|
||||||
|
updateFile,
|
||||||
|
forEachCli,
|
||||||
|
checkFilesExist,
|
||||||
|
tmpProjPath,
|
||||||
|
supportUi
|
||||||
|
} from './utils';
|
||||||
|
import { toClassName } from '@nrwl/workspace';
|
||||||
|
|
||||||
|
forEachCli(() => {
|
||||||
|
describe('Create New Workspace', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
ensureProject();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work', async () => {
|
||||||
|
const myapp = uniq('myapp');
|
||||||
|
const mylib = uniq('mylib');
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/angular:app ${myapp} --directory=myDir --no-interactive`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/angular:lib ${mylib} --directory=myDir --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
updateFile(
|
||||||
|
`apps/my-dir/${myapp}/src/app/app.module.ts`,
|
||||||
|
`
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { MyDir${toClassName(
|
||||||
|
mylib
|
||||||
|
)}Module } from '@proj/my-dir/${mylib}';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [BrowserModule, MyDir${toClassName(mylib)}Module],
|
||||||
|
declarations: [AppComponent],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
runCLI(`build my-dir-${myapp} --prod --output-hashing none`);
|
||||||
|
|
||||||
|
checkFilesExist(
|
||||||
|
`dist/apps/my-dir/${myapp}/main-es2015.js`,
|
||||||
|
`dist/apps/my-dir/${myapp}/main-es5.js`
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is a loose requirement because there are a lot of
|
||||||
|
// influences external from this project that affect this.
|
||||||
|
const es2015BundleSize = getSize(
|
||||||
|
tmpProjPath(`dist/apps/my-dir/${myapp}/main-es2015.js`)
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`The current es2015 bundle size is ${es2015BundleSize / 1000} KB`
|
||||||
|
);
|
||||||
|
expect(es2015BundleSize).toBeLessThanOrEqual(150000);
|
||||||
|
|
||||||
|
const es5BundleSize = getSize(
|
||||||
|
tmpProjPath(`dist/apps/my-dir/${myapp}/main-es5.js`)
|
||||||
|
);
|
||||||
|
console.log(`The current es5 bundle size is ${es5BundleSize / 1000} KB`);
|
||||||
|
expect(es5BundleSize).toBeLessThanOrEqual(175000);
|
||||||
|
|
||||||
|
// running tests for the app
|
||||||
|
expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`));
|
||||||
|
|
||||||
|
// running tests for the lib
|
||||||
|
expectTestsPass(await runCLIAsync(`test my-dir-${mylib} --no-watch`));
|
||||||
|
|
||||||
|
if (supportUi()) {
|
||||||
|
expect(
|
||||||
|
runCLI(`e2e my-dir-${myapp}-e2e --headless --no-watch`)
|
||||||
|
).toContain('All specs passed!');
|
||||||
|
}
|
||||||
|
}, 1000000);
|
||||||
|
|
||||||
|
it('should support router config generation (lazy)', async () => {
|
||||||
|
const myapp = uniq('myapp');
|
||||||
|
const mylib = uniq('mylib');
|
||||||
|
runCLI(`generate @nrwl/angular:app ${myapp} --directory=myDir --routing`);
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/angular:lib ${mylib} --directory=myDir --routing --lazy --parentModule=apps/my-dir/${myapp}/src/app/app.module.ts`
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(`build my-dir-${myapp} --aot`);
|
||||||
|
expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`));
|
||||||
|
}, 1000000);
|
||||||
|
|
||||||
|
it('should support router config generation (eager)', async () => {
|
||||||
|
const myapp = uniq('myapp');
|
||||||
|
runCLI(`generate @nrwl/angular:app ${myapp} --directory=myDir --routing`);
|
||||||
|
const mylib = uniq('mylib');
|
||||||
|
runCLI(
|
||||||
|
`generate @nrwl/angular:lib ${mylib} --directory=myDir --routing --parentModule=apps/my-dir/${myapp}/src/app/app.module.ts`
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(`build my-dir-${myapp} --aot`);
|
||||||
|
expectTestsPass(await runCLIAsync(`test my-dir-${myapp} --no-watch`));
|
||||||
|
}, 1000000);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -6,16 +6,19 @@ import {
|
|||||||
runCLI,
|
runCLI,
|
||||||
runCLIAsync,
|
runCLIAsync,
|
||||||
runCommand,
|
runCommand,
|
||||||
runNgNew,
|
runNew,
|
||||||
updateFile
|
updateFile,
|
||||||
|
forEachCli,
|
||||||
|
runNgAdd
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
|
forEachCli('angular', () => {
|
||||||
describe('Nrwl Convert to Nx Workspace', () => {
|
describe('Nrwl Convert to Nx Workspace', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
afterAll(cleanup);
|
afterAll(cleanup);
|
||||||
|
|
||||||
it('should generate a workspace', () => {
|
it('should generate a workspace', () => {
|
||||||
runNgNew();
|
runNew('', false, false);
|
||||||
|
|
||||||
// update package.json
|
// update package.json
|
||||||
const packageJson = readJson('package.json');
|
const packageJson = readJson('package.json');
|
||||||
@ -48,7 +51,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
updateFile('angular.json', JSON.stringify(angularCLIJson, null, 2));
|
updateFile('angular.json', JSON.stringify(angularCLIJson, null, 2));
|
||||||
|
|
||||||
// run the command
|
// run the command
|
||||||
runCLI('add @nrwl/workspace --npmScope projscope --skip-install');
|
runNgAdd('add @nrwl/workspace --npmScope projscope --skip-install');
|
||||||
copyMissingPackages();
|
copyMissingPackages();
|
||||||
|
|
||||||
// check that prettier config exits and that files have been moved!
|
// check that prettier config exits and that files have been moved!
|
||||||
@ -94,7 +97,9 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
'workspace-schematic': 'nx workspace-schematic',
|
'workspace-schematic': 'nx workspace-schematic',
|
||||||
help: 'nx help'
|
help: 'nx help'
|
||||||
});
|
});
|
||||||
expect(updatedPackageJson.devDependencies['@nrwl/workspace']).toBeDefined();
|
expect(
|
||||||
|
updatedPackageJson.devDependencies['@nrwl/workspace']
|
||||||
|
).toBeDefined();
|
||||||
expect(updatedPackageJson.devDependencies['@angular/cli']).toBeDefined();
|
expect(updatedPackageJson.devDependencies['@angular/cli']).toBeDefined();
|
||||||
|
|
||||||
const nxJson = readJson('nx.json');
|
const nxJson = readJson('nx.json');
|
||||||
@ -127,6 +132,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
expect(updatedAngularCLIJson.projects.proj.architect.build).toEqual({
|
expect(updatedAngularCLIJson.projects.proj.architect.build).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:browser',
|
builder: '@angular-devkit/build-angular:browser',
|
||||||
options: {
|
options: {
|
||||||
|
aot: false,
|
||||||
outputPath: 'dist/apps/proj',
|
outputPath: 'dist/apps/proj',
|
||||||
index: 'apps/proj/src/index.html',
|
index: 'apps/proj/src/index.html',
|
||||||
main: 'apps/proj/src/main.ts',
|
main: 'apps/proj/src/main.ts',
|
||||||
@ -214,13 +220,15 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
devServerTarget: 'proj:serve'
|
devServerTarget: 'proj:serve'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(updatedAngularCLIJson.projects['proj-e2e'].architect.lint).toEqual({
|
expect(updatedAngularCLIJson.projects['proj-e2e'].architect.lint).toEqual(
|
||||||
|
{
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
builder: '@angular-devkit/build-angular:tslint',
|
||||||
options: {
|
options: {
|
||||||
tsConfig: 'apps/proj-e2e/tsconfig.json',
|
tsConfig: 'apps/proj-e2e/tsconfig.json',
|
||||||
exclude: ['**/node_modules/**']
|
exclude: ['**/node_modules/**']
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const updatedTslint = readJson('tslint.json');
|
const updatedTslint = readJson('tslint.json');
|
||||||
expect(updatedTslint.rules['nx-enforce-module-boundaries']).toEqual([
|
expect(updatedTslint.rules['nx-enforce-module-boundaries']).toEqual([
|
||||||
@ -237,13 +245,15 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
|
|
||||||
it('should generate a workspace and not change dependencies, devDependencies, or vscode extensions if they already exist', () => {
|
it('should generate a workspace and not change dependencies, devDependencies, or vscode extensions if they already exist', () => {
|
||||||
// create a new AngularCLI app
|
// create a new AngularCLI app
|
||||||
runNgNew();
|
runNew();
|
||||||
const nxVersion = '0.0.0';
|
const nxVersion = '0.0.0';
|
||||||
const schematicsVersion = '0.0.0';
|
const schematicsVersion = '0.0.0';
|
||||||
const ngrxVersion = '0.0.0';
|
const ngrxVersion = '0.0.0';
|
||||||
// update package.json
|
// update package.json
|
||||||
const existingPackageJson = readJson('package.json');
|
const existingPackageJson = readJson('package.json');
|
||||||
existingPackageJson.devDependencies['@nrwl/workspace'] = schematicsVersion;
|
existingPackageJson.devDependencies[
|
||||||
|
'@nrwl/workspace'
|
||||||
|
] = schematicsVersion;
|
||||||
existingPackageJson.dependencies['@ngrx/store'] = ngrxVersion;
|
existingPackageJson.dependencies['@ngrx/store'] = ngrxVersion;
|
||||||
existingPackageJson.dependencies['@ngrx/effects'] = ngrxVersion;
|
existingPackageJson.dependencies['@ngrx/effects'] = ngrxVersion;
|
||||||
existingPackageJson.dependencies['@ngrx/router-store'] = ngrxVersion;
|
existingPackageJson.dependencies['@ngrx/router-store'] = ngrxVersion;
|
||||||
@ -257,7 +267,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
// run the command
|
// run the command
|
||||||
runCLI('add @nrwl/workspace --npmScope projscope --skip-install');
|
runNgAdd('add @nrwl/workspace --npmScope projscope --skip-install');
|
||||||
|
|
||||||
// check that dependencies and devDependencies remained the same
|
// check that dependencies and devDependencies remained the same
|
||||||
const packageJson = readJson('package.json');
|
const packageJson = readJson('package.json');
|
||||||
@ -266,7 +276,9 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
);
|
);
|
||||||
expect(packageJson.dependencies['@ngrx/store']).toEqual(ngrxVersion);
|
expect(packageJson.dependencies['@ngrx/store']).toEqual(ngrxVersion);
|
||||||
expect(packageJson.dependencies['@ngrx/effects']).toEqual(ngrxVersion);
|
expect(packageJson.dependencies['@ngrx/effects']).toEqual(ngrxVersion);
|
||||||
expect(packageJson.dependencies['@ngrx/router-store']).toEqual(ngrxVersion);
|
expect(packageJson.dependencies['@ngrx/router-store']).toEqual(
|
||||||
|
ngrxVersion
|
||||||
|
);
|
||||||
expect(packageJson.devDependencies['@ngrx/store-devtools']).toEqual(
|
expect(packageJson.devDependencies['@ngrx/store-devtools']).toEqual(
|
||||||
ngrxVersion
|
ngrxVersion
|
||||||
);
|
);
|
||||||
@ -282,53 +294,27 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
|
|
||||||
it('should convert a project with common libraries in the ecosystem', () => {
|
it('should convert a project with common libraries in the ecosystem', () => {
|
||||||
// create a new AngularCLI app
|
// create a new AngularCLI app
|
||||||
runNgNew();
|
runNew();
|
||||||
|
|
||||||
// Add some Angular libraries
|
// Add some Angular libraries
|
||||||
runCLI('add @angular/elements');
|
runNgAdd('add @angular/elements');
|
||||||
runCLI('add @angular/material');
|
runNgAdd('add @angular/material');
|
||||||
runCLI('add @angular/pwa');
|
runNgAdd('add @angular/pwa');
|
||||||
runCLI('add @ngrx/store');
|
runNgAdd('add @ngrx/store');
|
||||||
runCLI('add @ngrx/effects');
|
runNgAdd('add @ngrx/effects');
|
||||||
|
|
||||||
// Add Nx
|
// Add Nx
|
||||||
runCLI('add @nrwl/workspace --skip-install');
|
runNgAdd('add @nrwl/workspace --skip-install');
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle workspaces with no e2e project', async () => {
|
|
||||||
// create a new AngularCLI app
|
|
||||||
runNgNew();
|
|
||||||
|
|
||||||
// Remove e2e
|
|
||||||
runCommand('rm -rf e2e');
|
|
||||||
const existingAngularJson = readJson('angular.json');
|
|
||||||
delete existingAngularJson.projects['proj'].architect.e2e;
|
|
||||||
updateFile('angular.json', JSON.stringify(existingAngularJson, null, 2));
|
|
||||||
|
|
||||||
// Add @nrwl/workspace
|
|
||||||
const result = await runCLIAsync(
|
|
||||||
'add @nrwl/workspace --npmScope projscope --skip-install'
|
|
||||||
);
|
|
||||||
|
|
||||||
checkFilesExist(
|
|
||||||
'.prettierrc',
|
|
||||||
'apps/proj/src/main.ts',
|
|
||||||
'apps/proj/src/app/app.module.ts'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result.stderr).toContain(
|
|
||||||
'No e2e project was migrated because there was none declared in angular.json'
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle different types of errors', () => {
|
it('should handle different types of errors', () => {
|
||||||
// create a new AngularCLI app
|
// create a new AngularCLI app
|
||||||
runNgNew();
|
runNew();
|
||||||
|
|
||||||
// Only remove e2e directory
|
// Only remove e2e directory
|
||||||
runCommand('mv e2e e2e-bak');
|
runCommand('mv e2e e2e-bak');
|
||||||
try {
|
try {
|
||||||
runCLI('add @nrwl/workspace --npmScope projscope --skip-install');
|
runNgAdd('add @nrwl/workspace --npmScope projscope --skip-install');
|
||||||
fail('Did not handle not having a e2e directory');
|
fail('Did not handle not having a e2e directory');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.stderr.toString()).toContain(
|
expect(e.stderr.toString()).toContain(
|
||||||
@ -342,7 +328,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
// Remove package.json
|
// Remove package.json
|
||||||
runCommand('mv package.json package.json.bak');
|
runCommand('mv package.json package.json.bak');
|
||||||
try {
|
try {
|
||||||
runCLI('add @nrwl/workspace --npmScope projscope --skip-install');
|
runNgAdd('add @nrwl/workspace --npmScope projscope --skip-install');
|
||||||
fail('Did not handle not having a package.json');
|
fail('Did not handle not having a package.json');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.stderr.toString()).toContain(
|
expect(e.stderr.toString()).toContain(
|
||||||
@ -356,7 +342,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
// Remove src
|
// Remove src
|
||||||
runCommand('mv src src-bak');
|
runCommand('mv src src-bak');
|
||||||
try {
|
try {
|
||||||
runCLI('add @nrwl/workspace --npmScope projscope --skip-install');
|
runNgAdd('add @nrwl/workspace --npmScope projscope --skip-install');
|
||||||
fail('Did not handle not having a src directory');
|
fail('Did not handle not having a src directory');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.stderr.toString()).toContain('Path: src does not exist');
|
expect(e.stderr.toString()).toContain('Path: src does not exist');
|
||||||
@ -366,3 +352,10 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
runCommand('mv src-bak src');
|
runCommand('mv src-bak src');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
forEachCli('nx', () => {
|
||||||
|
describe('ng-add', () => {
|
||||||
|
it('is not supported', () => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -1,115 +0,0 @@
|
|||||||
import {
|
|
||||||
ensureProject,
|
|
||||||
exists,
|
|
||||||
expectTestsPass,
|
|
||||||
getSize,
|
|
||||||
runCLI,
|
|
||||||
runCLIAsync,
|
|
||||||
runsInWSL,
|
|
||||||
uniq,
|
|
||||||
updateFile
|
|
||||||
} from './utils';
|
|
||||||
import { toClassName } from '@nrwl/workspace';
|
|
||||||
|
|
||||||
describe('Nrwl Workspace', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
ensureProject();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work', async () => {
|
|
||||||
const myapp = uniq('myapp');
|
|
||||||
const mylib = uniq('mylib');
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:app ${myapp} --directory=myDir --no-interactive`
|
|
||||||
);
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:lib ${mylib} --directory=myDir --no-interactive`
|
|
||||||
);
|
|
||||||
|
|
||||||
updateFile(
|
|
||||||
`apps/my-dir/${myapp}/src/app/app.module.ts`,
|
|
||||||
`
|
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
|
||||||
import { MyDir${toClassName(
|
|
||||||
mylib
|
|
||||||
)}Module } from '@proj/my-dir/${mylib}';
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [BrowserModule, MyDir${toClassName(mylib)}Module],
|
|
||||||
declarations: [AppComponent],
|
|
||||||
bootstrap: [AppComponent]
|
|
||||||
})
|
|
||||||
export class AppModule {}
|
|
||||||
`
|
|
||||||
);
|
|
||||||
runCLI(`build --prod --project=my-dir-${myapp} --output-hashing none`);
|
|
||||||
expect(
|
|
||||||
exists(`./tmp/proj/dist/apps/my-dir/${myapp}/main-es2015.js`)
|
|
||||||
).toEqual(true);
|
|
||||||
expect(exists(`./tmp/proj/dist/apps/my-dir/${myapp}/main-es5.js`)).toEqual(
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
// This is a loose requirement because there are a lot of
|
|
||||||
// influences external from this project that affect this.
|
|
||||||
const es2015BundleSize = getSize(
|
|
||||||
`./tmp/proj/dist/apps/my-dir/${myapp}/main-es2015.js`
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
`The current es2015 bundle size is ${es2015BundleSize / 1000} KB`
|
|
||||||
);
|
|
||||||
expect(es2015BundleSize).toBeLessThanOrEqual(150000);
|
|
||||||
|
|
||||||
const es5BundleSize = getSize(
|
|
||||||
`./tmp/proj/dist/apps/my-dir/${myapp}/main-es5.js`
|
|
||||||
);
|
|
||||||
console.log(`The current es5 bundle size is ${es5BundleSize / 1000} KB`);
|
|
||||||
expect(es5BundleSize).toBeLessThanOrEqual(175000);
|
|
||||||
|
|
||||||
// running tests for the app
|
|
||||||
expectTestsPass(
|
|
||||||
await runCLIAsync(`test --project=my-dir-${myapp} --no-watch`)
|
|
||||||
);
|
|
||||||
|
|
||||||
// running tests for the lib
|
|
||||||
expectTestsPass(
|
|
||||||
await runCLIAsync(`test --project=my-dir-${mylib} --no-watch`)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!runsInWSL()) {
|
|
||||||
expect(
|
|
||||||
runCLI(`e2e --project=my-dir-${myapp}-e2e --headless --watch=false`)
|
|
||||||
).toContain('All specs passed!');
|
|
||||||
}
|
|
||||||
}, 1000000);
|
|
||||||
|
|
||||||
it('should support router config generation (lazy)', async () => {
|
|
||||||
const myapp = uniq('myapp');
|
|
||||||
const mylib = uniq('mylib');
|
|
||||||
runCLI(`generate @nrwl/angular:app ${myapp} --directory=myDir --routing`);
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:lib ${mylib} --directory=myDir --routing --lazy --parentModule=apps/my-dir/${myapp}/src/app/app.module.ts`
|
|
||||||
);
|
|
||||||
|
|
||||||
runCLI(`build --aot --project=my-dir-${myapp}`);
|
|
||||||
expectTestsPass(
|
|
||||||
await runCLIAsync(`test --project=my-dir-${myapp} --no-watch`)
|
|
||||||
);
|
|
||||||
}, 1000000);
|
|
||||||
|
|
||||||
it('should support router config generation (eager)', async () => {
|
|
||||||
const myapp = uniq('myapp');
|
|
||||||
runCLI(`generate @nrwl/angular:app ${myapp} --directory=myDir --routing`);
|
|
||||||
const mylib = uniq('mylib');
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/angular:lib ${mylib} --directory=myDir --routing --parentModule=apps/my-dir/${myapp}/src/app/app.module.ts`
|
|
||||||
);
|
|
||||||
|
|
||||||
runCLI(`build --aot --project=my-dir-${myapp}`);
|
|
||||||
expectTestsPass(
|
|
||||||
await runCLIAsync(`test --project=my-dir-${myapp} --no-watch`)
|
|
||||||
);
|
|
||||||
}, 1000000);
|
|
||||||
});
|
|
||||||
@ -4,9 +4,11 @@ import {
|
|||||||
runCLIAsync,
|
runCLIAsync,
|
||||||
uniq,
|
uniq,
|
||||||
ensureProject,
|
ensureProject,
|
||||||
readJson
|
readJson,
|
||||||
|
forEachCli
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
|
forEachCli(() => {
|
||||||
describe('ngrx', () => {
|
describe('ngrx', () => {
|
||||||
it('should work', async () => {
|
it('should work', async () => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
@ -31,7 +33,9 @@ describe('ngrx', () => {
|
|||||||
`generate @nrwl/angular:ngrx flights --module=libs/${mylib}/src/lib/${mylib}.module.ts --facade`
|
`generate @nrwl/angular:ngrx flights --module=libs/${mylib}/src/lib/${mylib}.module.ts --facade`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main-es2015.js,');
|
expect(runCLI(`build ${myapp}`)).toContain(
|
||||||
|
'chunk {main} main-es2015.js,'
|
||||||
|
);
|
||||||
expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main-es5.js,');
|
expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main-es5.js,');
|
||||||
expectTestsPass(await runCLIAsync(`test ${myapp} --no-watch`));
|
expectTestsPass(await runCLIAsync(`test ${myapp} --no-watch`));
|
||||||
expectTestsPass(await runCLIAsync(`test ${mylib} --no-watch`));
|
expectTestsPass(await runCLIAsync(`test ${mylib} --no-watch`));
|
||||||
@ -62,9 +66,12 @@ describe('ngrx', () => {
|
|||||||
`generate @nrwl/angular:ngrx flights --module=libs/${mylib}/src/lib/${mylib}.module.ts --facade --syntax=creators`
|
`generate @nrwl/angular:ngrx flights --module=libs/${mylib}/src/lib/${mylib}.module.ts --facade --syntax=creators`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main-es2015.js,');
|
expect(runCLI(`build ${myapp}`)).toContain(
|
||||||
|
'chunk {main} main-es2015.js,'
|
||||||
|
);
|
||||||
expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main-es5.js,');
|
expect(runCLI(`build ${myapp}`)).toContain('chunk {main} main-es5.js,');
|
||||||
expectTestsPass(await runCLIAsync(`test ${myapp} --no-watch`));
|
expectTestsPass(await runCLIAsync(`test ${myapp} --no-watch`));
|
||||||
expectTestsPass(await runCLIAsync(`test ${mylib} --no-watch`));
|
expectTestsPass(await runCLIAsync(`test ${mylib} --no-watch`));
|
||||||
}, 1000000);
|
}, 1000000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -9,7 +9,11 @@ import {
|
|||||||
runCLI,
|
runCLI,
|
||||||
runCLIAsync,
|
runCLIAsync,
|
||||||
uniq,
|
uniq,
|
||||||
updateFile
|
updateFile,
|
||||||
|
forEachCli,
|
||||||
|
checkFilesExist,
|
||||||
|
tmpProjPath,
|
||||||
|
workspaceConfigName
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
function getData(): Promise<any> {
|
function getData(): Promise<any> {
|
||||||
@ -27,8 +31,9 @@ function getData(): Promise<any> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forEachCli(() => {
|
||||||
describe('Node Applications', () => {
|
describe('Node Applications', () => {
|
||||||
fit('should be able to generate an express application', async done => {
|
it('should be able to generate an express application', async done => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
const nodeapp = uniq('nodeapp');
|
const nodeapp = uniq('nodeapp');
|
||||||
runCLI(`generate @nrwl/express:app ${nodeapp}`);
|
runCLI(`generate @nrwl/express:app ${nodeapp}`);
|
||||||
@ -49,23 +54,22 @@ describe('Node Applications', () => {
|
|||||||
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||||
await runCLIAsync(`build ${nodeapp}`);
|
await runCLIAsync(`build ${nodeapp}`);
|
||||||
|
|
||||||
expect(exists(`./tmp/proj/dist/apps/${nodeapp}/main.js`)).toBeTruthy();
|
checkFilesExist(
|
||||||
expect(
|
`dist/apps/${nodeapp}/main.js`,
|
||||||
exists(`./tmp/proj/dist/apps/${nodeapp}/assets/file.txt`)
|
`dist/apps/${nodeapp}/assets/file.txt`,
|
||||||
).toBeTruthy();
|
`dist/apps/${nodeapp}/main.js.map`
|
||||||
expect(exists(`./tmp/proj/dist/apps/${nodeapp}/main.js.map`)).toBeTruthy();
|
|
||||||
const server = fork(
|
|
||||||
path.join(__dirname, '../../tmp/proj', `./dist/apps/${nodeapp}/main.js`),
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
cwd: './tmp/proj',
|
|
||||||
silent: true
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const server = fork(`./dist/apps/${nodeapp}/main.js`, [], {
|
||||||
|
cwd: tmpProjPath(),
|
||||||
|
silent: true
|
||||||
|
});
|
||||||
expect(server).toBeTruthy();
|
expect(server).toBeTruthy();
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
server.stdout.once('data', async data => {
|
server.stdout.once('data', async data => {
|
||||||
expect(data.toString()).toContain('Listening at http://localhost:3333');
|
expect(data.toString()).toContain(
|
||||||
|
'Listening at http://localhost:3333'
|
||||||
|
);
|
||||||
const result = await getData();
|
const result = await getData();
|
||||||
|
|
||||||
expect(result.message).toEqual(`Welcome to ${nodeapp}!`);
|
expect(result.message).toEqual(`Welcome to ${nodeapp}!`);
|
||||||
@ -75,7 +79,7 @@ describe('Node Applications', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const config = readJson('angular.json');
|
const config = readJson(workspaceConfigName());
|
||||||
config.projects[nodeapp].architect.waitAndPrint = {
|
config.projects[nodeapp].architect.waitAndPrint = {
|
||||||
builder: '@nrwl/workspace:run-commands',
|
builder: '@nrwl/workspace:run-commands',
|
||||||
options: {
|
options: {
|
||||||
@ -87,15 +91,16 @@ describe('Node Applications', () => {
|
|||||||
readyWhen: 'DONE'
|
readyWhen: 'DONE'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
config.projects[nodeapp].architect.serve.options.waitUntilTargets = [
|
config.projects[nodeapp].architect.serve.options.waitUntilTargets = [
|
||||||
`${nodeapp}:waitAndPrint`
|
`${nodeapp}:waitAndPrint`
|
||||||
];
|
];
|
||||||
updateFile('angular.json', JSON.stringify(config));
|
updateFile(workspaceConfigName(), JSON.stringify(config));
|
||||||
const process = spawn(
|
const process = spawn(
|
||||||
'node',
|
'node',
|
||||||
['./node_modules/.bin/ng', 'serve', nodeapp],
|
['./node_modules/.bin/nx', 'serve', nodeapp],
|
||||||
{
|
{
|
||||||
cwd: './tmp/proj'
|
cwd: tmpProjPath()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
let collectedOutput = '';
|
let collectedOutput = '';
|
||||||
@ -126,20 +131,16 @@ describe('Node Applications', () => {
|
|||||||
|
|
||||||
await runCLIAsync(`build ${nestapp}`);
|
await runCLIAsync(`build ${nestapp}`);
|
||||||
|
|
||||||
expect(exists(`./tmp/proj/dist/apps/${nestapp}/main.js`)).toBeTruthy();
|
checkFilesExist(
|
||||||
expect(
|
`dist/apps/${nestapp}/main.js`,
|
||||||
exists(`./tmp/proj/dist/apps/${nestapp}/assets/file.txt`)
|
`dist/apps/${nestapp}/assets/file.txt`,
|
||||||
).toBeTruthy();
|
`dist/apps/${nestapp}/main.js.map`
|
||||||
expect(exists(`./tmp/proj/dist/apps/${nestapp}/main.js.map`)).toBeTruthy();
|
|
||||||
|
|
||||||
const server = fork(
|
|
||||||
path.join(__dirname, '../../tmp/proj', `./dist/apps/${nestapp}/main.js`),
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
cwd: './tmp/proj',
|
|
||||||
silent: true
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const server = fork(`./dist/apps/${nestapp}/main.js`, [], {
|
||||||
|
cwd: tmpProjPath(),
|
||||||
|
silent: true
|
||||||
|
});
|
||||||
expect(server).toBeTruthy();
|
expect(server).toBeTruthy();
|
||||||
|
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
@ -159,9 +160,9 @@ describe('Node Applications', () => {
|
|||||||
|
|
||||||
const process = spawn(
|
const process = spawn(
|
||||||
'node',
|
'node',
|
||||||
['./node_modules/.bin/ng', 'serve', nestapp],
|
['./node_modules/.bin/nx', 'serve', nestapp],
|
||||||
{
|
{
|
||||||
cwd: './tmp/proj'
|
cwd: tmpProjPath()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -185,10 +186,12 @@ describe('Node Applications', () => {
|
|||||||
runCLI(`generate @nrwl/node:app ${nodeapp}`);
|
runCLI(`generate @nrwl/node:app ${nodeapp}`);
|
||||||
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
||||||
await runCLIAsync(`build ${nodeapp}`);
|
await runCLIAsync(`build ${nodeapp}`);
|
||||||
expect(exists(`./tmp/proj/dist/apps/${nodeapp}/main.js`)).toBeTruthy();
|
|
||||||
|
checkFilesExist(`dist/apps/${nodeapp}/main.js`);
|
||||||
const result = execSync(`node dist/apps/${nodeapp}/main.js`, {
|
const result = execSync(`node dist/apps/${nodeapp}/main.js`, {
|
||||||
cwd: './tmp/proj'
|
cwd: tmpProjPath()
|
||||||
}).toString();
|
}).toString();
|
||||||
expect(result).toContain('Hello World!');
|
expect(result).toContain('Hello World!');
|
||||||
}, 30000);
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -7,10 +7,14 @@ import {
|
|||||||
runCLIAsync,
|
runCLIAsync,
|
||||||
checkFilesExist,
|
checkFilesExist,
|
||||||
renameFile,
|
renameFile,
|
||||||
readJson
|
readJson,
|
||||||
|
forEachCli,
|
||||||
|
supportUi,
|
||||||
|
workspaceConfigName
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import { serializeJson } from '@nrwl/workspace';
|
import { serializeJson } from '@nrwl/workspace';
|
||||||
|
|
||||||
|
forEachCli(() => {
|
||||||
describe('React Applications', () => {
|
describe('React Applications', () => {
|
||||||
it('should be able to generate a react app + lib', async () => {
|
it('should be able to generate a react app + lib', async () => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
@ -52,7 +56,10 @@ describe('React Applications', () => {
|
|||||||
runCLI(`generate @nrwl/react:app ${appName} --no-interactive`);
|
runCLI(`generate @nrwl/react:app ${appName} --no-interactive`);
|
||||||
runCLI(`generate @nrwl/react:lib ${libName} --no-interactive`);
|
runCLI(`generate @nrwl/react:lib ${libName} --no-interactive`);
|
||||||
|
|
||||||
renameFile(`apps/${appName}/src/main.tsx`, `apps/${appName}/src/main.jsx`);
|
renameFile(
|
||||||
|
`apps/${appName}/src/main.tsx`,
|
||||||
|
`apps/${appName}/src/main.jsx`
|
||||||
|
);
|
||||||
renameFile(
|
renameFile(
|
||||||
`apps/${appName}/src/app/app.tsx`,
|
`apps/${appName}/src/app/app.tsx`,
|
||||||
`apps/${appName}/src/app/app.jsx`
|
`apps/${appName}/src/app/app.jsx`
|
||||||
@ -65,7 +72,7 @@ describe('React Applications', () => {
|
|||||||
`apps/${appName}/src/polyfills.ts`,
|
`apps/${appName}/src/polyfills.ts`,
|
||||||
`apps/${appName}/src/polyfills.js`
|
`apps/${appName}/src/polyfills.js`
|
||||||
);
|
);
|
||||||
const angularJson = readJson('angular.json');
|
const angularJson = readJson(workspaceConfigName());
|
||||||
|
|
||||||
angularJson.projects[
|
angularJson.projects[
|
||||||
appName
|
appName
|
||||||
@ -73,7 +80,7 @@ describe('React Applications', () => {
|
|||||||
angularJson.projects[
|
angularJson.projects[
|
||||||
appName
|
appName
|
||||||
].architect.build.options.polyfills = `apps/${appName}/src/polyfills.js`;
|
].architect.build.options.polyfills = `apps/${appName}/src/polyfills.js`;
|
||||||
updateFile('angular.json', serializeJson(angularJson));
|
updateFile(workspaceConfigName(), serializeJson(angularJson));
|
||||||
|
|
||||||
const mainPath = `apps/${appName}/src/main.jsx`;
|
const mainPath = `apps/${appName}/src/main.jsx`;
|
||||||
updateFile(mainPath, `import '@proj/${libName}';\n` + readFile(mainPath));
|
updateFile(mainPath, `import '@proj/${libName}';\n` + readFile(mainPath));
|
||||||
@ -120,7 +127,11 @@ describe('React Applications', () => {
|
|||||||
expect(testResults.stderr).toContain('Test Suites: 1 passed, 1 total');
|
expect(testResults.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||||
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
||||||
expect(lintE2eResults).toContain('All files pass linting.');
|
expect(lintE2eResults).toContain('All files pass linting.');
|
||||||
|
|
||||||
|
if (supportUi()) {
|
||||||
const e2eResults = runCLI(`e2e ${appName}-e2e`);
|
const e2eResults = runCLI(`e2e ${appName}-e2e`);
|
||||||
expect(e2eResults).toContain('All specs passed!');
|
expect(e2eResults).toContain('All specs passed!');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,17 +1,18 @@
|
|||||||
import {
|
import {
|
||||||
ensureProject,
|
ensureProject,
|
||||||
patchKarmaToWorkOnWSL,
|
|
||||||
runCLI,
|
runCLI,
|
||||||
uniq,
|
uniq,
|
||||||
updateFile
|
updateFile,
|
||||||
|
forEachCli,
|
||||||
|
supportUi
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
describe('Upgrade', () => {
|
forEachCli(() => {
|
||||||
|
xdescribe('Upgrade', () => {
|
||||||
it('should generate an UpgradeModule setup', async () => {
|
it('should generate an UpgradeModule setup', async () => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
const myapp = uniq('myapp');
|
const myapp = uniq('myapp');
|
||||||
runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner=karma`);
|
runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner=karma`);
|
||||||
patchKarmaToWorkOnWSL();
|
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${myapp}/src/legacy.js`,
|
`apps/${myapp}/src/legacy.js`,
|
||||||
@ -38,6 +39,9 @@ describe('Upgrade', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`build ${myapp}`);
|
runCLI(`build ${myapp}`);
|
||||||
|
if (supportUi()) {
|
||||||
expect(runCLI(`test ${myapp} --no-watch`)).toContain('1 SUCCESS');
|
expect(runCLI(`test ${myapp} --no-watch`)).toContain('1 SUCCESS');
|
||||||
|
}
|
||||||
}, 1000000);
|
}, 1000000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
217
e2e/utils.ts
217
e2e/utils.ts
@ -3,57 +3,107 @@ import { readFileSync, statSync, writeFileSync, renameSync } from 'fs';
|
|||||||
import { ensureDirSync } from 'fs-extra';
|
import { ensureDirSync } from 'fs-extra';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
const projectName: string = 'proj';
|
export let cli;
|
||||||
|
|
||||||
export function uniq(prefix: string) {
|
export function uniq(prefix: string) {
|
||||||
return `${prefix}${Math.floor(Math.random() * 10000000)}`;
|
return `${prefix}${Math.floor(Math.random() * 10000000)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function patchPackageJsonDeps() {
|
export function forEachCli(
|
||||||
const p = readFileSync('./tmp/proj/package.json').toString();
|
selectedCliOrFunction: string | Function,
|
||||||
|
callback?: Function
|
||||||
|
) {
|
||||||
|
let clis;
|
||||||
|
if (process.env.SELECTED_CLI && selectedCliOrFunction && callback) {
|
||||||
|
if (selectedCliOrFunction == process.env.SELECTED_CLI) {
|
||||||
|
clis = [process.env.SELECTED_CLI];
|
||||||
|
} else {
|
||||||
|
clis = [];
|
||||||
|
}
|
||||||
|
} else if (process.env.SELECTED_CLI) {
|
||||||
|
clis = [process.env.SELECTED_CLI];
|
||||||
|
} else {
|
||||||
|
clis = callback ? [selectedCliOrFunction] : ['nx', 'angular'];
|
||||||
|
}
|
||||||
|
|
||||||
|
const cb: any = callback ? callback : selectedCliOrFunction;
|
||||||
|
clis.forEach(c => {
|
||||||
|
describe(`[${c}]`, () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cli = c;
|
||||||
|
});
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function workspaceConfigName() {
|
||||||
|
return cli === 'angular' ? 'angular.json' : 'workspace.json';
|
||||||
|
}
|
||||||
|
|
||||||
|
function patchPackageJsonDeps(addWorkspace = true) {
|
||||||
|
const p = JSON.parse(readFileSync(tmpProjPath('package.json')).toString());
|
||||||
const workspacePath = path.join(getCwd(), 'build', 'packages', 'workspace');
|
const workspacePath = path.join(getCwd(), 'build', 'packages', 'workspace');
|
||||||
const angularPath = path.join(getCwd(), 'build', 'packages', 'angular');
|
const angularPath = path.join(getCwd(), 'build', 'packages', 'angular');
|
||||||
writeFileSync(
|
const reactPath = path.join(getCwd(), 'build', 'packages', 'react');
|
||||||
'./tmp/proj/package.json',
|
|
||||||
p
|
if (addWorkspace) {
|
||||||
.replace(
|
p.devDependencies['@nrwl/workspace'] = `file:${workspacePath}`;
|
||||||
'"@nrwl/workspace": "*"',
|
}
|
||||||
`"@nrwl/workspace": "file:${workspacePath}"`
|
p.devDependencies['@nrwl/angular'] = `file:${angularPath}`;
|
||||||
)
|
p.devDependencies['@nrwl/react'] = `file:${reactPath}`;
|
||||||
.replace('"@nrwl/angular": "*"', `"@nrwl/angular": "file:${angularPath}"`)
|
writeFileSync(tmpProjPath('package.json'), JSON.stringify(p, null, 2));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function runYarnInstall(silent: boolean = true) {
|
function runYarnInstall(silent: boolean = true) {
|
||||||
const install = execSync('yarn install', {
|
const install = execSync('yarn install', {
|
||||||
cwd: './tmp/proj',
|
cwd: tmpProjPath(),
|
||||||
...(silent ? { stdio: ['ignore', 'ignore', 'ignore'] } : {})
|
...(silent ? { stdio: ['ignore', 'ignore', 'ignore'] } : {})
|
||||||
});
|
});
|
||||||
return install ? install.toString() : '';
|
return install ? install.toString() : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runNgNew(command?: string, silent?: boolean): string {
|
export function runNew(
|
||||||
const gen = execSync(
|
command?: string,
|
||||||
`../node_modules/.bin/ng new proj --no-interactive --skip-install ${command ||
|
silent?: boolean,
|
||||||
|
addWorkspace = true
|
||||||
|
): string {
|
||||||
|
let gen;
|
||||||
|
if (cli === 'angular') {
|
||||||
|
gen = execSync(
|
||||||
|
`../../node_modules/.bin/ng new proj --no-interactive --skip-install ${command ||
|
||||||
''}`,
|
''}`,
|
||||||
{
|
{
|
||||||
cwd: `./tmp`,
|
cwd: `./tmp/${cli}`,
|
||||||
...(silent ? { stdio: ['ignore', 'ignore', 'ignore'] } : {})
|
...(silent ? { stdio: ['ignore', 'ignore', 'ignore'] } : {})
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
patchPackageJsonDeps();
|
} else {
|
||||||
const install = runYarnInstall(silent);
|
gen = execSync(
|
||||||
|
`node ../../node_modules/@nrwl/tao/index.js new proj --no-interactive --skip-install ${command ||
|
||||||
|
''}`,
|
||||||
|
{
|
||||||
|
cwd: `./tmp/${cli}`,
|
||||||
|
...(silent && false ? { stdio: ['ignore', 'ignore', 'ignore'] } : {})
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
patchPackageJsonDeps(addWorkspace);
|
||||||
|
const install = runYarnInstall(silent && false);
|
||||||
return silent ? null : `${gen ? gen.toString() : ''}${install}`;
|
return silent ? null : `${gen ? gen.toString() : ''}${install}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function newProject(): void {
|
export function newProject(): void {
|
||||||
cleanup();
|
cleanup();
|
||||||
if (!directoryExists('./tmp/proj_backup')) {
|
if (!directoryExists(tmpBackupProjPath())) {
|
||||||
runNgNew('--collection=@nrwl/workspace --npmScope=proj', true);
|
runNew('--collection=@nrwl/workspace --npmScope=proj', true);
|
||||||
copyMissingPackages();
|
copyMissingPackages();
|
||||||
|
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
'./tmp/proj/node_modules/@angular-devkit/schematics/tasks/node-package/executor.js',
|
tmpProjPath(
|
||||||
|
'node_modules/@angular-devkit/schematics/tasks/node-package/executor.js'
|
||||||
|
),
|
||||||
`
|
`
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
@ -67,45 +117,28 @@ function default_1(factoryOptions = {}) {
|
|||||||
}
|
}
|
||||||
exports.default = default_1;`
|
exports.default = default_1;`
|
||||||
);
|
);
|
||||||
runCLI('add @nrwl/jest');
|
|
||||||
runCLI('add @nrwl/cypress');
|
execSync(`mv ${tmpProjPath()} ${tmpBackupProjPath()}`);
|
||||||
runCLI('add @nrwl/web');
|
|
||||||
runCLI('add @nrwl/react');
|
|
||||||
runCLI('add @nrwl/angular');
|
|
||||||
runCLI('add @nrwl/node');
|
|
||||||
runCLI('add @nrwl/express');
|
|
||||||
runCLI('add @nrwl/nest');
|
|
||||||
execSync('mv ./tmp/proj ./tmp/proj_backup');
|
|
||||||
}
|
}
|
||||||
execSync('cp -a ./tmp/proj_backup ./tmp/proj');
|
execSync(`cp -a ${tmpBackupProjPath()} ${tmpProjPath()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureProject(): void {
|
export function ensureProject(): void {
|
||||||
if (!directoryExists('./tmp/proj')) {
|
if (!directoryExists(tmpProjPath())) {
|
||||||
newProject();
|
newProject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runsInWSL() {
|
export function supportUi() {
|
||||||
return !!process.env['WINDOWSTMP'];
|
// powershell => wsl => no ui for now
|
||||||
}
|
|
||||||
|
|
||||||
export function patchKarmaToWorkOnWSL(): void {
|
|
||||||
try {
|
try {
|
||||||
const karma = readFile('karma.conf.js');
|
execSync(`powershell.exe echo 1`, {
|
||||||
if (process.env['WINDOWSTMP']) {
|
stdio: ['ignore', 'ignore', 'ignore']
|
||||||
updateFile(
|
});
|
||||||
'karma.conf.js',
|
return false;
|
||||||
karma.replace(
|
} catch (e) {
|
||||||
`const { constants } = require('karma');`,
|
return true;
|
||||||
`
|
|
||||||
const { constants } = require('karma');
|
|
||||||
process.env['TMPDIR']="${process.env['WINDOWSTMP']}";
|
|
||||||
`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function copyMissingPackages(): void {
|
export function copyMissingPackages(): void {
|
||||||
@ -150,7 +183,7 @@ export function copyMissingPackages(): void {
|
|||||||
|
|
||||||
'document-register-element'
|
'document-register-element'
|
||||||
];
|
];
|
||||||
modulesToCopy.forEach(m => copyNodeModule(projectName, m));
|
modulesToCopy.forEach(m => copyNodeModule(m));
|
||||||
updateFile(
|
updateFile(
|
||||||
'node_modules/@angular-devkit/schematics/tasks/node-package/executor.js',
|
'node_modules/@angular-devkit/schematics/tasks/node-package/executor.js',
|
||||||
`
|
`
|
||||||
@ -167,17 +200,18 @@ export function copyMissingPackages(): void {
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
execSync('rm -rf tmp/proj/node_modules/.bin/webpack');
|
execSync(`rm -rf ${tmpProjPath('node_modules/.bin/webpack')}`);
|
||||||
execSync(
|
execSync(
|
||||||
`cp -a node_modules/.bin/webpack tmp/proj/node_modules/.bin/webpack`
|
`cp -a node_modules/.bin/webpack ${tmpProjPath(
|
||||||
|
'node_modules/.bin/webpack'
|
||||||
|
)}`
|
||||||
);
|
);
|
||||||
execSync(`rm -rf ./tmp/proj/node_modules/cypress/node_modules/@types`);
|
execSync(`rm -rf ${tmpProjPath('node_modules/cypress/node_modules/@types')}`);
|
||||||
execSync(`rm -rf ./tmp/proj/@types/sinon-chai/node_modules/@types`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyNodeModule(path: string, name: string) {
|
function copyNodeModule(name: string) {
|
||||||
execSync(`rm -rf tmp/${path}/node_modules/${name}`);
|
execSync(`rm -rf ${tmpProjPath('node_modules/' + name)}`);
|
||||||
execSync(`cp -a node_modules/${name} tmp/${path}/node_modules/${name}`);
|
execSync(`cp -a node_modules/${name} ${tmpProjPath('node_modules/' + name)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runCommandAsync(
|
export function runCommandAsync(
|
||||||
@ -190,7 +224,7 @@ export function runCommandAsync(
|
|||||||
exec(
|
exec(
|
||||||
command,
|
command,
|
||||||
{
|
{
|
||||||
cwd: `./tmp/proj`
|
cwd: tmpProjPath()
|
||||||
},
|
},
|
||||||
(err, stdout, stderr) => {
|
(err, stdout, stderr) => {
|
||||||
if (!opts.silenceError && err) {
|
if (!opts.silenceError && err) {
|
||||||
@ -208,7 +242,35 @@ export function runCLIAsync(
|
|||||||
silenceError: false
|
silenceError: false
|
||||||
}
|
}
|
||||||
): Promise<{ stdout: string; stderr: string }> {
|
): Promise<{ stdout: string; stderr: string }> {
|
||||||
return runCommandAsync(`./node_modules/.bin/ng ${command}`, opts);
|
return runCommandAsync(
|
||||||
|
`node ./node_modules/@nrwl/cli/bin/nx.js ${command}`,
|
||||||
|
opts
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runNgAdd(
|
||||||
|
command?: string,
|
||||||
|
opts = {
|
||||||
|
silenceError: false
|
||||||
|
}
|
||||||
|
): string {
|
||||||
|
try {
|
||||||
|
return execSync(`./node_modules/.bin/ng ${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 runCLI(
|
export function runCLI(
|
||||||
@ -218,8 +280,8 @@ export function runCLI(
|
|||||||
}
|
}
|
||||||
): string {
|
): string {
|
||||||
try {
|
try {
|
||||||
return execSync(`./node_modules/.bin/ng ${command}`, {
|
return execSync(`node ./node_modules/@nrwl/cli/bin/nx.js ${command}`, {
|
||||||
cwd: `./tmp/${projectName}`
|
cwd: tmpProjPath()
|
||||||
})
|
})
|
||||||
.toString()
|
.toString()
|
||||||
.replace(
|
.replace(
|
||||||
@ -244,7 +306,7 @@ export function expectTestsPass(v: { stdout: string; stderr: string }) {
|
|||||||
export function runCommand(command: string): string {
|
export function runCommand(command: string): string {
|
||||||
try {
|
try {
|
||||||
return execSync(command, {
|
return execSync(command, {
|
||||||
cwd: `./tmp/${projectName}`,
|
cwd: tmpProjPath(),
|
||||||
stdio: ['pipe', 'pipe', 'pipe']
|
stdio: ['pipe', 'pipe', 'pipe']
|
||||||
}).toString();
|
}).toString();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -253,23 +315,18 @@ export function runCommand(command: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function updateFile(f: string, content: string): void {
|
export function updateFile(f: string, content: string): void {
|
||||||
ensureDirSync(path.dirname(path.join(getCwd(), 'tmp', 'proj', f)));
|
ensureDirSync(path.dirname(tmpProjPath(f)));
|
||||||
writeFileSync(path.join(getCwd(), 'tmp', 'proj', f), content);
|
writeFileSync(tmpProjPath(f), content);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renameFile(f: string, newPath: string): void {
|
export function renameFile(f: string, newPath: string): void {
|
||||||
ensureDirSync(path.dirname(path.join(getCwd(), 'tmp', 'proj', newPath)));
|
ensureDirSync(path.dirname(tmpProjPath(newPath)));
|
||||||
renameSync(
|
renameSync(tmpProjPath(f), tmpProjPath(newPath));
|
||||||
path.join(getCwd(), 'tmp', 'proj', f),
|
|
||||||
path.join(getCwd(), 'tmp', 'proj', newPath)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkFilesExist(...expectedFiles: string[]) {
|
export function checkFilesExist(...expectedFiles: string[]) {
|
||||||
expectedFiles.forEach(f => {
|
expectedFiles.forEach(f => {
|
||||||
const ff = f.startsWith('/')
|
const ff = f.startsWith('/') ? f : tmpProjPath(f);
|
||||||
? f
|
|
||||||
: path.join(getCwd(), 'tmp', projectName, f);
|
|
||||||
if (!exists(ff)) {
|
if (!exists(ff)) {
|
||||||
throw new Error(`File '${ff}' does not exist`);
|
throw new Error(`File '${ff}' does not exist`);
|
||||||
}
|
}
|
||||||
@ -281,12 +338,12 @@ export function readJson(f: string): any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function readFile(f: string) {
|
export function readFile(f: string) {
|
||||||
const ff = f.startsWith('/') ? f : path.join(getCwd(), 'tmp', projectName, f);
|
const ff = f.startsWith('/') ? f : tmpProjPath(f);
|
||||||
return readFileSync(ff).toString();
|
return readFileSync(ff).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cleanup() {
|
export function cleanup() {
|
||||||
execSync('rm -rf ./tmp/proj');
|
execSync(`rm -rf ${tmpProjPath()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCwd(): string {
|
export function getCwd(): string {
|
||||||
@ -316,3 +373,11 @@ export function exists(filePath: string): boolean {
|
|||||||
export function getSize(filePath: string): number {
|
export function getSize(filePath: string): number {
|
||||||
return statSync(filePath).size;
|
return statSync(filePath).size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tmpProjPath(path?: string) {
|
||||||
|
return path ? `./tmp/${cli}/proj/${path}` : `./tmp/${cli}/proj`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tmpBackupProjPath(path?: string) {
|
||||||
|
return path ? `./tmp/${cli}/proj-backup/${path}` : `./tmp/${cli}/proj-backup`;
|
||||||
|
}
|
||||||
|
|||||||
@ -4,9 +4,12 @@ import {
|
|||||||
readFile,
|
readFile,
|
||||||
runCLI,
|
runCLI,
|
||||||
runCLIAsync,
|
runCLIAsync,
|
||||||
uniq
|
uniq,
|
||||||
|
forEachCli,
|
||||||
|
supportUi
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
|
forEachCli(() => {
|
||||||
describe('Web Components Applications', () => {
|
describe('Web Components Applications', () => {
|
||||||
it('should be able to generate a web app', async () => {
|
it('should be able to generate a web app', async () => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
@ -54,3 +57,4 @@ describe('Web Components Applications', () => {
|
|||||||
expect(e2eResults).toContain('All specs passed!');
|
expect(e2eResults).toContain('All specs passed!');
|
||||||
}, 120000);
|
}, 120000);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -49,7 +49,7 @@
|
|||||||
"@ngrx/schematics": "8.1.0",
|
"@ngrx/schematics": "8.1.0",
|
||||||
"@ngrx/store": "8.1.0",
|
"@ngrx/store": "8.1.0",
|
||||||
"@ngrx/store-devtools": "8.1.0",
|
"@ngrx/store-devtools": "8.1.0",
|
||||||
"@schematics/angular": "8.0.0",
|
"@schematics/angular": "8.1.1",
|
||||||
"@testing-library/react": "8.0.5",
|
"@testing-library/react": "8.0.5",
|
||||||
"@types/express": "4.16.0",
|
"@types/express": "4.16.0",
|
||||||
"@types/jasmine": "~2.8.6",
|
"@types/jasmine": "~2.8.6",
|
||||||
@ -94,7 +94,7 @@
|
|||||||
"karma-jasmine-html-reporter": "^0.2.2",
|
"karma-jasmine-html-reporter": "^0.2.2",
|
||||||
"karma-webpack": "2.0.4",
|
"karma-webpack": "2.0.4",
|
||||||
"license-webpack-plugin": "^1.4.0",
|
"license-webpack-plugin": "^1.4.0",
|
||||||
"ng-packagr": "5.1.0",
|
"ng-packagr": "5.3.0",
|
||||||
"ngrx-store-freeze": "0.2.4",
|
"ngrx-store-freeze": "0.2.4",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"opn": "^5.3.0",
|
"opn": "^5.3.0",
|
||||||
|
|||||||
@ -13,27 +13,27 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('not nested', () => {
|
describe('not nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-app'].root).toEqual('apps/my-app');
|
expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app');
|
||||||
expect(angularJson.projects['my-app-e2e'].root).toEqual(
|
expect(workspaceJson.projects['my-app-e2e'].root).toEqual(
|
||||||
'apps/my-app-e2e'
|
'apps/my-app-e2e'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-app'].architect.lint.options.exclude
|
workspaceJson.projects['my-app'].architect.lint.options.exclude
|
||||||
).toEqual(['**/node_modules/**', '!apps/my-app/**']);
|
).toEqual(['**/node_modules/**', '!apps/my-app/**']);
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-app-e2e'].architect.lint.options.exclude
|
workspaceJson.projects['my-app-e2e'].architect.lint.options.exclude
|
||||||
).toEqual(['**/node_modules/**', '!apps/my-app-e2e/**']);
|
).toEqual(['**/node_modules/**', '!apps/my-app-e2e/**']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove the e2e target on the application', async () => {
|
it('should remove the e2e target on the application', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
expect(angularJson.projects['my-app'].architect.e2e).not.toBeDefined();
|
expect(workspaceJson.projects['my-app'].architect.e2e).not.toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
it('should update nx.json', async () => {
|
||||||
@ -107,8 +107,10 @@ describe('app', () => {
|
|||||||
let appE2eSpec = noPrefix
|
let appE2eSpec = noPrefix
|
||||||
.read('apps/my-app-e2e/src/app.e2e-spec.ts')
|
.read('apps/my-app-e2e/src/app.e2e-spec.ts')
|
||||||
.toString();
|
.toString();
|
||||||
let angularJson = JSON.parse(noPrefix.read('angular.json').toString());
|
let workspaceJson = JSON.parse(
|
||||||
let myAppPrefix = angularJson.projects['my-app'].prefix;
|
noPrefix.read('workspace.json').toString()
|
||||||
|
);
|
||||||
|
let myAppPrefix = workspaceJson.projects['my-app'].prefix;
|
||||||
|
|
||||||
expect(myAppPrefix).toEqual('proj');
|
expect(myAppPrefix).toEqual('proj');
|
||||||
expect(appE2eSpec).toContain('Welcome to my-app!');
|
expect(appE2eSpec).toContain('Welcome to my-app!');
|
||||||
@ -118,8 +120,8 @@ describe('app', () => {
|
|||||||
appE2eSpec = withPrefix
|
appE2eSpec = withPrefix
|
||||||
.read('apps/my-app-e2e/src/app.e2e-spec.ts')
|
.read('apps/my-app-e2e/src/app.e2e-spec.ts')
|
||||||
.toString();
|
.toString();
|
||||||
angularJson = JSON.parse(withPrefix.read('angular.json').toString());
|
workspaceJson = JSON.parse(withPrefix.read('workspace.json').toString());
|
||||||
myAppPrefix = angularJson.projects['my-app'].prefix;
|
myAppPrefix = workspaceJson.projects['my-app'].prefix;
|
||||||
|
|
||||||
expect(myAppPrefix).toEqual('custom');
|
expect(myAppPrefix).toEqual('custom');
|
||||||
expect(appE2eSpec).toContain('Welcome to my-app!');
|
expect(appE2eSpec).toContain('Welcome to my-app!');
|
||||||
@ -127,7 +129,7 @@ describe('app', () => {
|
|||||||
|
|
||||||
xit('should work if the new project root is changed', async () => {
|
xit('should work if the new project root is changed', async () => {
|
||||||
appTree = await callRule(
|
appTree = await callRule(
|
||||||
updateJsonInTree('/angular.json', json => ({
|
updateJsonInTree('/workspace.json', json => ({
|
||||||
...json,
|
...json,
|
||||||
newProjectRoot: 'newProjectRoot'
|
newProjectRoot: 'newProjectRoot'
|
||||||
})),
|
})),
|
||||||
@ -141,26 +143,27 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('nested', () => {
|
describe('nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'app',
|
'app',
|
||||||
{ name: 'myApp', directory: 'myDir' },
|
{ name: 'myApp', directory: 'myDir' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-dir-my-app'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-app'].root).toEqual(
|
||||||
'apps/my-dir/my-app'
|
'apps/my-dir/my-app'
|
||||||
);
|
);
|
||||||
expect(angularJson.projects['my-dir-my-app-e2e'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-app-e2e'].root).toEqual(
|
||||||
'apps/my-dir/my-app-e2e'
|
'apps/my-dir/my-app-e2e'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-dir-my-app'].architect.lint.options.exclude
|
workspaceJson.projects['my-dir-my-app'].architect.lint.options.exclude
|
||||||
).toEqual(['**/node_modules/**', '!apps/my-dir/my-app/**']);
|
).toEqual(['**/node_modules/**', '!apps/my-dir/my-app/**']);
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-dir-my-app-e2e'].architect.lint.options.exclude
|
workspaceJson.projects['my-dir-my-app-e2e'].architect.lint.options
|
||||||
|
.exclude
|
||||||
).toEqual(['**/node_modules/**', '!apps/my-dir/my-app-e2e/**']);
|
).toEqual(['**/node_modules/**', '!apps/my-dir/my-app-e2e/**']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -314,9 +317,9 @@ describe('app', () => {
|
|||||||
{ name: 'myApp', style: 'scss' },
|
{ name: 'myApp', style: 'scss' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-app'].schematics).toEqual({
|
expect(workspaceJson.projects['my-app'].schematics).toEqual({
|
||||||
'@nrwl/workspace:component': {
|
'@nrwl/workspace:component': {
|
||||||
style: 'scss'
|
style: 'scss'
|
||||||
}
|
}
|
||||||
@ -334,12 +337,12 @@ describe('app', () => {
|
|||||||
|
|
||||||
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeTruthy();
|
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeTruthy();
|
||||||
expect(tree.exists('apps/my-app/karma.conf.js')).toBeTruthy();
|
expect(tree.exists('apps/my-app/karma.conf.js')).toBeTruthy();
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app'].architect.test.builder).toEqual(
|
expect(workspaceJson.projects['my-app'].architect.test.builder).toEqual(
|
||||||
'@angular-devkit/build-angular:karma'
|
'@angular-devkit/build-angular:karma'
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-app'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-app'].architect.lint.options.tsConfig
|
||||||
).toEqual([
|
).toEqual([
|
||||||
'apps/my-app/tsconfig.app.json',
|
'apps/my-app/tsconfig.app.json',
|
||||||
'apps/my-app/tsconfig.spec.json'
|
'apps/my-app/tsconfig.spec.json'
|
||||||
@ -367,26 +370,28 @@ describe('app', () => {
|
|||||||
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeFalsy();
|
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-app/karma.config.js')).toBeFalsy();
|
expect(tree.exists('apps/my-app/karma.config.js')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app'].architect.test).toBeUndefined();
|
expect(workspaceJson.projects['my-app'].architect.test).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-app'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-app'].architect.lint.options.tsConfig
|
||||||
).toEqual(['apps/my-app/tsconfig.app.json']);
|
).toEqual(['apps/my-app/tsconfig.app.json']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('--e2e-test-runner', () => {
|
describe('--e2e-test-runner', () => {
|
||||||
describe('protractor', () => {
|
describe('protractor', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'app',
|
'app',
|
||||||
{ name: 'myApp', e2eTestRunner: 'protractor' },
|
{ name: 'myApp', e2eTestRunner: 'protractor' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app'].architect.e2e).not.toBeDefined();
|
expect(
|
||||||
expect(angularJson.projects['my-app-e2e']).toEqual({
|
workspaceJson.projects['my-app'].architect.e2e
|
||||||
|
).not.toBeDefined();
|
||||||
|
expect(workspaceJson.projects['my-app-e2e']).toEqual({
|
||||||
root: 'apps/my-app-e2e',
|
root: 'apps/my-app-e2e',
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
architect: {
|
architect: {
|
||||||
@ -422,30 +427,30 @@ describe('app', () => {
|
|||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app-e2e']).toBeUndefined();
|
expect(workspaceJson.projects['my-app-e2e']).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('replaceAppNameWithPath', () => {
|
describe('replaceAppNameWithPath', () => {
|
||||||
it('should protect `angular.json` commands and properties', async () => {
|
it('should protect `workspace.json` commands and properties', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'ui' }, appTree);
|
const tree = await runSchematic('app', { name: 'ui' }, appTree);
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['ui']).toBeDefined();
|
expect(workspaceJson.projects['ui']).toBeDefined();
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['ui']['architect']['build']['builder']
|
workspaceJson.projects['ui']['architect']['build']['builder']
|
||||||
).toEqual('@angular-devkit/build-angular:browser');
|
).toEqual('@angular-devkit/build-angular:browser');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should protect `angular.json` sensible properties value to be renamed', async () => {
|
it('should protect `workspace.json` sensible properties value to be renamed', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'app',
|
'app',
|
||||||
{ name: 'ui', prefix: 'ui' },
|
{ name: 'ui', prefix: 'ui' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['ui'].prefix).toEqual('ui');
|
expect(workspaceJson.projects['ui'].prefix).toEqual('ui');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import {
|
|||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {
|
import {
|
||||||
angularSchematicNames,
|
|
||||||
formatFiles,
|
formatFiles,
|
||||||
getNpmScope,
|
getNpmScope,
|
||||||
getWorkspacePath,
|
getWorkspacePath,
|
||||||
@ -26,7 +25,8 @@ import {
|
|||||||
replaceNodeValue,
|
replaceNodeValue,
|
||||||
toFileName,
|
toFileName,
|
||||||
updateJsonInTree,
|
updateJsonInTree,
|
||||||
updateWorkspace
|
updateWorkspace,
|
||||||
|
addGlobalLint
|
||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import { join, normalize } from '@angular-devkit/core';
|
import { join, normalize } from '@angular-devkit/core';
|
||||||
import ngAdd from '../ng-add/ng-add';
|
import ngAdd from '../ng-add/ng-add';
|
||||||
@ -202,6 +202,16 @@ function updateProject(options: NormalizedSchema): Rule {
|
|||||||
options.appProjectRoot
|
options.appProjectRoot
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const angularSchematicNames = [
|
||||||
|
'class',
|
||||||
|
'component',
|
||||||
|
'directive',
|
||||||
|
'guard',
|
||||||
|
'module',
|
||||||
|
'pipe',
|
||||||
|
'service'
|
||||||
|
];
|
||||||
|
|
||||||
if (fixedProject.schematics) {
|
if (fixedProject.schematics) {
|
||||||
angularSchematicNames.forEach(type => {
|
angularSchematicNames.forEach(type => {
|
||||||
const schematic = `@schematics/angular:${type}`;
|
const schematic = `@schematics/angular:${type}`;
|
||||||
@ -345,13 +355,13 @@ export default function(schema: Schema): Rule {
|
|||||||
|
|
||||||
// Determine the roots where @schematics/angular will place the projects
|
// Determine the roots where @schematics/angular will place the projects
|
||||||
// This is not where the projects actually end up
|
// This is not where the projects actually end up
|
||||||
const angularJson = readJsonInTree(host, getWorkspacePath(host));
|
const workspaceJson = readJsonInTree(host, getWorkspacePath(host));
|
||||||
|
|
||||||
const appProjectRoot = angularJson.newProjectRoot
|
const appProjectRoot = workspaceJson.newProjectRoot
|
||||||
? `${angularJson.newProjectRoot}/${options.name}`
|
? `${workspaceJson.newProjectRoot}/${options.name}`
|
||||||
: options.name;
|
: options.name;
|
||||||
const e2eProjectRoot = angularJson.newProjectRoot
|
const e2eProjectRoot = workspaceJson.newProjectRoot
|
||||||
? `${angularJson.newProjectRoot}/${options.e2eProjectName}`
|
? `${workspaceJson.newProjectRoot}/${options.e2eProjectName}`
|
||||||
: `${options.name}/e2e`;
|
: `${options.name}/e2e`;
|
||||||
|
|
||||||
return chain([
|
return chain([
|
||||||
@ -359,6 +369,7 @@ export default function(schema: Schema): Rule {
|
|||||||
...options,
|
...options,
|
||||||
skipFormat: true
|
skipFormat: true
|
||||||
}),
|
}),
|
||||||
|
addGlobalLint('tslint'),
|
||||||
externalSchematic('@schematics/angular', 'application', {
|
externalSchematic('@schematics/angular', 'application', {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
inlineStyle: options.inlineStyle,
|
inlineStyle: options.inlineStyle,
|
||||||
@ -373,11 +384,9 @@ export default function(schema: Schema): Rule {
|
|||||||
skipPackageJson: false
|
skipPackageJson: false
|
||||||
}),
|
}),
|
||||||
addTsconfigs(options),
|
addTsconfigs(options),
|
||||||
|
|
||||||
options.e2eTestRunner === 'protractor'
|
options.e2eTestRunner === 'protractor'
|
||||||
? move(e2eProjectRoot, options.e2eProjectRoot)
|
? move(e2eProjectRoot, options.e2eProjectRoot)
|
||||||
: removeE2e(options, e2eProjectRoot),
|
: removeE2e(options, e2eProjectRoot),
|
||||||
|
|
||||||
options.e2eTestRunner === 'protractor'
|
options.e2eTestRunner === 'protractor'
|
||||||
? updateE2eProject(options)
|
? updateE2eProject(options)
|
||||||
: noop(),
|
: noop(),
|
||||||
@ -388,10 +397,8 @@ export default function(schema: Schema): Rule {
|
|||||||
project: options.name
|
project: options.name
|
||||||
})
|
})
|
||||||
: noop(),
|
: noop(),
|
||||||
|
|
||||||
move(appProjectRoot, options.appProjectRoot),
|
move(appProjectRoot, options.appProjectRoot),
|
||||||
updateProject(options),
|
updateProject(options),
|
||||||
|
|
||||||
updateComponentTemplate(options),
|
updateComponentTemplate(options),
|
||||||
options.routing ? addRouterRootConfiguration(options) : noop(),
|
options.routing ? addRouterRootConfiguration(options) : noop(),
|
||||||
updateLinting(options),
|
updateLinting(options),
|
||||||
|
|||||||
@ -81,7 +81,7 @@ module.exports = function(config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('library', () => {
|
describe('library', () => {
|
||||||
it('should alter angular.json', async () => {
|
it('should alter workspace.json', async () => {
|
||||||
const resultTree = await runSchematic(
|
const resultTree = await runSchematic(
|
||||||
'karma-project',
|
'karma-project',
|
||||||
{
|
{
|
||||||
@ -89,8 +89,8 @@ module.exports = function(config) {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||||
expect(angularJson.projects.lib1.architect.test).toEqual({
|
expect(workspaceJson.projects.lib1.architect.test).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:karma',
|
builder: '@angular-devkit/build-angular:karma',
|
||||||
options: {
|
options: {
|
||||||
main: 'libs/lib1/src/test.ts',
|
main: 'libs/lib1/src/test.ts',
|
||||||
@ -99,7 +99,7 @@ module.exports = function(config) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects.lib1.architect.lint.options.tsConfig
|
workspaceJson.projects.lib1.architect.lint.options.tsConfig
|
||||||
).toContain('libs/lib1/tsconfig.spec.json');
|
).toContain('libs/lib1/tsconfig.spec.json');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ module.exports = function(config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('applications', () => {
|
describe('applications', () => {
|
||||||
it('should alter angular.json', async () => {
|
it('should alter workspace.json', async () => {
|
||||||
const resultTree = await runSchematic(
|
const resultTree = await runSchematic(
|
||||||
'karma-project',
|
'karma-project',
|
||||||
{
|
{
|
||||||
@ -149,8 +149,8 @@ module.exports = function(config) {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||||
expect(angularJson.projects.app1.architect.test).toEqual({
|
expect(workspaceJson.projects.app1.architect.test).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:karma',
|
builder: '@angular-devkit/build-angular:karma',
|
||||||
options: {
|
options: {
|
||||||
main: 'apps/app1/src/test.ts',
|
main: 'apps/app1/src/test.ts',
|
||||||
@ -163,7 +163,7 @@ module.exports = function(config) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects.app1.architect.lint.options.tsConfig
|
workspaceJson.projects.app1.architect.lint.options.tsConfig
|
||||||
).toContain('apps/app1/tsconfig.spec.json');
|
).toContain('apps/app1/tsconfig.spec.json');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
readJsonInTree,
|
readJsonInTree,
|
||||||
updateJsonInTree,
|
updateJsonInTree,
|
||||||
offsetFromRoot
|
offsetFromRoot,
|
||||||
|
updateWorkspaceInTree
|
||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import { join, normalize } from '@angular-devkit/core';
|
import { join, normalize } from '@angular-devkit/core';
|
||||||
import { getProjectConfig } from '@nrwl/workspace';
|
import { getProjectConfig } from '@nrwl/workspace';
|
||||||
@ -76,8 +77,8 @@ function updateTsSpecConfig(options: KarmaProjectSchema): Rule {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAngularJson(options: KarmaProjectSchema): Rule {
|
function updateworkspaceJson(options: KarmaProjectSchema): Rule {
|
||||||
return updateJsonInTree('angular.json', json => {
|
return updateWorkspaceInTree(json => {
|
||||||
const projectConfig = json.projects[options.project];
|
const projectConfig = json.projects[options.project];
|
||||||
projectConfig.architect.test = {
|
projectConfig.architect.test = {
|
||||||
builder: '@angular-devkit/build-angular:karma',
|
builder: '@angular-devkit/build-angular:karma',
|
||||||
@ -124,6 +125,6 @@ export default function(options: KarmaProjectSchema): Rule {
|
|||||||
generateFiles(options),
|
generateFiles(options),
|
||||||
updateTsConfig(options),
|
updateTsConfig(options),
|
||||||
updateTsSpecConfig(options),
|
updateTsSpecConfig(options),
|
||||||
updateAngularJson(options)
|
updateworkspaceJson(options)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,5 +5,5 @@ This library was generated with [Nx](https://nx.dev).
|
|||||||
|
|
||||||
## Running unit tests
|
## Running unit tests
|
||||||
|
|
||||||
Run `ng test <%= name %>` to execute the unit tests.
|
Run `nx test <%= name %>` to execute the unit tests.
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|||||||
@ -79,37 +79,39 @@ describe('lib', () => {
|
|||||||
expect(packageJson.name).toEqual('@proj/my-lib');
|
expect(packageJson.name).toEqual('@proj/my-lib');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'lib',
|
'lib',
|
||||||
{ name: 'myLib', framework: 'angular', publishable: true },
|
{ name: 'myLib', framework: 'angular', publishable: true },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||||
expect(angularJson.projects['my-lib'].architect.build).toBeDefined();
|
expect(workspaceJson.projects['my-lib'].architect.build).toBeDefined();
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-lib'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||||
).toEqual([
|
).toEqual([
|
||||||
'libs/my-lib/tsconfig.lib.json',
|
'libs/my-lib/tsconfig.lib.json',
|
||||||
'libs/my-lib/tsconfig.spec.json'
|
'libs/my-lib/tsconfig.spec.json'
|
||||||
]);
|
]);
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-lib'].architect.lint.options.exclude
|
workspaceJson.projects['my-lib'].architect.lint.options.exclude
|
||||||
).toEqual(['**/node_modules/**', '!libs/my-lib/**']);
|
).toEqual(['**/node_modules/**', '!libs/my-lib/**']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should remove "build" target from angular.json when a library is not publishable', async () => {
|
it('should remove "build" target from workspace.json when a library is not publishable', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'lib',
|
'lib',
|
||||||
{ name: 'myLib', publishable: false },
|
{ name: 'myLib', publishable: false },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||||
expect(angularJson.projects['my-lib'].architect.build).not.toBeDefined();
|
expect(
|
||||||
|
workspaceJson.projects['my-lib'].architect.build
|
||||||
|
).not.toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
it('should update nx.json', async () => {
|
||||||
@ -216,8 +218,9 @@ describe('lib', () => {
|
|||||||
it('should default the prefix to npmScope', async () => {
|
it('should default the prefix to npmScope', async () => {
|
||||||
const noPrefix = await runSchematic('lib', { name: 'myLib' }, appTree);
|
const noPrefix = await runSchematic('lib', { name: 'myLib' }, appTree);
|
||||||
expect(
|
expect(
|
||||||
JSON.parse(noPrefix.read('angular.json').toString()).projects['my-lib']
|
JSON.parse(noPrefix.read('workspace.json').toString()).projects[
|
||||||
.prefix
|
'my-lib'
|
||||||
|
].prefix
|
||||||
).toEqual('proj');
|
).toEqual('proj');
|
||||||
|
|
||||||
const withPrefix = await runSchematic(
|
const withPrefix = await runSchematic(
|
||||||
@ -226,7 +229,7 @@ describe('lib', () => {
|
|||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
JSON.parse(withPrefix.read('angular.json').toString()).projects[
|
JSON.parse(withPrefix.read('workspace.json').toString()).projects[
|
||||||
'my-lib'
|
'my-lib'
|
||||||
].prefix
|
].prefix
|
||||||
).toEqual('custom');
|
).toEqual('custom');
|
||||||
@ -381,26 +384,26 @@ describe('lib', () => {
|
|||||||
expect(ngPackage.dest).toEqual('../../../dist/libs/my-dir/my-lib');
|
expect(ngPackage.dest).toEqual('../../../dist/libs/my-dir/my-lib');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'lib',
|
'lib',
|
||||||
{ name: 'myLib', directory: 'myDir' },
|
{ name: 'myLib', directory: 'myDir' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-dir-my-lib'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-lib'].root).toEqual(
|
||||||
'libs/my-dir/my-lib'
|
'libs/my-dir/my-lib'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-dir-my-lib'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-dir-my-lib'].architect.lint.options.tsConfig
|
||||||
).toEqual([
|
).toEqual([
|
||||||
'libs/my-dir/my-lib/tsconfig.lib.json',
|
'libs/my-dir/my-lib/tsconfig.lib.json',
|
||||||
'libs/my-dir/my-lib/tsconfig.spec.json'
|
'libs/my-dir/my-lib/tsconfig.spec.json'
|
||||||
]);
|
]);
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-dir-my-lib'].architect.lint.options.exclude
|
workspaceJson.projects['my-dir-my-lib'].architect.lint.options.exclude
|
||||||
).toEqual(['**/node_modules/**', '!libs/my-dir/my-lib/**']);
|
).toEqual(['**/node_modules/**', '!libs/my-dir/my-lib/**']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -763,9 +766,9 @@ describe('lib', () => {
|
|||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
|
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-lib'].schematics).toEqual({
|
expect(workspaceJson.projects['my-lib'].schematics).toEqual({
|
||||||
'@nrwl/angular:component': {
|
'@nrwl/angular:component': {
|
||||||
styleext: 'scss'
|
styleext: 'scss'
|
||||||
}
|
}
|
||||||
@ -785,18 +788,18 @@ describe('lib', () => {
|
|||||||
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeTruthy();
|
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeTruthy();
|
||||||
expect(resultTree.exists('libs/my-lib/karma.conf.js')).toBeTruthy();
|
expect(resultTree.exists('libs/my-lib/karma.conf.js')).toBeTruthy();
|
||||||
expect(resultTree.exists('karma.conf.js')).toBeTruthy();
|
expect(resultTree.exists('karma.conf.js')).toBeTruthy();
|
||||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-lib'].architect.test.builder).toEqual(
|
expect(workspaceJson.projects['my-lib'].architect.test.builder).toEqual(
|
||||||
'@angular-devkit/build-angular:karma'
|
'@angular-devkit/build-angular:karma'
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-lib'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||||
).toEqual([
|
).toEqual([
|
||||||
'libs/my-lib/tsconfig.lib.json',
|
'libs/my-lib/tsconfig.lib.json',
|
||||||
'libs/my-lib/tsconfig.spec.json'
|
'libs/my-lib/tsconfig.spec.json'
|
||||||
]);
|
]);
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-lib'].architect.lint.options.exclude
|
workspaceJson.projects['my-lib'].architect.lint.options.exclude
|
||||||
).toEqual(['**/node_modules/**', '!libs/my-lib/**']);
|
).toEqual(['**/node_modules/**', '!libs/my-lib/**']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -816,10 +819,10 @@ describe('lib', () => {
|
|||||||
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy();
|
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy();
|
||||||
expect(resultTree.exists('libs/my-lib/jest.config.js')).toBeFalsy();
|
expect(resultTree.exists('libs/my-lib/jest.config.js')).toBeFalsy();
|
||||||
expect(resultTree.exists('libs/my-lib/karma.conf.js')).toBeFalsy();
|
expect(resultTree.exists('libs/my-lib/karma.conf.js')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-lib'].architect.test).toBeUndefined();
|
expect(workspaceJson.projects['my-lib'].architect.test).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-lib'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||||
).toEqual(['libs/my-lib/tsconfig.lib.json']);
|
).toEqual(['libs/my-lib/tsconfig.lib.json']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -22,7 +22,8 @@ import {
|
|||||||
NxJson,
|
NxJson,
|
||||||
updateJsonInTree,
|
updateJsonInTree,
|
||||||
readJsonInTree,
|
readJsonInTree,
|
||||||
offsetFromRoot
|
offsetFromRoot,
|
||||||
|
addGlobalLint
|
||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import { addGlobal, addIncludeToTsConfig, insert } from '@nrwl/workspace';
|
import { addGlobal, addIncludeToTsConfig, insert } from '@nrwl/workspace';
|
||||||
import { toClassName, toFileName, toPropertyName } from '@nrwl/workspace';
|
import { toClassName, toFileName, toPropertyName } from '@nrwl/workspace';
|
||||||
@ -430,6 +431,7 @@ export default function(schema: Schema): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return chain([
|
return chain([
|
||||||
|
addGlobalLint('tslint'),
|
||||||
addUnitTestRunner(options),
|
addUnitTestRunner(options),
|
||||||
externalSchematic('@schematics/angular', 'library', {
|
externalSchematic('@schematics/angular', 'library', {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
|||||||
@ -74,7 +74,7 @@ describe('ng-add', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const { schematics } = readJsonInTree(tree, 'angular.json');
|
const { schematics } = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(schematics['@nrwl/angular:application'].unitTestRunner).toEqual(
|
expect(schematics['@nrwl/angular:application'].unitTestRunner).toEqual(
|
||||||
'karma'
|
'karma'
|
||||||
);
|
);
|
||||||
@ -118,7 +118,7 @@ describe('ng-add', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const { schematics } = readJsonInTree(tree, 'angular.json');
|
const { schematics } = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(schematics['@nrwl/angular:application'].unitTestRunner).toEqual(
|
expect(schematics['@nrwl/angular:application'].unitTestRunner).toEqual(
|
||||||
'jest'
|
'jest'
|
||||||
);
|
);
|
||||||
@ -153,7 +153,7 @@ describe('ng-add', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const { schematics } = readJsonInTree(tree, 'angular.json');
|
const { schematics } = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(schematics['@nrwl/angular:application'].e2eTestRunner).toEqual(
|
expect(schematics['@nrwl/angular:application'].e2eTestRunner).toEqual(
|
||||||
'cypress'
|
'cypress'
|
||||||
);
|
);
|
||||||
@ -185,7 +185,7 @@ describe('ng-add', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const { schematics } = readJsonInTree(tree, 'angular.json');
|
const { schematics } = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(schematics['@nrwl/angular:application'].e2eTestRunner).toEqual(
|
expect(schematics['@nrwl/angular:application'].e2eTestRunner).toEqual(
|
||||||
'protractor'
|
'protractor'
|
||||||
);
|
);
|
||||||
@ -196,13 +196,13 @@ describe('ng-add', () => {
|
|||||||
describe('defaultCollection', () => {
|
describe('defaultCollection', () => {
|
||||||
it('should be set if none was set before', async () => {
|
it('should be set if none was set before', async () => {
|
||||||
const result = await runSchematic('ng-add', {}, appTree);
|
const result = await runSchematic('ng-add', {}, appTree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be set if @nrwl/workspace was set before', async () => {
|
it('should be set if @nrwl/workspace was set before', async () => {
|
||||||
appTree = await callRule(
|
appTree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/workspace'
|
defaultCollection: '@nrwl/workspace'
|
||||||
};
|
};
|
||||||
@ -212,13 +212,13 @@ describe('ng-add', () => {
|
|||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, appTree);
|
const result = await runSchematic('ng-add', {}, appTree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be set if something else was set before', async () => {
|
it('should not be set if something else was set before', async () => {
|
||||||
appTree = await callRule(
|
appTree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/react'
|
defaultCollection: '@nrwl/react'
|
||||||
};
|
};
|
||||||
@ -228,8 +228,8 @@ describe('ng-add', () => {
|
|||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, appTree);
|
const result = await runSchematic('ng-add', {}, appTree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/react');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/react');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -94,7 +94,7 @@ export function createApp(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
tree.overwrite(
|
tree.overwrite(
|
||||||
'/angular.json',
|
'/workspace.json',
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
newProjectRoot: '',
|
newProjectRoot: '',
|
||||||
version: 1,
|
version: 1,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export const nxVersion = '*';
|
export const nxVersion = '*';
|
||||||
export const angularVersion = '^8.0.0';
|
export const angularVersion = '^8.0.0';
|
||||||
export const angularDevkitVersion = '^0.800.0';
|
export const angularDevkitVersion = '^0.800.1';
|
||||||
export const angularJsVersion = '1.6.6';
|
export const angularJsVersion = '1.6.6';
|
||||||
export const ngrxVersion = '8.1.0';
|
export const ngrxVersion = '8.1.0';
|
||||||
export const rxjsVersion = '~6.4.0';
|
export const rxjsVersion = '~6.4.0';
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tmp": "0.0.33",
|
"tmp": "0.0.33",
|
||||||
"yargs-parser": "10.0.0",
|
"yargs-parser": "10.0.0",
|
||||||
"yargs": "^11.0.0"
|
"yargs": "^11.0.0",
|
||||||
|
"@nrwl/tao": "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,40 +4,89 @@
|
|||||||
import { output } from '@nrwl/workspace/src/command-line/output';
|
import { output } from '@nrwl/workspace/src/command-line/output';
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import { writeFileSync } from 'fs';
|
import { writeFileSync } from 'fs';
|
||||||
|
import * as inquirer from 'inquirer';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { dirSync } from 'tmp';
|
import { dirSync } from 'tmp';
|
||||||
import * as yargsParser from 'yargs-parser';
|
import * as yargsParser from 'yargs-parser';
|
||||||
|
|
||||||
|
const presetOptions = [
|
||||||
|
{
|
||||||
|
value: 'empty',
|
||||||
|
name: 'empty [an empty workspace]'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'angular',
|
||||||
|
name: 'angular [a workspace with a single Angular application]'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'react',
|
||||||
|
name: 'react [a workspace with a single React application]'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'web-components',
|
||||||
|
name:
|
||||||
|
'web components [a workspace with a single app built using web components]'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'full-stack',
|
||||||
|
name:
|
||||||
|
'full-stack [a workspace with a full stack application (NestJS + Angular Ivy)]'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const tsVersion = 'TYPESCRIPT_VERSION';
|
||||||
|
const cliVersion = 'NX_VERSION';
|
||||||
|
const nxVersion = 'NX_VERSION';
|
||||||
|
const angularCliVersion = 'ANGULAR_CLI_VERSION';
|
||||||
|
|
||||||
const parsedArgs = yargsParser(process.argv, {
|
const parsedArgs = yargsParser(process.argv, {
|
||||||
string: ['directory'],
|
string: ['cli', 'preset'],
|
||||||
boolean: ['help']
|
boolean: ['help']
|
||||||
});
|
});
|
||||||
|
|
||||||
if (parsedArgs.help) {
|
if (parsedArgs.help) {
|
||||||
|
showHelp();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
validateInput(parsedArgs);
|
||||||
|
const packageManager = determinePackageManager();
|
||||||
|
determinePreset(parsedArgs).then(preset => {
|
||||||
|
return determineCli(preset, parsedArgs).then(cli => {
|
||||||
|
const tmpDir = createSandbox(packageManager, cli);
|
||||||
|
createApp(tmpDir, cli, parsedArgs, preset);
|
||||||
|
showNxWarning();
|
||||||
|
showCliWarning(preset, parsedArgs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function showHelp() {
|
||||||
console.log(`
|
console.log(`
|
||||||
Usage: create-nx-workspace <directory> [options] [ng new options]
|
Usage: create-nx-workspace <name> [options] [new workspace options]
|
||||||
|
|
||||||
Create a new Nx workspace
|
Create a new Nx workspace
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
directory path to the workspace root directory
|
name workspace name
|
||||||
|
|
||||||
[ng new options] any 'ng new' options
|
preset What to create in a new workspace (options: ${presetOptions
|
||||||
run 'ng new --help' for more information
|
.map(o => '"' + o.value + '"')
|
||||||
|
.join(', ')})
|
||||||
|
|
||||||
|
cli CLI to power the Nx workspace (options: "nx", "angular")
|
||||||
|
|
||||||
|
[new workspace options] any 'new workspace' options
|
||||||
`);
|
`);
|
||||||
process.exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const nxTool = {
|
function determinePackageManager() {
|
||||||
name: 'Schematics',
|
// If you have Angular CLI installed, read Angular CLI config.
|
||||||
packageName: '@nrwl/workspace'
|
// If it isn't not installed, default to 'yarn'.
|
||||||
};
|
|
||||||
|
|
||||||
let packageManager: string;
|
let packageManager: string;
|
||||||
try {
|
try {
|
||||||
packageManager = execSync('ng config -g cli.packageManager', {
|
packageManager = execSync('ng config -g cli.packageManager', {
|
||||||
stdio: ['ignore', 'pipe', 'ignore']
|
stdio: ['ignore', 'pipe', 'ignore'],
|
||||||
|
timeout: 500
|
||||||
})
|
})
|
||||||
.toString()
|
.toString()
|
||||||
.trim();
|
.trim();
|
||||||
@ -51,10 +100,12 @@ try {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
packageManager = 'npm';
|
packageManager = 'npm';
|
||||||
}
|
}
|
||||||
|
return packageManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateInput(parsedArgs: any) {
|
||||||
const projectName = parsedArgs._[2];
|
const projectName = parsedArgs._[2];
|
||||||
|
|
||||||
// check that the workspace name is passed in
|
|
||||||
if (!projectName) {
|
if (!projectName) {
|
||||||
output.error({
|
output.error({
|
||||||
title: 'A project name is required when creating a new workspace',
|
title: 'A project name is required when creating a new workspace',
|
||||||
@ -67,21 +118,102 @@ if (!projectName) {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// creating the sandbox
|
return projectName;
|
||||||
output.logSingleLine(`Creating a sandbox...`);
|
}
|
||||||
|
|
||||||
|
function determinePreset(parsedArgs: any): Promise<string> {
|
||||||
|
if (parsedArgs.preset) {
|
||||||
|
if (presetOptions.map(o => o.value).indexOf(parsedArgs.preset) === -1) {
|
||||||
|
console.error(
|
||||||
|
`Invalid preset. It must be one of the following: ${presetOptions
|
||||||
|
.map(o => '"' + o.value + '"')
|
||||||
|
.join(', ')}.`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(parsedArgs.preset);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return inquirer
|
||||||
|
.prompt([
|
||||||
|
{
|
||||||
|
name: 'Preset',
|
||||||
|
message: `What to create in the new workspace`,
|
||||||
|
default: 'empty',
|
||||||
|
type: 'list',
|
||||||
|
choices: presetOptions
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.then(a => a.Preset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function determineCli(preset: string, parsedArgs: any) {
|
||||||
|
const angular = {
|
||||||
|
package: '@angular/cli',
|
||||||
|
version: angularCliVersion,
|
||||||
|
command: 'ng'
|
||||||
|
};
|
||||||
|
|
||||||
|
const nx = {
|
||||||
|
package: '@nrwl/tao',
|
||||||
|
version: cliVersion,
|
||||||
|
command: 'tao'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (parsedArgs.cli) {
|
||||||
|
if (['nx', 'angular'].indexOf(parsedArgs.cli) === -1) {
|
||||||
|
console.error(
|
||||||
|
`Invalid cli. It must be one of the following: "nx", "angular".`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
return Promise.resolve(parsedArgs.cli === 'angular' ? angular : nx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preset == 'angular' || preset == 'full-stack') {
|
||||||
|
return Promise.resolve(angular);
|
||||||
|
} else if (preset === 'web-components' || preset === 'react') {
|
||||||
|
return Promise.resolve(nx);
|
||||||
|
} else {
|
||||||
|
return inquirer
|
||||||
|
.prompt([
|
||||||
|
{
|
||||||
|
name: 'CLI',
|
||||||
|
message: `CLI to power the Nx workspace`,
|
||||||
|
default: 'nx',
|
||||||
|
type: 'list',
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
value: 'nx',
|
||||||
|
name:
|
||||||
|
'Nx [Extensible CLI for JavaScript and TypeScript applications]'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
value: 'angular',
|
||||||
|
name: 'Angular CLI [Extensible CLI for Angular applications]'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
])
|
||||||
|
.then(a => (a.CLI === 'angular' ? angular : nx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSandbox(
|
||||||
|
packageManager: string,
|
||||||
|
cli: { package: string; version: string }
|
||||||
|
) {
|
||||||
|
console.log(`Creating a sandbox with Nx...`);
|
||||||
const tmpDir = dirSync().name;
|
const tmpDir = dirSync().name;
|
||||||
|
|
||||||
const nxVersion = 'NX_VERSION';
|
|
||||||
const cliVersion = 'ANGULAR_CLI_VERSION';
|
|
||||||
const typescriptVersion = 'TYPESCRIPT_VERSION';
|
|
||||||
|
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
path.join(tmpDir, 'package.json'),
|
path.join(tmpDir, 'package.json'),
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
dependencies: {
|
dependencies: {
|
||||||
[nxTool.packageName]: nxVersion,
|
'@nrwl/workspace': nxVersion,
|
||||||
'@angular/cli': cliVersion,
|
[cli.package]: cli.version,
|
||||||
typescript: typescriptVersion
|
typescript: tsVersion
|
||||||
},
|
},
|
||||||
license: 'MIT'
|
license: 'MIT'
|
||||||
})
|
})
|
||||||
@ -92,42 +224,69 @@ execSync(`${packageManager} install --silent`, {
|
|||||||
stdio: [0, 1, 2]
|
stdio: [0, 1, 2]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return tmpDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createApp(
|
||||||
|
tmpDir: string,
|
||||||
|
cli: { command: string },
|
||||||
|
parsedArgs: any,
|
||||||
|
preset: string
|
||||||
|
) {
|
||||||
// creating the app itself
|
// creating the app itself
|
||||||
const args = process.argv
|
const args = process.argv
|
||||||
.slice(2)
|
.slice(2)
|
||||||
|
.filter(a => !a.startsWith('--cli')) // not used by the new command
|
||||||
.map(a => `"${a}"`)
|
.map(a => `"${a}"`)
|
||||||
.join(' ');
|
.join(' ');
|
||||||
|
|
||||||
output.logSingleLine(
|
const presetArg = parsedArgs.preset ? '' : ` --preset=${preset}`;
|
||||||
`${output.colors.gray('Running:')} ng new ${args} --collection=${
|
|
||||||
nxTool.packageName
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
|
|
||||||
|
console.log(`new ${args}${presetArg} --collection=@nrwl/workspace`);
|
||||||
execSync(
|
execSync(
|
||||||
`"${path.join(
|
`"${path.join(
|
||||||
tmpDir,
|
tmpDir,
|
||||||
'node_modules',
|
'node_modules',
|
||||||
'.bin',
|
'.bin',
|
||||||
'ng'
|
cli.command
|
||||||
)}" new ${args} --collection=${nxTool.packageName}`,
|
)}" new ${args}${presetArg} --collection=@nrwl/workspace`,
|
||||||
{
|
{
|
||||||
stdio: [0, 1, 2]
|
stdio: [0, 1, 2]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: vsavkin: reenable for 8.4
|
function showNxWarning() {
|
||||||
// try {
|
try {
|
||||||
// execSync('nx --version');
|
execSync('nx --version', { stdio: ['ignore', 'ignore', 'ignore'] });
|
||||||
// } catch (e) {
|
} catch (e) {
|
||||||
// // no nx found
|
// no nx found
|
||||||
// console.log('-----------------------------------------------------------');
|
console.log('-----------------------------------------------------------');
|
||||||
// console.log(`It looks like you don't have the Nx CLI installed globally.`);
|
console.log(`It looks like you don't have the Nx CLI installed globally.`);
|
||||||
// console.log(
|
console.log(
|
||||||
// `This means that you might have to use "yarn nx" or "npm nx" to execute commands in your workspace.`
|
`This means that you might have to use "yarn nx" or "npm nx" to execute commands in your workspace.`
|
||||||
// );
|
);
|
||||||
// console.log(
|
console.log(
|
||||||
// `If you want to execute the nx command directly, run "yarn global add @nrwl/cli" or "npm install -g @nrwl/cli"`
|
`If you want to execute the nx command directly, run "yarn global add @nrwl/cli" or "npm install -g @nrwl/cli"`
|
||||||
// );
|
);
|
||||||
// console.log('-----------------------------------------------------------');
|
console.log('-----------------------------------------------------------');
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCliWarning(preset: string, parsedArgs: any) {
|
||||||
|
if (!parsedArgs.cli) {
|
||||||
|
if (preset == 'angular' || preset == 'full-stack') {
|
||||||
|
console.log(
|
||||||
|
'Because you selected an Angular-specific preset, we generated an Nx workspace powered by the Angular CLi.'
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`If you want want to power the workspace using a different CLI, you can pass it using '--cli'. Find out more by running 'create-nx-workspace --help'.`
|
||||||
|
);
|
||||||
|
} else if (preset === 'web-components' || preset === 'react') {
|
||||||
|
console.log('We generated an Nx workspace powered by the Nx CLi.');
|
||||||
|
console.log(
|
||||||
|
`If you want want to power the workspace using a different CLI, you can pass it using '--cli'. Find out more by running 'create-nx-workspace --help'.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
"@nrwl/workspace": "*",
|
"@nrwl/workspace": "*",
|
||||||
"tmp": "0.0.33",
|
"tmp": "0.0.33",
|
||||||
"yargs-parser": "10.0.0",
|
"yargs-parser": "10.0.0",
|
||||||
"yargs": "^11.0.0"
|
"yargs": "^11.0.0",
|
||||||
|
"inquirer": "^6.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,21 +37,21 @@ describe('schematic:cypress-project', () => {
|
|||||||
expect(tree.exists('apps/my-app-e2e/src/support/index.ts')).toBeTruthy();
|
expect(tree.exists('apps/my-app-e2e/src/support/index.ts')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add update `angular.json` file', async () => {
|
it('should add update `workspace.json` file', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'cypress-project',
|
'cypress-project',
|
||||||
{ name: 'my-app-e2e', project: 'my-app' },
|
{ name: 'my-app-e2e', project: 'my-app' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
const project = angularJson.projects['my-app-e2e'];
|
const project = workspaceJson.projects['my-app-e2e'];
|
||||||
|
|
||||||
expect(project.root).toEqual('apps/my-app-e2e');
|
expect(project.root).toEqual('apps/my-app-e2e');
|
||||||
|
|
||||||
expect(project.architect.lint).toEqual({
|
expect(project.architect.lint).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
builder: '@angular-devkit/build-angular:tslint',
|
||||||
options: {
|
options: {
|
||||||
tsConfig: 'apps/my-app-e2e/tsconfig.e2e.json',
|
tsConfig: ['apps/my-app-e2e/tsconfig.e2e.json'],
|
||||||
exclude: ['**/node_modules/**', '!apps/my-app-e2e/**']
|
exclude: ['**/node_modules/**', '!apps/my-app-e2e/**']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -107,13 +107,13 @@ describe('schematic:cypress-project', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('nested', () => {
|
describe('nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'cypress-project',
|
'cypress-project',
|
||||||
{ name: 'my-app-e2e', project: 'my-dir-my-app', directory: 'my-dir' },
|
{ name: 'my-app-e2e', project: 'my-dir-my-app', directory: 'my-dir' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const projectConfig = readJsonInTree(tree, 'angular.json').projects[
|
const projectConfig = readJsonInTree(tree, 'workspace.json').projects[
|
||||||
'my-dir-my-app-e2e'
|
'my-dir-my-app-e2e'
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ describe('schematic:cypress-project', () => {
|
|||||||
expect(projectConfig.architect.lint).toEqual({
|
expect(projectConfig.architect.lint).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
builder: '@angular-devkit/build-angular:tslint',
|
||||||
options: {
|
options: {
|
||||||
tsConfig: 'apps/my-dir/my-app-e2e/tsconfig.e2e.json',
|
tsConfig: ['apps/my-dir/my-app-e2e/tsconfig.e2e.json'],
|
||||||
exclude: ['**/node_modules/**', '!apps/my-dir/my-app-e2e/**']
|
exclude: ['**/node_modules/**', '!apps/my-dir/my-app-e2e/**']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,7 +9,13 @@ import {
|
|||||||
} from '@angular-devkit/schematics';
|
} from '@angular-devkit/schematics';
|
||||||
import { join, normalize } from '@angular-devkit/core';
|
import { join, normalize } from '@angular-devkit/core';
|
||||||
// app
|
// app
|
||||||
import { updateJsonInTree, NxJson } from '@nrwl/workspace';
|
import {
|
||||||
|
updateJsonInTree,
|
||||||
|
NxJson,
|
||||||
|
updateWorkspaceInTree,
|
||||||
|
generateProjectLint,
|
||||||
|
addGlobalLint
|
||||||
|
} from '@nrwl/workspace';
|
||||||
import { offsetFromRoot } from '@nrwl/workspace';
|
import { offsetFromRoot } from '@nrwl/workspace';
|
||||||
import { toFileName } from '@nrwl/workspace';
|
import { toFileName } from '@nrwl/workspace';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
@ -44,8 +50,8 @@ function updateNxJson(options: CypressProjectSchema): Rule {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAngularJson(options: CypressProjectSchema): Rule {
|
function updateWorkspaceJson(options: CypressProjectSchema): Rule {
|
||||||
return updateJsonInTree('angular.json', json => {
|
return updateWorkspaceInTree(json => {
|
||||||
const architect: any = {};
|
const architect: any = {};
|
||||||
|
|
||||||
architect.e2e = {
|
architect.e2e = {
|
||||||
@ -61,16 +67,13 @@ function updateAngularJson(options: CypressProjectSchema): Rule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
architect.lint = {
|
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
architect.lint = generateProjectLint(
|
||||||
options: {
|
normalize(options.projectRoot),
|
||||||
tsConfig: join(normalize(options.projectRoot), 'tsconfig.e2e.json'),
|
join(normalize(options.projectRoot), 'tsconfig.e2e.json'),
|
||||||
exclude: [
|
options.linter
|
||||||
'**/node_modules/**',
|
);
|
||||||
'!' + join(normalize(options.projectRoot), '**')
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
json.projects[options.projectName] = {
|
json.projects[options.projectName] = {
|
||||||
root: options.projectRoot,
|
root: options.projectRoot,
|
||||||
sourceRoot: join(normalize(options.projectRoot), 'src'),
|
sourceRoot: join(normalize(options.projectRoot), 'src'),
|
||||||
@ -84,8 +87,9 @@ function updateAngularJson(options: CypressProjectSchema): Rule {
|
|||||||
export default function(options: CypressProjectSchema): Rule {
|
export default function(options: CypressProjectSchema): Rule {
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
return chain([
|
return chain([
|
||||||
|
addGlobalLint(options.linter),
|
||||||
generateFiles(options),
|
generateFiles(options),
|
||||||
updateAngularJson(options),
|
updateWorkspaceJson(options),
|
||||||
updateNxJson(options)
|
updateNxJson(options)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,4 +2,5 @@ export interface Schema {
|
|||||||
project: string;
|
project: string;
|
||||||
name: string;
|
name: string;
|
||||||
directory: string;
|
directory: string;
|
||||||
|
linter: 'eslint' | 'tslint';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,12 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "A directory where the app is placed",
|
"description": "A directory where the app is placed",
|
||||||
"x-prompt": "In which directory should the library be generated?"
|
"x-prompt": "In which directory should the library be generated?"
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "tslint"],
|
||||||
|
"default": "tslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["name"]
|
"required": ["name"]
|
||||||
|
|||||||
@ -32,13 +32,13 @@ describe('ng-add', () => {
|
|||||||
describe('defaultCollection', () => {
|
describe('defaultCollection', () => {
|
||||||
it('should be set if none was set before', async () => {
|
it('should be set if none was set before', async () => {
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/express');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/express');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be set if @nrwl/workspace was set before', async () => {
|
it('should be set if @nrwl/workspace was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/workspace'
|
defaultCollection: '@nrwl/workspace'
|
||||||
};
|
};
|
||||||
@ -48,13 +48,13 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/express');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/express');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be set if something else was set before', async () => {
|
it('should not be set if something else was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/angular'
|
defaultCollection: '@nrwl/angular'
|
||||||
};
|
};
|
||||||
@ -64,8 +64,8 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -10,7 +10,7 @@ describe('jestProject', () => {
|
|||||||
appTree = Tree.empty();
|
appTree = Tree.empty();
|
||||||
appTree = createEmptyWorkspace(appTree);
|
appTree = createEmptyWorkspace(appTree);
|
||||||
appTree = await callRule(
|
appTree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.projects.lib1 = {
|
json.projects.lib1 = {
|
||||||
root: 'libs/lib1',
|
root: 'libs/lib1',
|
||||||
architect: {
|
architect: {
|
||||||
@ -52,7 +52,7 @@ describe('jestProject', () => {
|
|||||||
expect(resultTree.exists('/libs/lib1/tsconfig.spec.json')).toBeTruthy();
|
expect(resultTree.exists('/libs/lib1/tsconfig.spec.json')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should alter angular.json', async () => {
|
it('should alter workspace.json', async () => {
|
||||||
const resultTree = await runSchematic(
|
const resultTree = await runSchematic(
|
||||||
'jest-project',
|
'jest-project',
|
||||||
{
|
{
|
||||||
@ -61,8 +61,8 @@ describe('jestProject', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||||
expect(angularJson.projects.lib1.architect.test).toEqual({
|
expect(workspaceJson.projects.lib1.architect.test).toEqual({
|
||||||
builder: '@nrwl/jest:jest',
|
builder: '@nrwl/jest:jest',
|
||||||
options: {
|
options: {
|
||||||
jestConfig: 'libs/lib1/jest.config.js',
|
jestConfig: 'libs/lib1/jest.config.js',
|
||||||
@ -70,9 +70,9 @@ describe('jestProject', () => {
|
|||||||
tsConfig: 'libs/lib1/tsconfig.spec.json'
|
tsConfig: 'libs/lib1/tsconfig.spec.json'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(angularJson.projects.lib1.architect.lint.options.tsConfig).toContain(
|
expect(
|
||||||
'libs/lib1/tsconfig.spec.json'
|
workspaceJson.projects.lib1.architect.lint.options.tsConfig
|
||||||
);
|
).toContain('libs/lib1/tsconfig.spec.json');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a jest.config.js', async () => {
|
it('should create a jest.config.js', async () => {
|
||||||
@ -144,7 +144,7 @@ describe('jestProject', () => {
|
|||||||
expect(resultTree.exists('src/test-setup.ts')).toBeFalsy();
|
expect(resultTree.exists('src/test-setup.ts')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not list the setup file in angular.json', async () => {
|
it('should not list the setup file in workspace.json', async () => {
|
||||||
const resultTree = await runSchematic(
|
const resultTree = await runSchematic(
|
||||||
'jest-project',
|
'jest-project',
|
||||||
{
|
{
|
||||||
@ -153,9 +153,9 @@ describe('jestProject', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects.lib1.architect.test.options.setupFile
|
workspaceJson.projects.lib1.architect.test.options.setupFile
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ describe('jestProject', () => {
|
|||||||
expect(resultTree.exists('src/test-setup.ts')).toBeFalsy();
|
expect(resultTree.exists('src/test-setup.ts')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not list the setup file in angular.json', async () => {
|
it('should not list the setup file in workspace.json', async () => {
|
||||||
const resultTree = await runSchematic(
|
const resultTree = await runSchematic(
|
||||||
'jest-project',
|
'jest-project',
|
||||||
{
|
{
|
||||||
@ -198,9 +198,9 @@ describe('jestProject', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects.lib1.architect.test.options.setupFile
|
workspaceJson.projects.lib1.architect.test.options.setupFile
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,11 @@ import {
|
|||||||
noop,
|
noop,
|
||||||
filter
|
filter
|
||||||
} from '@angular-devkit/schematics';
|
} from '@angular-devkit/schematics';
|
||||||
import { readJsonInTree, updateJsonInTree } from '@nrwl/workspace';
|
import {
|
||||||
|
readJsonInTree,
|
||||||
|
updateJsonInTree,
|
||||||
|
updateWorkspaceInTree
|
||||||
|
} from '@nrwl/workspace';
|
||||||
import { getProjectConfig, addDepsToPackageJson } from '@nrwl/workspace';
|
import { getProjectConfig, addDepsToPackageJson } from '@nrwl/workspace';
|
||||||
import { offsetFromRoot } from '@nrwl/workspace';
|
import { offsetFromRoot } from '@nrwl/workspace';
|
||||||
import { join, normalize } from '@angular-devkit/core';
|
import { join, normalize } from '@angular-devkit/core';
|
||||||
@ -69,8 +73,8 @@ function updateTsConfig(options: JestProjectSchema): Rule {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAngularJson(options: JestProjectSchema): Rule {
|
function updateWorkspaceJson(options: JestProjectSchema): Rule {
|
||||||
return updateJsonInTree('angular.json', json => {
|
return updateWorkspaceInTree(json => {
|
||||||
const projectConfig = json.projects[options.project];
|
const projectConfig = json.projects[options.project];
|
||||||
projectConfig.architect.test = {
|
projectConfig.architect.test = {
|
||||||
builder: '@nrwl/jest:jest',
|
builder: '@nrwl/jest:jest',
|
||||||
@ -106,7 +110,9 @@ function check(options: JestProjectSchema): Rule {
|
|||||||
const packageJson = readJsonInTree(host, 'package.json');
|
const packageJson = readJsonInTree(host, 'package.json');
|
||||||
if (!packageJson.devDependencies.jest) {
|
if (!packageJson.devDependencies.jest) {
|
||||||
context.logger.warn(`"jest" is not installed as a dependency.`);
|
context.logger.warn(`"jest" is not installed as a dependency.`);
|
||||||
context.logger.info(`Add "jest" via "ng add @nrwl/jest"`);
|
context.logger.info(
|
||||||
|
`Add "jest" via "yarn add --dev @nrwl/jest" or "npm install -D @nrwl/jest"`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return host;
|
return host;
|
||||||
};
|
};
|
||||||
@ -128,6 +134,6 @@ export default function(options: JestProjectSchema): Rule {
|
|||||||
check(options),
|
check(options),
|
||||||
generateFiles(options),
|
generateFiles(options),
|
||||||
updateTsConfig(options),
|
updateTsConfig(options),
|
||||||
updateAngularJson(options)
|
updateWorkspaceJson(options)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,13 +23,13 @@ describe('ng-add', () => {
|
|||||||
describe('defaultCollection', () => {
|
describe('defaultCollection', () => {
|
||||||
it('should be set if none was set before', async () => {
|
it('should be set if none was set before', async () => {
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/nest');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/nest');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be set if @nrwl/workspace was set before', async () => {
|
it('should be set if @nrwl/workspace was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/workspace'
|
defaultCollection: '@nrwl/workspace'
|
||||||
};
|
};
|
||||||
@ -39,13 +39,13 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/nest');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/nest');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be set if something else was set before', async () => {
|
it('should not be set if something else was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/angular'
|
defaultCollection: '@nrwl/angular'
|
||||||
};
|
};
|
||||||
@ -55,8 +55,8 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -14,10 +14,10 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('not nested', () => {
|
describe('not nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'myNodeApp' }, appTree);
|
const tree = await runSchematic('app', { name: 'myNodeApp' }, appTree);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
const project = angularJson.projects['my-node-app'];
|
const project = workspaceJson.projects['my-node-app'];
|
||||||
expect(project.root).toEqual('apps/my-node-app');
|
expect(project.root).toEqual('apps/my-node-app');
|
||||||
expect(project.architect).toEqual(
|
expect(project.architect).toEqual(
|
||||||
jasmine.objectContaining({
|
jasmine.objectContaining({
|
||||||
@ -52,7 +52,7 @@ describe('app', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(angularJson.projects['my-node-app'].architect.lint).toEqual({
|
expect(workspaceJson.projects['my-node-app'].architect.lint).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
builder: '@angular-devkit/build-angular:tslint',
|
||||||
options: {
|
options: {
|
||||||
tsConfig: [
|
tsConfig: [
|
||||||
@ -62,8 +62,8 @@ describe('app', () => {
|
|||||||
exclude: ['**/node_modules/**', '!apps/my-node-app/**']
|
exclude: ['**/node_modules/**', '!apps/my-node-app/**']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(angularJson.projects['my-node-app-e2e']).toBeUndefined();
|
expect(workspaceJson.projects['my-node-app-e2e']).toBeUndefined();
|
||||||
expect(angularJson.defaultProject).toEqual('my-node-app');
|
expect(workspaceJson.defaultProject).toEqual('my-node-app');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
it('should update nx.json', async () => {
|
||||||
@ -109,20 +109,21 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('nested', () => {
|
describe('nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'app',
|
'app',
|
||||||
{ name: 'myNodeApp', directory: 'myDir' },
|
{ name: 'myNodeApp', directory: 'myDir' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-dir-my-node-app'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-node-app'].root).toEqual(
|
||||||
'apps/my-dir/my-node-app'
|
'apps/my-dir/my-node-app'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(angularJson.projects['my-dir-my-node-app'].architect.lint).toEqual(
|
expect(
|
||||||
{
|
workspaceJson.projects['my-dir-my-node-app'].architect.lint
|
||||||
|
).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
builder: '@angular-devkit/build-angular:tslint',
|
||||||
options: {
|
options: {
|
||||||
tsConfig: [
|
tsConfig: [
|
||||||
@ -131,11 +132,10 @@ describe('app', () => {
|
|||||||
],
|
],
|
||||||
exclude: ['**/node_modules/**', '!apps/my-dir/my-node-app/**']
|
exclude: ['**/node_modules/**', '!apps/my-dir/my-node-app/**']
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
expect(angularJson.projects['my-dir-my-node-app-e2e']).toBeUndefined();
|
expect(workspaceJson.projects['my-dir-my-node-app-e2e']).toBeUndefined();
|
||||||
expect(angularJson.defaultProject).toEqual('my-dir-my-node-app');
|
expect(workspaceJson.defaultProject).toEqual('my-dir-my-node-app');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
it('should update nx.json', async () => {
|
||||||
@ -213,12 +213,12 @@ describe('app', () => {
|
|||||||
expect(tree.exists('apps/my-node-app/src/test.ts')).toBeFalsy();
|
expect(tree.exists('apps/my-node-app/src/test.ts')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-node-app/tsconfig.spec.json')).toBeFalsy();
|
expect(tree.exists('apps/my-node-app/tsconfig.spec.json')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-node-app/jest.config.js')).toBeFalsy();
|
expect(tree.exists('apps/my-node-app/jest.config.js')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-node-app'].architect.test
|
workspaceJson.projects['my-node-app'].architect.test
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-node-app'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-node-app'].architect.lint.options.tsConfig
|
||||||
).toEqual(['apps/my-node-app/tsconfig.app.json']);
|
).toEqual(['apps/my-node-app/tsconfig.app.json']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -234,7 +234,7 @@ describe('app', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
||||||
const serve = JSON.parse(tree.readContent('angular.json')).projects[
|
const serve = JSON.parse(tree.readContent('workspace.json')).projects[
|
||||||
'my-frontend'
|
'my-frontend'
|
||||||
].architect.serve;
|
].architect.serve;
|
||||||
expect(serve.options.proxyConfig).toEqual(
|
expect(serve.options.proxyConfig).toEqual(
|
||||||
@ -252,7 +252,7 @@ describe('app', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
expect(tree.exists('apps/my-frontend/proxy.conf.json')).toBeTruthy();
|
||||||
const serve = JSON.parse(tree.readContent('angular.json')).projects[
|
const serve = JSON.parse(tree.readContent('workspace.json')).projects[
|
||||||
'my-frontend'
|
'my-frontend'
|
||||||
].architect.serve;
|
].architect.serve;
|
||||||
expect(serve.options.proxyConfig).toEqual(
|
expect(serve.options.proxyConfig).toEqual(
|
||||||
|
|||||||
@ -13,7 +13,12 @@ import {
|
|||||||
} from '@angular-devkit/schematics';
|
} from '@angular-devkit/schematics';
|
||||||
import { join, normalize, Path } from '@angular-devkit/core';
|
import { join, normalize, Path } from '@angular-devkit/core';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { updateJsonInTree } from '@nrwl/workspace';
|
import {
|
||||||
|
updateJsonInTree,
|
||||||
|
updateWorkspaceInTree,
|
||||||
|
generateProjectLint,
|
||||||
|
addGlobalLint
|
||||||
|
} from '@nrwl/workspace';
|
||||||
import { toFileName } from '@nrwl/workspace';
|
import { toFileName } from '@nrwl/workspace';
|
||||||
import { getProjectConfig } from '@nrwl/workspace';
|
import { getProjectConfig } from '@nrwl/workspace';
|
||||||
import { offsetFromRoot } from '@nrwl/workspace';
|
import { offsetFromRoot } from '@nrwl/workspace';
|
||||||
@ -61,16 +66,6 @@ function getBuildConfig(project: any, options: NormalizedSchema) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLintConfig(project: any) {
|
|
||||||
return {
|
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
|
||||||
options: {
|
|
||||||
tsConfig: [join(project.root, 'tsconfig.app.json')],
|
|
||||||
exclude: ['**/node_modules/**', '!' + join(project.root, '**')]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getServeConfig(options: NormalizedSchema) {
|
function getServeConfig(options: NormalizedSchema) {
|
||||||
return {
|
return {
|
||||||
builder: '@nrwl/node:execute',
|
builder: '@nrwl/node:execute',
|
||||||
@ -80,8 +75,8 @@ function getServeConfig(options: NormalizedSchema) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAngularJson(options: NormalizedSchema): Rule {
|
function updateWorkspaceJson(options: NormalizedSchema): Rule {
|
||||||
return updateJsonInTree('angular.json', angularJson => {
|
return updateWorkspaceInTree(workspaceJson => {
|
||||||
const project = {
|
const project = {
|
||||||
root: options.appProjectRoot,
|
root: options.appProjectRoot,
|
||||||
sourceRoot: join(options.appProjectRoot, 'src'),
|
sourceRoot: join(options.appProjectRoot, 'src'),
|
||||||
@ -93,12 +88,17 @@ function updateAngularJson(options: NormalizedSchema): Rule {
|
|||||||
|
|
||||||
project.architect.build = getBuildConfig(project, options);
|
project.architect.build = getBuildConfig(project, options);
|
||||||
project.architect.serve = getServeConfig(options);
|
project.architect.serve = getServeConfig(options);
|
||||||
project.architect.lint = getLintConfig(project);
|
project.architect.lint = generateProjectLint(
|
||||||
angularJson.projects[options.name] = project;
|
normalize(project.root),
|
||||||
|
join(normalize(project.root), 'tsconfig.app.json'),
|
||||||
|
options.linter
|
||||||
|
);
|
||||||
|
|
||||||
angularJson.defaultProject = angularJson.defaultProject || options.name;
|
workspaceJson.projects[options.name] = project;
|
||||||
|
|
||||||
return angularJson;
|
workspaceJson.defaultProject = workspaceJson.defaultProject || options.name;
|
||||||
|
|
||||||
|
return workspaceJson;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ function addProxy(options: NormalizedSchema): Rule {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
updateJsonInTree('angular.json', json => {
|
updateWorkspaceInTree(json => {
|
||||||
projectConfig.architect.serve.options.proxyConfig = pathToProxyFile;
|
projectConfig.architect.serve.options.proxyConfig = pathToProxyFile;
|
||||||
json.projects[options.frontendProject] = projectConfig;
|
json.projects[options.frontendProject] = projectConfig;
|
||||||
return json;
|
return json;
|
||||||
@ -151,8 +151,9 @@ export default function(schema: Schema): Rule {
|
|||||||
ngAdd({
|
ngAdd({
|
||||||
skipFormat: true
|
skipFormat: true
|
||||||
}),
|
}),
|
||||||
|
addGlobalLint(options.linter),
|
||||||
addAppFiles(options),
|
addAppFiles(options),
|
||||||
updateAngularJson(options),
|
updateWorkspaceJson(options),
|
||||||
updateNxJson(options),
|
updateNxJson(options),
|
||||||
options.unitTestRunner === 'jest'
|
options.unitTestRunner === 'jest'
|
||||||
? externalSchematic('@nrwl/jest', 'jest-project', {
|
? externalSchematic('@nrwl/jest', 'jest-project', {
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
// This file can be replaced during build by using the `fileReplacements` array.
|
|
||||||
// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
|
|
||||||
// The list of file replacements can be found in `angular.json`.
|
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false
|
production: false
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { UnitTestRunner } from '../../utils/test-runners';
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
name: string;
|
name: string;
|
||||||
skipFormat: boolean;
|
skipFormat: boolean;
|
||||||
skipPackageJson: boolean;
|
skipPackageJson: boolean;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
unitTestRunner: UnitTestRunner;
|
unitTestRunner: 'jest' | 'none';
|
||||||
|
linter: 'eslint' | 'tslint';
|
||||||
tags?: string;
|
tags?: string;
|
||||||
frontendProject?: string;
|
frontendProject?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,12 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to package.json."
|
"description": "Do not add dependencies to package.json."
|
||||||
},
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "tslint"],
|
||||||
|
"default": "tslint"
|
||||||
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
|
|||||||
@ -21,13 +21,13 @@ describe('ng-add', () => {
|
|||||||
describe('defaultCollection', () => {
|
describe('defaultCollection', () => {
|
||||||
it('should be set if none was set before', async () => {
|
it('should be set if none was set before', async () => {
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/node');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/node');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be set if @nrwl/workspace was set before', async () => {
|
it('should be set if @nrwl/workspace was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/workspace'
|
defaultCollection: '@nrwl/workspace'
|
||||||
};
|
};
|
||||||
@ -37,13 +37,13 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/node');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/node');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be set if something else was set before', async () => {
|
it('should not be set if something else was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/angular'
|
defaultCollection: '@nrwl/angular'
|
||||||
};
|
};
|
||||||
@ -53,8 +53,8 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,15 +13,15 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('not nested', () => {
|
describe('not nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-app'].root).toEqual('apps/my-app');
|
expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app');
|
||||||
expect(angularJson.projects['my-app-e2e'].root).toEqual(
|
expect(workspaceJson.projects['my-app-e2e'].root).toEqual(
|
||||||
'apps/my-app-e2e'
|
'apps/my-app-e2e'
|
||||||
);
|
);
|
||||||
expect(angularJson.defaultProject).toEqual('my-app');
|
expect(workspaceJson.defaultProject).toEqual('my-app');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
it('should update nx.json', async () => {
|
||||||
@ -76,18 +76,18 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('nested', () => {
|
describe('nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'app',
|
'app',
|
||||||
{ name: 'myApp', directory: 'myDir' },
|
{ name: 'myApp', directory: 'myDir' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-dir-my-app'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-app'].root).toEqual(
|
||||||
'apps/my-dir/my-app'
|
'apps/my-dir/my-app'
|
||||||
);
|
);
|
||||||
expect(angularJson.projects['my-dir-my-app-e2e'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-app-e2e'].root).toEqual(
|
||||||
'apps/my-dir/my-app-e2e'
|
'apps/my-dir/my-app-e2e'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -225,8 +225,8 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
const architectConfig = angularJson.projects['my-app'].architect;
|
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||||
expect(architectConfig.build.builder).toEqual('@nrwl/web:build');
|
expect(architectConfig.build.builder).toEqual('@nrwl/web:build');
|
||||||
expect(architectConfig.build.options).toEqual({
|
expect(architectConfig.build.options).toEqual({
|
||||||
assets: ['apps/my-app/src/favicon.ico', 'apps/my-app/src/assets'],
|
assets: ['apps/my-app/src/favicon.ico', 'apps/my-app/src/assets'],
|
||||||
@ -270,8 +270,8 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
const architectConfig = angularJson.projects['my-app'].architect;
|
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||||
expect(architectConfig.serve.builder).toEqual('@nrwl/web:dev-server');
|
expect(architectConfig.serve.builder).toEqual('@nrwl/web:dev-server');
|
||||||
expect(architectConfig.serve.options).toEqual({
|
expect(architectConfig.serve.options).toEqual({
|
||||||
buildTarget: 'my-app:build'
|
buildTarget: 'my-app:build'
|
||||||
@ -289,8 +289,8 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app'].architect.lint).toEqual({
|
expect(workspaceJson.projects['my-app'].architect.lint).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
builder: '@angular-devkit/build-angular:tslint',
|
||||||
options: {
|
options: {
|
||||||
exclude: ['**/node_modules/**', '!apps/my-app/**'],
|
exclude: ['**/node_modules/**', '!apps/my-app/**'],
|
||||||
@ -312,10 +312,10 @@ describe('app', () => {
|
|||||||
expect(tree.exists('apps/my-app/src/app/app.spec.tsx')).toBeFalsy();
|
expect(tree.exists('apps/my-app/src/app/app.spec.tsx')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeFalsy();
|
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app'].architect.test).toBeUndefined();
|
expect(workspaceJson.projects['my-app'].architect.test).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-app'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-app'].architect.lint.options.tsConfig
|
||||||
).toEqual(['apps/my-app/tsconfig.app.json']);
|
).toEqual(['apps/my-app/tsconfig.app.json']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -328,8 +328,8 @@ describe('app', () => {
|
|||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app-e2e']).toBeUndefined();
|
expect(workspaceJson.projects['my-app-e2e']).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -417,17 +417,17 @@ describe('app', () => {
|
|||||||
expect(content).toContain('<StyledApp>');
|
expect(content).toContain('<StyledApp>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should exclude styles from angular.json', async () => {
|
it('should exclude styles from workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'app',
|
'app',
|
||||||
{ name: 'myApp', style: '@emotion/styled' },
|
{ name: 'myApp', style: '@emotion/styled' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
|
|
||||||
const angularJSON = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
angularJSON.projects['my-app'].architect.build.options.styles
|
workspaceJson.projects['my-app'].architect.build.options.styles
|
||||||
).toEqual([]);
|
).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -19,9 +19,14 @@ import {
|
|||||||
NxJson,
|
NxJson,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
toFileName,
|
toFileName,
|
||||||
updateJsonInTree
|
updateJsonInTree,
|
||||||
|
generateProjectLint,
|
||||||
|
addGlobalLint
|
||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import { addDepsToPackageJson } from '@nrwl/workspace/src/utils/ast-utils';
|
import {
|
||||||
|
addDepsToPackageJson,
|
||||||
|
updateWorkspaceInTree
|
||||||
|
} from '@nrwl/workspace/src/utils/ast-utils';
|
||||||
import ngAdd from '../ng-add/ng-add';
|
import ngAdd from '../ng-add/ng-add';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
@ -48,6 +53,7 @@ export default function(schema: Schema): Rule {
|
|||||||
ngAdd({
|
ngAdd({
|
||||||
skipFormat: true
|
skipFormat: true
|
||||||
}),
|
}),
|
||||||
|
addGlobalLint(options.linter),
|
||||||
createApplicationFiles(options),
|
createApplicationFiles(options),
|
||||||
updateNxJson(options),
|
updateNxJson(options),
|
||||||
addProject(options),
|
addProject(options),
|
||||||
@ -102,7 +108,7 @@ function updateNxJson(options: NormalizedSchema): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addProject(options: NormalizedSchema): Rule {
|
function addProject(options: NormalizedSchema): Rule {
|
||||||
return updateJsonInTree('angular.json', json => {
|
return updateWorkspaceInTree(json => {
|
||||||
const architect: { [key: string]: any } = {};
|
const architect: { [key: string]: any } = {};
|
||||||
|
|
||||||
architect.build = {
|
architect.build = {
|
||||||
@ -166,16 +172,11 @@ function addProject(options: NormalizedSchema): Rule {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
architect.lint = {
|
architect.lint = generateProjectLint(
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
normalize(options.appProjectRoot),
|
||||||
options: {
|
join(normalize(options.appProjectRoot), 'tsconfig.app.json'),
|
||||||
tsConfig: [join(options.appProjectRoot, 'tsconfig.app.json')],
|
options.linter
|
||||||
exclude: [
|
);
|
||||||
'**/node_modules/**',
|
|
||||||
'!' + join(options.appProjectRoot, '**')
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
json.projects[options.projectName] = {
|
json.projects[options.projectName] = {
|
||||||
root: options.appProjectRoot,
|
root: options.appProjectRoot,
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
name: string;
|
name: string;
|
||||||
style?: string;
|
style?: string;
|
||||||
skipFormat: boolean;
|
skipFormat: boolean;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
tags?: string;
|
tags?: string;
|
||||||
unitTestRunner: UnitTestRunner;
|
unitTestRunner: 'jest' | 'none';
|
||||||
e2eTestRunner: E2eTestRunner;
|
e2eTestRunner: 'cypress' | 'none';
|
||||||
|
linter: 'eslint' | 'tslint';
|
||||||
pascalCaseFiles?: boolean;
|
pascalCaseFiles?: boolean;
|
||||||
classComponent?: boolean;
|
classComponent?: boolean;
|
||||||
routing?: boolean;
|
routing?: boolean;
|
||||||
|
|||||||
@ -50,6 +50,12 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "tslint"],
|
||||||
|
"default": "tslint"
|
||||||
|
},
|
||||||
"routing": {
|
"routing": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Generate application with routes",
|
"description": "Generate application with routes",
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"project": {
|
"project": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The name of the project (as specified in angular.json).",
|
"description": "The name of the project.",
|
||||||
"$default": {
|
"$default": {
|
||||||
"$source": "projectName"
|
"$source": "projectName"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,4 +4,4 @@ This library was generated with [Nx](https://nx.dev).
|
|||||||
|
|
||||||
## Running unit tests
|
## Running unit tests
|
||||||
|
|
||||||
Run `ng test <%= name %>` to execute the unit tests via [Jest](https://jestjs.io).
|
Run `yarn test <%= name %>` to execute the unit tests via [Jest](https://jestjs.io).
|
||||||
|
|||||||
@ -13,13 +13,12 @@ describe('lib', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('not nested', () => {
|
describe('not nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic('lib', { name: 'myLib' }, appTree);
|
const tree = await runSchematic('lib', { name: 'myLib' }, appTree);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||||
expect(angularJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
expect(workspaceJson.projects['my-lib'].architect.build).toBeUndefined();
|
||||||
expect(angularJson.projects['my-lib'].architect.build).toBeUndefined();
|
expect(workspaceJson.projects['my-lib'].architect.lint).toEqual({
|
||||||
expect(angularJson.projects['my-lib'].architect.lint).toEqual({
|
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
builder: '@angular-devkit/build-angular:tslint',
|
||||||
options: {
|
options: {
|
||||||
exclude: ['**/node_modules/**', '!libs/my-lib/**'],
|
exclude: ['**/node_modules/**', '!libs/my-lib/**'],
|
||||||
@ -172,18 +171,18 @@ describe('lib', () => {
|
|||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'lib',
|
'lib',
|
||||||
{ name: 'myLib', directory: 'myDir' },
|
{ name: 'myLib', directory: 'myDir' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-dir-my-lib'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-lib'].root).toEqual(
|
||||||
'libs/my-dir/my-lib'
|
'libs/my-dir/my-lib'
|
||||||
);
|
);
|
||||||
expect(angularJson.projects['my-dir-my-lib'].architect.lint).toEqual({
|
expect(workspaceJson.projects['my-dir-my-lib'].architect.lint).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
builder: '@angular-devkit/build-angular:tslint',
|
||||||
options: {
|
options: {
|
||||||
exclude: ['**/node_modules/**', '!libs/my-dir/my-lib/**'],
|
exclude: ['**/node_modules/**', '!libs/my-dir/my-lib/**'],
|
||||||
@ -256,10 +255,10 @@ describe('lib', () => {
|
|||||||
);
|
);
|
||||||
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy();
|
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeFalsy();
|
||||||
expect(resultTree.exists('libs/my-lib/jest.config.js')).toBeFalsy();
|
expect(resultTree.exists('libs/my-lib/jest.config.js')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-lib'].architect.test).toBeUndefined();
|
expect(workspaceJson.projects['my-lib'].architect.test).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-lib'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||||
).toEqual(['libs/my-lib/tsconfig.lib.json']);
|
).toEqual(['libs/my-lib/tsconfig.lib.json']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -22,7 +22,10 @@ import {
|
|||||||
readJsonInTree,
|
readJsonInTree,
|
||||||
toClassName,
|
toClassName,
|
||||||
toFileName,
|
toFileName,
|
||||||
updateJsonInTree
|
updateJsonInTree,
|
||||||
|
updateWorkspaceInTree,
|
||||||
|
addGlobalLint,
|
||||||
|
generateProjectLint
|
||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import { join, normalize, Path } from '@angular-devkit/core';
|
import { join, normalize, Path } from '@angular-devkit/core';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
@ -44,6 +47,7 @@ export default function(schema: Schema): Rule {
|
|||||||
const options = normalizeOptions(schema);
|
const options = normalizeOptions(schema);
|
||||||
|
|
||||||
return chain([
|
return chain([
|
||||||
|
addGlobalLint(options.linter),
|
||||||
createFiles(options),
|
createFiles(options),
|
||||||
!options.skipTsConfig ? updateTsConfig(options) : noop(),
|
!options.skipTsConfig ? updateTsConfig(options) : noop(),
|
||||||
addProject(options),
|
addProject(options),
|
||||||
@ -71,19 +75,14 @@ export default function(schema: Schema): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addProject(options: NormalizedSchema): Rule {
|
function addProject(options: NormalizedSchema): Rule {
|
||||||
return updateJsonInTree('angular.json', json => {
|
return updateWorkspaceInTree(json => {
|
||||||
const architect: { [key: string]: any } = {};
|
const architect: { [key: string]: any } = {};
|
||||||
|
|
||||||
architect.lint = {
|
architect.lint = generateProjectLint(
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
normalize(options.projectRoot),
|
||||||
options: {
|
join(normalize(options.projectRoot), 'tsconfig.lib.json'),
|
||||||
tsConfig: [join(normalize(options.projectRoot), 'tsconfig.lib.json')],
|
options.linter
|
||||||
exclude: [
|
);
|
||||||
'**/node_modules/**',
|
|
||||||
'!' + join(normalize(options.projectRoot), '**')
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
json.projects[options.name] = {
|
json.projects[options.name] = {
|
||||||
root: options.projectRoot,
|
root: options.projectRoot,
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import { UnitTestRunner } from '../../utils/test-runners';
|
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
name: string;
|
name: string;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
@ -11,5 +9,6 @@ export interface Schema {
|
|||||||
pascalCaseFiles?: boolean;
|
pascalCaseFiles?: boolean;
|
||||||
routing?: boolean;
|
routing?: boolean;
|
||||||
parentRoute?: string;
|
parentRoute?: string;
|
||||||
unitTestRunner: UnitTestRunner;
|
unitTestRunner: 'jest' | 'none';
|
||||||
|
linter: 'eslint' | 'tslint';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,12 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "tslint"],
|
||||||
|
"default": "tslint"
|
||||||
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
|
|||||||
@ -27,13 +27,13 @@ describe('ng-add', () => {
|
|||||||
describe('defaultCollection', () => {
|
describe('defaultCollection', () => {
|
||||||
it('should be set if none was set before', async () => {
|
it('should be set if none was set before', async () => {
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/react');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/react');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be set if @nrwl/workspace was set before', async () => {
|
it('should be set if @nrwl/workspace was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/workspace'
|
defaultCollection: '@nrwl/workspace'
|
||||||
};
|
};
|
||||||
@ -43,13 +43,13 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/react');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/react');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be set if something else was set before', async () => {
|
it('should not be set if something else was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/angular'
|
defaultCollection: '@nrwl/angular'
|
||||||
};
|
};
|
||||||
@ -59,8 +59,8 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { readCliConfigFile, updateJsonFile } from '@nrwl/workspace';
|
import { readWorkspaceConfigPath, updateJsonFile } from '@nrwl/workspace';
|
||||||
import { writeFileSync, unlinkSync } from 'fs';
|
import { writeFileSync, unlinkSync } from 'fs';
|
||||||
import { offsetFromRoot } from '@nrwl/workspace';
|
import { offsetFromRoot } from '@nrwl/workspace';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
@ -6,7 +6,7 @@ import * as path from 'path';
|
|||||||
export default {
|
export default {
|
||||||
description: 'Create tsconfig.app.json for every app',
|
description: 'Create tsconfig.app.json for every app',
|
||||||
run: () => {
|
run: () => {
|
||||||
const config = readCliConfigFile();
|
const config = readWorkspaceConfigPath();
|
||||||
config.apps.forEach(app => {
|
config.apps.forEach(app => {
|
||||||
if (!app.root.startsWith('apps/')) return;
|
if (!app.root.startsWith('apps/')) return;
|
||||||
const offset = offsetFromRoot(app.root);
|
const offset = offsetFromRoot(app.root);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
|||||||
export default {
|
export default {
|
||||||
description: `Create nx.json before migrating to Angular CLI 6.`,
|
description: `Create nx.json before migrating to Angular CLI 6.`,
|
||||||
run: () => {
|
run: () => {
|
||||||
if (!existsSync('.angular-cli.json') && existsSync('angular.json')) {
|
if (!existsSync('.angular-cli.json') && existsSync('workspace.json')) {
|
||||||
console.warn(stripIndents`
|
console.warn(stripIndents`
|
||||||
You have already upgraded to Angular CLI 6.
|
You have already upgraded to Angular CLI 6.
|
||||||
We will not be able to recover information about your project's tags for you.
|
We will not be able to recover information about your project's tags for you.
|
||||||
@ -13,8 +13,8 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const angularJson = readJsonFile('.angular-cli.json');
|
const workspaceJson = readJsonFile('.angular-cli.json');
|
||||||
const projects = angularJson.apps.reduce((projects, app) => {
|
const projects = workspaceJson.apps.reduce((projects, app) => {
|
||||||
if (app.name === '$workspaceRoot') {
|
if (app.name === '$workspaceRoot') {
|
||||||
return projects;
|
return projects;
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ export default {
|
|||||||
writeFileSync(
|
writeFileSync(
|
||||||
'nx.json',
|
'nx.json',
|
||||||
serializeJson({
|
serializeJson({
|
||||||
npmScope: angularJson.project.npmScope,
|
npmScope: workspaceJson.project.npmScope,
|
||||||
projects: projects
|
projects: projects
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { join } from 'path';
|
|||||||
export default {
|
export default {
|
||||||
description: `Switch to Nx 6.0`,
|
description: `Switch to Nx 6.0`,
|
||||||
run: () => {
|
run: () => {
|
||||||
if (!existsSync('.angular-cli.json') && existsSync('angular.json')) {
|
if (!existsSync('.angular-cli.json') && existsSync('workspace.json')) {
|
||||||
console.warn(stripIndents`
|
console.warn(stripIndents`
|
||||||
You have already upgraded to Angular CLI 6.
|
You have already upgraded to Angular CLI 6.
|
||||||
We will not be able to recover information about your project's tags for you.
|
We will not be able to recover information about your project's tags for you.
|
||||||
|
|||||||
@ -10,7 +10,8 @@ import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
|
|||||||
import {
|
import {
|
||||||
createOrUpdate,
|
createOrUpdate,
|
||||||
readJsonInTree,
|
readJsonInTree,
|
||||||
updateJsonInTree
|
updateJsonInTree,
|
||||||
|
updateWorkspaceInTree
|
||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import { serializeJson, renameSync } from '@nrwl/workspace';
|
import { serializeJson, renameSync } from '@nrwl/workspace';
|
||||||
import { parseTarget, serializeTarget } from '@nrwl/workspace';
|
import { parseTarget, serializeTarget } from '@nrwl/workspace';
|
||||||
@ -256,8 +257,8 @@ function createTsconfigLibJson(host: Tree, project: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createAdditionalFiles(host: Tree) {
|
function createAdditionalFiles(host: Tree) {
|
||||||
const angularJson = readJsonInTree(host, 'angular.json');
|
const workspaceJson = readJsonInTree(host, 'workspace.json');
|
||||||
Object.entries<any>(angularJson.projects).forEach(([key, project]) => {
|
Object.entries<any>(workspaceJson.projects).forEach(([key, project]) => {
|
||||||
if (project.architect.test) {
|
if (project.architect.test) {
|
||||||
createTsconfigSpecJson(host, project);
|
createTsconfigSpecJson(host, project);
|
||||||
createKarma(host, project);
|
createKarma(host, project);
|
||||||
@ -282,9 +283,9 @@ function createAdditionalFiles(host: Tree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function moveE2eTests(host: Tree, context: SchematicContext) {
|
function moveE2eTests(host: Tree, context: SchematicContext) {
|
||||||
const angularJson = readJsonInTree(host, 'angular.json');
|
const workspaceJson = readJsonInTree(host, 'workspace.json');
|
||||||
|
|
||||||
Object.entries<any>(angularJson.projects).forEach(([key, p]) => {
|
Object.entries<any>(workspaceJson.projects).forEach(([key, p]) => {
|
||||||
if (p.projectType === 'application' && !p.architect.e2e) {
|
if (p.projectType === 'application' && !p.architect.e2e) {
|
||||||
renameSync(`${p.root}/e2e`, `${p.root}-e2e/src`, err => {
|
renameSync(`${p.root}/e2e`, `${p.root}-e2e/src`, err => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@ -320,9 +321,9 @@ function deleteUnneededFiles(host: Tree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function patchLibIndexFiles(host: Tree, context: SchematicContext) {
|
function patchLibIndexFiles(host: Tree, context: SchematicContext) {
|
||||||
const angularJson = readJsonInTree(host, 'angular.json');
|
const workspaceJson = readJsonInTree(host, 'workspace.json');
|
||||||
|
|
||||||
Object.entries<any>(angularJson.projects).forEach(([key, p]) => {
|
Object.entries<any>(workspaceJson.projects).forEach(([key, p]) => {
|
||||||
if (p.projectType === 'library') {
|
if (p.projectType === 'library') {
|
||||||
try {
|
try {
|
||||||
// TODO: incorporate this into fileutils.renameSync
|
// TODO: incorporate this into fileutils.renameSync
|
||||||
@ -489,8 +490,8 @@ function createDefaultE2eTsConfig(host: Tree, project: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateTsConfigs(host: Tree) {
|
function updateTsConfigs(host: Tree) {
|
||||||
const angularJson = readJsonInTree(host, 'angular.json');
|
const workspaceJson = readJsonInTree(host, 'workspace.json');
|
||||||
Object.entries<any>(angularJson.projects).forEach(([key, project]) => {
|
Object.entries<any>(workspaceJson.projects).forEach(([key, project]) => {
|
||||||
if (
|
if (
|
||||||
project.architect.build &&
|
project.architect.build &&
|
||||||
project.architect.build.options.main.startsWith('apps')
|
project.architect.build.options.main.startsWith('apps')
|
||||||
@ -562,7 +563,7 @@ function updateTsConfigs(host: Tree) {
|
|||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateAngularJson = updateJsonInTree('angular.json', json => {
|
const updateworkspaceJson = updateWorkspaceInTree(json => {
|
||||||
json.newProjectRoot = '';
|
json.newProjectRoot = '';
|
||||||
json.cli = {
|
json.cli = {
|
||||||
...json.cli,
|
...json.cli,
|
||||||
@ -681,7 +682,7 @@ function addInstallTask(host: Tree, context: SchematicContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkCli6Upgraded(host: Tree) {
|
function checkCli6Upgraded(host: Tree) {
|
||||||
if (!host.exists('angular.json') && host.exists('.angular-cli.json')) {
|
if (!host.exists('workspace.json') && host.exists('.angular-cli.json')) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Please install the latest version and run ng update @angular/cli first'
|
'Please install the latest version and run ng update @angular/cli first'
|
||||||
);
|
);
|
||||||
@ -701,7 +702,7 @@ export default function(): Rule {
|
|||||||
return chain([
|
return chain([
|
||||||
checkCli6Upgraded,
|
checkCli6Upgraded,
|
||||||
updatePackageJson,
|
updatePackageJson,
|
||||||
updateAngularJson,
|
updateworkspaceJson,
|
||||||
moveE2eTests,
|
moveE2eTests,
|
||||||
updateTsConfigs,
|
updateTsConfigs,
|
||||||
createAdditionalFiles,
|
createAdditionalFiles,
|
||||||
|
|||||||
@ -25,7 +25,7 @@ const addImplicitDependencies = updateJsonInTree<NxJson>('nx.json', nxJson => {
|
|||||||
return {
|
return {
|
||||||
...nxJson,
|
...nxJson,
|
||||||
implicitDependencies: {
|
implicitDependencies: {
|
||||||
'angular.json': '*',
|
'workspace.json': '*',
|
||||||
'package.json': '*',
|
'package.json': '*',
|
||||||
'tsconfig.json': '*',
|
'tsconfig.json': '*',
|
||||||
'tslint.json': '*',
|
'tslint.json': '*',
|
||||||
|
|||||||
@ -15,7 +15,7 @@ describe('Update 7.2.0', () => {
|
|||||||
scripts: {}
|
scripts: {}
|
||||||
});
|
});
|
||||||
createJson('tsconfig.json', {});
|
createJson('tsconfig.json', {});
|
||||||
createJson('angular.json', {
|
createJson('workspace.json', {
|
||||||
projects: {
|
projects: {
|
||||||
app1: {
|
app1: {
|
||||||
root: 'apps/app1',
|
root: 'apps/app1',
|
||||||
@ -321,7 +321,7 @@ describe('Update 7.2.0', () => {
|
|||||||
it('should fix cypress lint configs', async () => {
|
it('should fix cypress lint configs', async () => {
|
||||||
initialTree = await schematicRunner
|
initialTree = await schematicRunner
|
||||||
.callRule(
|
.callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.projects['app2-e2e'].architect.lint.options.tsConfig =
|
json.projects['app2-e2e'].architect.lint.options.tsConfig =
|
||||||
'e2e/tsconfig.e2e.json';
|
'e2e/tsconfig.e2e.json';
|
||||||
return json;
|
return json;
|
||||||
@ -333,8 +333,8 @@ describe('Update 7.2.0', () => {
|
|||||||
.runSchematicAsync('update-7.2.0', {}, initialTree)
|
.runSchematicAsync('update-7.2.0', {}, initialTree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
expect(
|
expect(
|
||||||
readJsonInTree(result, 'angular.json').projects['app2-e2e'].architect.lint
|
readJsonInTree(result, 'workspace.json').projects['app2-e2e'].architect
|
||||||
.options.tsConfig
|
.lint.options.tsConfig
|
||||||
).toEqual('apps/app2-e2e/tsconfig.e2e.json');
|
).toEqual('apps/app2-e2e/tsconfig.e2e.json');
|
||||||
[
|
[
|
||||||
'/apps/app1/tsconfig.app.json',
|
'/apps/app1/tsconfig.app.json',
|
||||||
@ -358,7 +358,7 @@ describe('Update 7.2.0', () => {
|
|||||||
it('should not fail for non-existing tsconfigs', async () => {
|
it('should not fail for non-existing tsconfigs', async () => {
|
||||||
initialTree = await schematicRunner
|
initialTree = await schematicRunner
|
||||||
.callRule(
|
.callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.projects['app2'].architect.lint.options.tsConfig =
|
json.projects['app2'].architect.lint.options.tsConfig =
|
||||||
'apps/nonexistent/tsconfig.app.json';
|
'apps/nonexistent/tsconfig.app.json';
|
||||||
return json;
|
return json;
|
||||||
|
|||||||
@ -10,7 +10,11 @@ import { normalize, join, Path, dirname } from '@angular-devkit/core';
|
|||||||
|
|
||||||
import { relative } from 'path';
|
import { relative } from 'path';
|
||||||
|
|
||||||
import { updateJsonInTree, readJsonInTree } from '@nrwl/workspace';
|
import {
|
||||||
|
updateJsonInTree,
|
||||||
|
readJsonInTree,
|
||||||
|
updateWorkspaceInTree
|
||||||
|
} from '@nrwl/workspace';
|
||||||
import { getWorkspacePath } from '@nrwl/workspace';
|
import { getWorkspacePath } from '@nrwl/workspace';
|
||||||
import { offsetFromRoot, addUpdateTask } from '@nrwl/workspace';
|
import { offsetFromRoot, addUpdateTask } from '@nrwl/workspace';
|
||||||
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||||
@ -159,9 +163,9 @@ function updateTsConfigs(project: any): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fixCypressConfigs(host: Tree, context: SchematicContext): Rule {
|
function fixCypressConfigs(host: Tree, context: SchematicContext): Rule {
|
||||||
const angularJson = readJsonInTree(host, 'angular.json');
|
const workspaceJson = readJsonInTree(host, 'workspace.json');
|
||||||
return chain(
|
return chain(
|
||||||
Object.entries<any>(angularJson.projects)
|
Object.entries<any>(workspaceJson.projects)
|
||||||
.filter(
|
.filter(
|
||||||
([key, project]) =>
|
([key, project]) =>
|
||||||
project.architect.e2e &&
|
project.architect.e2e &&
|
||||||
@ -175,12 +179,12 @@ function fixCypressConfigs(host: Tree, context: SchematicContext): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fixCypressConfig(project: any, projectKey: string): Rule {
|
function fixCypressConfig(project: any, projectKey: string): Rule {
|
||||||
return updateJsonInTree('angular.json', angularJson => {
|
return updateWorkspaceInTree(workspaceJson => {
|
||||||
angularJson.projects[projectKey].architect.lint.options.tsConfig = join(
|
workspaceJson.projects[projectKey].architect.lint.options.tsConfig = join(
|
||||||
project.root,
|
project.root,
|
||||||
'tsconfig.e2e.json'
|
'tsconfig.e2e.json'
|
||||||
);
|
);
|
||||||
return angularJson;
|
return workspaceJson;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,15 +5,16 @@ import * as path from 'path';
|
|||||||
|
|
||||||
import { serializeJson } from '@nrwl/workspace';
|
import { serializeJson } from '@nrwl/workspace';
|
||||||
import { readJsonInTree } from '@nrwl/workspace';
|
import { readJsonInTree } from '@nrwl/workspace';
|
||||||
|
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||||
|
|
||||||
describe('Update 7.5.0', () => {
|
describe('Update 7.5.0', () => {
|
||||||
let initialTree: Tree;
|
let initialTree: Tree;
|
||||||
let schematicRunner: SchematicTestRunner;
|
let schematicRunner: SchematicTestRunner;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
initialTree = Tree.empty();
|
initialTree = createEmptyWorkspace(Tree.empty());
|
||||||
|
|
||||||
initialTree.create(
|
initialTree.overwrite(
|
||||||
'package.json',
|
'package.json',
|
||||||
serializeJson({
|
serializeJson({
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { join } from 'path';
|
|||||||
import { serializeJson } from '@nrwl/workspace';
|
import { serializeJson } from '@nrwl/workspace';
|
||||||
import { readJsonInTree, updateJsonInTree } from '@nrwl/workspace';
|
import { readJsonInTree, updateJsonInTree } from '@nrwl/workspace';
|
||||||
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||||
|
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||||
|
|
||||||
const effectContents = `
|
const effectContents = `
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
@ -77,9 +78,9 @@ describe('Update 7.6.0', () => {
|
|||||||
let schematicRunner: SchematicTestRunner;
|
let schematicRunner: SchematicTestRunner;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
initialTree = new UnitTestTree(Tree.empty());
|
initialTree = createEmptyWorkspace(Tree.empty());
|
||||||
|
|
||||||
initialTree.create(
|
initialTree.overwrite(
|
||||||
'package.json',
|
'package.json',
|
||||||
serializeJson({
|
serializeJson({
|
||||||
dependencies: {
|
dependencies: {
|
||||||
@ -159,22 +160,22 @@ describe('Update 7.6.0', () => {
|
|||||||
.toPromise();
|
.toPromise();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
readJsonInTree(result, 'angular.json').schematics[
|
readJsonInTree(result, 'workspace.json').schematics[
|
||||||
'@nrwl/schematics:library'
|
'@nrwl/schematics:library'
|
||||||
].unitTestRunner
|
].unitTestRunner
|
||||||
).toEqual('karma');
|
).toEqual('karma');
|
||||||
expect(
|
expect(
|
||||||
readJsonInTree(result, 'angular.json').schematics[
|
readJsonInTree(result, 'workspace.json').schematics[
|
||||||
'@nrwl/schematics:application'
|
'@nrwl/schematics:application'
|
||||||
].unitTestRunner
|
].unitTestRunner
|
||||||
).toEqual('karma');
|
).toEqual('karma');
|
||||||
expect(
|
expect(
|
||||||
readJsonInTree(result, 'angular.json').schematics[
|
readJsonInTree(result, 'workspace.json').schematics[
|
||||||
'@nrwl/schematics:application'
|
'@nrwl/schematics:application'
|
||||||
].e2eTestRunner
|
].e2eTestRunner
|
||||||
).toEqual('protractor');
|
).toEqual('protractor');
|
||||||
expect(
|
expect(
|
||||||
readJsonInTree(result, 'angular.json').schematics[
|
readJsonInTree(result, 'workspace.json').schematics[
|
||||||
'@nrwl/schematics:node-application'
|
'@nrwl/schematics:node-application'
|
||||||
].framework
|
].framework
|
||||||
).toEqual('express');
|
).toEqual('express');
|
||||||
|
|||||||
@ -8,7 +8,8 @@ import {
|
|||||||
formatFiles,
|
formatFiles,
|
||||||
insert,
|
insert,
|
||||||
readJsonInTree,
|
readJsonInTree,
|
||||||
updateJsonInTree
|
updateJsonInTree,
|
||||||
|
updateWorkspaceInTree
|
||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import {
|
import {
|
||||||
getSourceNodes,
|
getSourceNodes,
|
||||||
@ -371,7 +372,7 @@ const addDotEnv = updateJsonInTree('package.json', json => {
|
|||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
|
||||||
const setDefaults = updateJsonInTree('angular.json', json => {
|
const setDefaults = updateWorkspaceInTree(json => {
|
||||||
if (!json.schematics) {
|
if (!json.schematics) {
|
||||||
json.schematics = {};
|
json.schematics = {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,13 +7,14 @@ import {
|
|||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { readJsonInTree } from '@nrwl/workspace';
|
import { readJsonInTree } from '@nrwl/workspace';
|
||||||
import { serializeJson } from '@nrwl/workspace';
|
import { serializeJson } from '@nrwl/workspace';
|
||||||
|
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||||
|
|
||||||
describe('Update 7.7.0', () => {
|
describe('Update 7.7.0', () => {
|
||||||
let initialTree: Tree;
|
let initialTree: Tree;
|
||||||
let schematicRunner: SchematicTestRunner;
|
let schematicRunner: SchematicTestRunner;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
initialTree = new UnitTestTree(Tree.empty());
|
initialTree = createEmptyWorkspace(Tree.empty());
|
||||||
|
|
||||||
schematicRunner = new SchematicTestRunner(
|
schematicRunner = new SchematicTestRunner(
|
||||||
'@nrwl/schematics',
|
'@nrwl/schematics',
|
||||||
@ -28,7 +29,7 @@ describe('Update 7.7.0', () => {
|
|||||||
.toPromise();
|
.toPromise();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
readJsonInTree(result, 'angular.json').schematics[
|
readJsonInTree(result, 'workspace.json').schematics[
|
||||||
'@nrwl/schematics:library'
|
'@nrwl/schematics:library'
|
||||||
].framework
|
].framework
|
||||||
).toEqual('angular');
|
).toEqual('angular');
|
||||||
@ -37,7 +38,7 @@ describe('Update 7.7.0', () => {
|
|||||||
|
|
||||||
describe('jest update', () => {
|
describe('jest update', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
initialTree.create(
|
initialTree.overwrite(
|
||||||
'package.json',
|
'package.json',
|
||||||
serializeJson({
|
serializeJson({
|
||||||
devDependencies: {
|
devDependencies: {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { chain, Rule, Tree } from '@angular-devkit/schematics';
|
import { chain, Rule, Tree } from '@angular-devkit/schematics';
|
||||||
|
|
||||||
import { updateJsonInTree, insert } from '@nrwl/workspace';
|
import { updateJsonInTree, insert } from '@nrwl/workspace';
|
||||||
import { formatFiles } from '@nrwl/workspace';
|
import { formatFiles, updateWorkspaceInTree } from '@nrwl/workspace';
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {
|
import {
|
||||||
@ -9,7 +9,7 @@ import {
|
|||||||
ReplaceChange
|
ReplaceChange
|
||||||
} from '@nrwl/workspace/src/utils/ast-utils';
|
} from '@nrwl/workspace/src/utils/ast-utils';
|
||||||
|
|
||||||
const setDefaults = updateJsonInTree('angular.json', json => {
|
const setDefaults = updateWorkspaceInTree(json => {
|
||||||
if (!json.schematics) {
|
if (!json.schematics) {
|
||||||
json.schematics = {};
|
json.schematics = {};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,14 +3,15 @@ import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
|||||||
import { serializeJson } from '@nrwl/workspace';
|
import { serializeJson } from '@nrwl/workspace';
|
||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||||
|
|
||||||
describe('Update 7.8.1', () => {
|
describe('Update 7.8.1', () => {
|
||||||
let initialTree: Tree;
|
let initialTree: Tree;
|
||||||
let schematicRunner: SchematicTestRunner;
|
let schematicRunner: SchematicTestRunner;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
initialTree = Tree.empty();
|
initialTree = createEmptyWorkspace(Tree.empty());
|
||||||
initialTree.create(
|
initialTree.overwrite(
|
||||||
'package.json',
|
'package.json',
|
||||||
serializeJson({
|
serializeJson({
|
||||||
scripts: {}
|
scripts: {}
|
||||||
|
|||||||
@ -3,13 +3,14 @@ import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
|||||||
import { updateJsonInTree, readJsonInTree } from '@nrwl/workspace';
|
import { updateJsonInTree, readJsonInTree } from '@nrwl/workspace';
|
||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||||
|
|
||||||
describe('Update 8-0-0', () => {
|
describe('Update 8-0-0', () => {
|
||||||
let initialTree: Tree;
|
let initialTree: Tree;
|
||||||
let schematicRunner: SchematicTestRunner;
|
let schematicRunner: SchematicTestRunner;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
initialTree = Tree.empty();
|
initialTree = createEmptyWorkspace(Tree.empty());
|
||||||
schematicRunner = new SchematicTestRunner(
|
schematicRunner = new SchematicTestRunner(
|
||||||
'@nrwl/schematics',
|
'@nrwl/schematics',
|
||||||
path.join(__dirname, '../migrations.json')
|
path.join(__dirname, '../migrations.json')
|
||||||
@ -56,7 +57,7 @@ describe('Update 8-0-0', () => {
|
|||||||
.toPromise();
|
.toPromise();
|
||||||
initialTree = await schematicRunner
|
initialTree = await schematicRunner
|
||||||
.callRule(
|
.callRule(
|
||||||
updateJsonInTree('angular.json', json => ({
|
updateJsonInTree('workspace.json', json => ({
|
||||||
projects: {
|
projects: {
|
||||||
'my-app': {
|
'my-app': {
|
||||||
architect: {
|
architect: {
|
||||||
@ -158,7 +159,7 @@ describe('Update 8-0-0', () => {
|
|||||||
const tree = await schematicRunner
|
const tree = await schematicRunner
|
||||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
const { projects } = readJsonInTree(tree, 'angular.json');
|
const { projects } = readJsonInTree(tree, 'workspace.json');
|
||||||
const { architect } = projects['my-app'];
|
const { architect } = projects['my-app'];
|
||||||
expect(architect.cypress.builder).toEqual('@nrwl/cypress:cypress');
|
expect(architect.cypress.builder).toEqual('@nrwl/cypress:cypress');
|
||||||
expect(architect.jest.builder).toEqual('@nrwl/jest:jest');
|
expect(architect.jest.builder).toEqual('@nrwl/jest:jest');
|
||||||
@ -281,7 +282,7 @@ describe('Update 8-0-0', () => {
|
|||||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
|
|
||||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||||
.defaultCollection;
|
.defaultCollection;
|
||||||
expect(defaultCollection).toEqual('@nrwl/angular');
|
expect(defaultCollection).toEqual('@nrwl/angular');
|
||||||
});
|
});
|
||||||
@ -304,7 +305,7 @@ describe('Update 8-0-0', () => {
|
|||||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
|
|
||||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||||
.defaultCollection;
|
.defaultCollection;
|
||||||
expect(defaultCollection).toEqual('@nrwl/react');
|
expect(defaultCollection).toEqual('@nrwl/react');
|
||||||
});
|
});
|
||||||
@ -326,7 +327,7 @@ describe('Update 8-0-0', () => {
|
|||||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
|
|
||||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||||
.defaultCollection;
|
.defaultCollection;
|
||||||
expect(defaultCollection).toEqual('@nrwl/nest');
|
expect(defaultCollection).toEqual('@nrwl/nest');
|
||||||
});
|
});
|
||||||
@ -347,7 +348,7 @@ describe('Update 8-0-0', () => {
|
|||||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
|
|
||||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||||
.defaultCollection;
|
.defaultCollection;
|
||||||
expect(defaultCollection).toEqual('@nrwl/express');
|
expect(defaultCollection).toEqual('@nrwl/express');
|
||||||
});
|
});
|
||||||
@ -368,7 +369,7 @@ describe('Update 8-0-0', () => {
|
|||||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
|
|
||||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||||
.defaultCollection;
|
.defaultCollection;
|
||||||
expect(defaultCollection).toEqual('@nrwl/express');
|
expect(defaultCollection).toEqual('@nrwl/express');
|
||||||
});
|
});
|
||||||
@ -385,7 +386,7 @@ describe('Update 8-0-0', () => {
|
|||||||
.toPromise();
|
.toPromise();
|
||||||
initialTree = await schematicRunner
|
initialTree = await schematicRunner
|
||||||
.callRule(
|
.callRule(
|
||||||
updateJsonInTree('angular.json', json => ({
|
updateJsonInTree('workspace.json', json => ({
|
||||||
...json,
|
...json,
|
||||||
projects: {}
|
projects: {}
|
||||||
})),
|
})),
|
||||||
@ -396,7 +397,7 @@ describe('Update 8-0-0', () => {
|
|||||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
|
|
||||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||||
.defaultCollection;
|
.defaultCollection;
|
||||||
expect(defaultCollection).toEqual('@nrwl/workspace');
|
expect(defaultCollection).toEqual('@nrwl/workspace');
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,7 +11,8 @@ import {
|
|||||||
insert,
|
insert,
|
||||||
readJsonInTree,
|
readJsonInTree,
|
||||||
updateJsonInTree,
|
updateJsonInTree,
|
||||||
addUpdateTask
|
addUpdateTask,
|
||||||
|
updateWorkspaceInTree
|
||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import {
|
import {
|
||||||
createSourceFile,
|
createSourceFile,
|
||||||
@ -31,7 +32,7 @@ function addDependencies() {
|
|||||||
return (host: Tree, context: SchematicContext) => {
|
return (host: Tree, context: SchematicContext) => {
|
||||||
const dependencies = readJsonInTree(host, 'package.json').dependencies;
|
const dependencies = readJsonInTree(host, 'package.json').dependencies;
|
||||||
const builders = new Set<string>();
|
const builders = new Set<string>();
|
||||||
const projects = readJsonInTree(host, 'angular.json').projects;
|
const projects = readJsonInTree(host, 'workspace.json').projects;
|
||||||
Object.values<any>(projects)
|
Object.values<any>(projects)
|
||||||
.filter(
|
.filter(
|
||||||
project =>
|
project =>
|
||||||
@ -110,7 +111,7 @@ const updateUpdateScript = updateJsonInTree('package.json', json => {
|
|||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateBuilders = updateJsonInTree('angular.json', json => {
|
const updateBuilders = updateWorkspaceInTree(json => {
|
||||||
if (!json.projects) {
|
if (!json.projects) {
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
@ -285,7 +286,7 @@ const updateDefaultCollection = (host: Tree, context: SchematicContext) => {
|
|||||||
'package.json'
|
'package.json'
|
||||||
);
|
);
|
||||||
|
|
||||||
return updateJsonInTree('angular.json', json => {
|
return updateWorkspaceInTree(json => {
|
||||||
json.cli = json.cli || {};
|
json.cli = json.cli || {};
|
||||||
if (dependencies['@nrwl/angular']) {
|
if (dependencies['@nrwl/angular']) {
|
||||||
json.cli.defaultCollection = '@nrwl/angular';
|
json.cli.defaultCollection = '@nrwl/angular';
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import { updateJsonFile, readCliConfigFile } from '@nrwl/workspace';
|
import { updateJsonFile, readWorkspaceConfigPath } from '@nrwl/workspace';
|
||||||
|
|
||||||
type Migration = { description: string; run(): void };
|
type Migration = { description: string; run(): void };
|
||||||
type MigrationName = { name: string; migration: Migration };
|
type MigrationName = { name: string; migration: Migration };
|
||||||
@ -32,7 +32,7 @@ updateLatestMigration();
|
|||||||
console.log('All migrations run successfully');
|
console.log('All migrations run successfully');
|
||||||
|
|
||||||
function readLatestMigration(): string {
|
function readLatestMigration(): string {
|
||||||
const angularCli = readCliConfigFile();
|
const angularCli = readWorkspaceConfigPath();
|
||||||
return angularCli.project.latestMigration;
|
return angularCli.project.latestMigration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
44
packages/tao/index.ts
Normal file
44
packages/tao/index.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import './src/compat/angular-cli-compat';
|
||||||
|
|
||||||
|
export async function invokeCommand(
|
||||||
|
command: string,
|
||||||
|
root: string,
|
||||||
|
commandArgs: string[]
|
||||||
|
) {
|
||||||
|
if (command === undefined) {
|
||||||
|
command = 'help';
|
||||||
|
}
|
||||||
|
switch (command) {
|
||||||
|
case 'new':
|
||||||
|
return (await import('./src/commands/generate')).taoNew(
|
||||||
|
root,
|
||||||
|
commandArgs
|
||||||
|
);
|
||||||
|
case 'generate':
|
||||||
|
case 'g':
|
||||||
|
return (await import('./src/commands/generate')).generate(
|
||||||
|
root,
|
||||||
|
commandArgs
|
||||||
|
);
|
||||||
|
case 'run':
|
||||||
|
case 'r':
|
||||||
|
return (await import('./src/commands/run')).run(root, commandArgs);
|
||||||
|
case 'help':
|
||||||
|
case '--help':
|
||||||
|
return (await import('./src/commands/help')).printHelp();
|
||||||
|
default:
|
||||||
|
// this is to make `tao test mylib` same as `tao run mylib:test`
|
||||||
|
return (await import('./src/commands/run')).run(root, [
|
||||||
|
`${commandArgs[0]}:${command}`,
|
||||||
|
...commandArgs.slice(1)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function invokeCli(root: string, args: string[]) {
|
||||||
|
const [command, ...commandArgs] = args;
|
||||||
|
process.exit(await invokeCommand(command, root, commandArgs));
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeCli(process.cwd(), process.argv.slice(2));
|
||||||
41
packages/tao/package.json
Normal file
41
packages/tao/package.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "@nrwl/tao",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "CLI for generating code and running commands",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/nrwl/nx.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"Monorepo",
|
||||||
|
"Angular",
|
||||||
|
"React",
|
||||||
|
"Web",
|
||||||
|
"Node",
|
||||||
|
"Nest",
|
||||||
|
"Jest",
|
||||||
|
"Cypress",
|
||||||
|
"CLI"
|
||||||
|
],
|
||||||
|
"main": "index.js",
|
||||||
|
"types": "index.d.ts",
|
||||||
|
"author": "Victor Savkin",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/nrwl/nx/issues"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"tao": "./index.js"
|
||||||
|
},
|
||||||
|
"homepage": "https://nx.dev",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@nrwl/workspace": "*"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@angular-devkit/schematics": "8.1.1",
|
||||||
|
"@angular-devkit/core": "8.1.1",
|
||||||
|
"@angular-devkit/architect": "0.801.1",
|
||||||
|
"inquirer": "^6.3.1",
|
||||||
|
"minimist": "^1.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
354
packages/tao/src/commands/generate.ts
Normal file
354
packages/tao/src/commands/generate.ts
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
import {
|
||||||
|
convertToCamelCase,
|
||||||
|
handleErrors,
|
||||||
|
Schema,
|
||||||
|
coerceTypes
|
||||||
|
} from '../shared/params';
|
||||||
|
import {
|
||||||
|
JsonObject,
|
||||||
|
logging,
|
||||||
|
normalize,
|
||||||
|
schema,
|
||||||
|
tags,
|
||||||
|
terminal,
|
||||||
|
virtualFs,
|
||||||
|
experimental
|
||||||
|
} from '@angular-devkit/core';
|
||||||
|
import { DryRunEvent, HostTree, Schematic } from '@angular-devkit/schematics';
|
||||||
|
import { NodeJsSyncHost } from '@angular-devkit/core/node';
|
||||||
|
import { NodeWorkflow } from '@angular-devkit/schematics/tools';
|
||||||
|
import * as inquirer from 'inquirer';
|
||||||
|
import { logger } from '../shared/logger';
|
||||||
|
import { printHelp, commandName } from '../shared/print-help';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import minimist = require('minimist');
|
||||||
|
|
||||||
|
interface GenerateOptions {
|
||||||
|
collectionName: string;
|
||||||
|
schematicName: string;
|
||||||
|
schematicOptions: { [k: string]: string };
|
||||||
|
help: boolean;
|
||||||
|
debug: boolean;
|
||||||
|
dryRun: boolean;
|
||||||
|
force: boolean;
|
||||||
|
interactive: boolean;
|
||||||
|
defaults: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function throwInvalidInvocation() {
|
||||||
|
throw new Error(
|
||||||
|
`Specify the schematic name (e.g., ${commandName} generate collection-name:schematic-name)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseGenerateOpts(
|
||||||
|
args: string[],
|
||||||
|
mode: 'generate' | 'new',
|
||||||
|
defaultCollection: string | null
|
||||||
|
): GenerateOptions {
|
||||||
|
const schematicOptions = convertToCamelCase(
|
||||||
|
minimist(args, {
|
||||||
|
boolean: ['help', 'dryRun', 'debug', 'force', 'interactive'],
|
||||||
|
alias: {
|
||||||
|
dryRun: 'dry-run'
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
debug: false,
|
||||||
|
dryRun: false,
|
||||||
|
interactive: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
let collectionName = null;
|
||||||
|
let schematicName = null;
|
||||||
|
if (mode === 'generate') {
|
||||||
|
if (!schematicOptions['_'] || schematicOptions['_'].length === 0) {
|
||||||
|
throwInvalidInvocation();
|
||||||
|
}
|
||||||
|
[collectionName, schematicName] = schematicOptions['_'].shift()!.split(':');
|
||||||
|
if (!schematicName) {
|
||||||
|
schematicName = collectionName;
|
||||||
|
collectionName = defaultCollection;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
collectionName = schematicOptions.collection;
|
||||||
|
schematicName = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!collectionName) {
|
||||||
|
throwInvalidInvocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = {
|
||||||
|
collectionName,
|
||||||
|
schematicName,
|
||||||
|
schematicOptions,
|
||||||
|
help: schematicOptions.help,
|
||||||
|
debug: schematicOptions.debug,
|
||||||
|
dryRun: schematicOptions.dryRun,
|
||||||
|
force: schematicOptions.force,
|
||||||
|
interactive: schematicOptions.interactive,
|
||||||
|
defaults: schematicOptions.defaults
|
||||||
|
};
|
||||||
|
|
||||||
|
delete schematicOptions.debug;
|
||||||
|
delete schematicOptions.dryRun;
|
||||||
|
delete schematicOptions.force;
|
||||||
|
delete schematicOptions.interactive;
|
||||||
|
delete schematicOptions.defaults;
|
||||||
|
delete schematicOptions.help;
|
||||||
|
delete schematicOptions['--'];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRecorder(record: any, logger: logging.Logger) {
|
||||||
|
return (event: DryRunEvent) => {
|
||||||
|
const eventPath = event.path.startsWith('/')
|
||||||
|
? event.path.substr(1)
|
||||||
|
: event.path;
|
||||||
|
if (event.kind === 'error') {
|
||||||
|
record.error = true;
|
||||||
|
logger.warn(
|
||||||
|
`ERROR! ${eventPath} ${
|
||||||
|
event.description == 'alreadyExist'
|
||||||
|
? 'already exists'
|
||||||
|
: 'does not exist.'
|
||||||
|
}.`
|
||||||
|
);
|
||||||
|
} else if (event.kind === 'update') {
|
||||||
|
record.loggingQueue.push(
|
||||||
|
tags.oneLine`${terminal.white('UPDATE')} ${eventPath} (${
|
||||||
|
event.content.length
|
||||||
|
} bytes)`
|
||||||
|
);
|
||||||
|
} else if (event.kind === 'create') {
|
||||||
|
record.loggingQueue.push(
|
||||||
|
tags.oneLine`${terminal.green('CREATE')} ${eventPath} (${
|
||||||
|
event.content.length
|
||||||
|
} bytes)`
|
||||||
|
);
|
||||||
|
} else if (event.kind === 'delete') {
|
||||||
|
record.loggingQueue.push(`${terminal.yellow('DELETE')} ${eventPath}`);
|
||||||
|
} else if (event.kind === 'rename') {
|
||||||
|
record.loggingQueue.push(
|
||||||
|
`${terminal.blue('RENAME')} ${eventPath} => ${event.to}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWorkflow(
|
||||||
|
fsHost: virtualFs.Host<fs.Stats>,
|
||||||
|
root: string,
|
||||||
|
opts: GenerateOptions
|
||||||
|
) {
|
||||||
|
const workflow = new NodeWorkflow(fsHost, {
|
||||||
|
force: opts.force,
|
||||||
|
dryRun: opts.dryRun,
|
||||||
|
packageManager: 'yarn',
|
||||||
|
root: normalize(root)
|
||||||
|
});
|
||||||
|
const _params = opts.schematicOptions._;
|
||||||
|
delete opts.schematicOptions._;
|
||||||
|
workflow.registry.addSmartDefaultProvider('argv', (schema: JsonObject) => {
|
||||||
|
if ('index' in schema) {
|
||||||
|
return _params[Number(schema['index'])];
|
||||||
|
} else {
|
||||||
|
return _params;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opts.interactive !== false && isTTY()) {
|
||||||
|
workflow.registry.usePromptProvider(
|
||||||
|
(definitions: Array<schema.PromptDefinition>) => {
|
||||||
|
const questions: inquirer.Questions = definitions.map(definition => {
|
||||||
|
const question = {
|
||||||
|
name: definition.id,
|
||||||
|
message: definition.message,
|
||||||
|
default: definition.default as any
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const validator = definition.validator;
|
||||||
|
if (validator) {
|
||||||
|
question.validate = (input: any) => validator(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (definition.type) {
|
||||||
|
case 'confirmation':
|
||||||
|
question.type = 'confirm';
|
||||||
|
break;
|
||||||
|
case 'list':
|
||||||
|
question.type = !!definition.multiselect ? 'checkbox' : 'list';
|
||||||
|
question.choices =
|
||||||
|
definition.items &&
|
||||||
|
definition.items.map(item => {
|
||||||
|
if (typeof item == 'string') {
|
||||||
|
return item;
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
name: item.label,
|
||||||
|
value: item.value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
question.type = definition.type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return question;
|
||||||
|
});
|
||||||
|
|
||||||
|
return inquirer.prompt(questions);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return workflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCollection(workflow: NodeWorkflow, name: string) {
|
||||||
|
const collection = workflow.engine.createCollection(name);
|
||||||
|
if (!collection) throw new Error(`Cannot find collection '${name}'`);
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printGenHelp(opts: GenerateOptions, schema: Schema) {
|
||||||
|
printHelp(
|
||||||
|
`${commandName} generate ${opts.collectionName}:${opts.schematicName}`,
|
||||||
|
schema
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getSchematicDefaults(
|
||||||
|
root: string,
|
||||||
|
collection: string,
|
||||||
|
schematic: string
|
||||||
|
) {
|
||||||
|
const workspace = await new experimental.workspace.Workspace(
|
||||||
|
normalize(root) as any,
|
||||||
|
new NodeJsSyncHost()
|
||||||
|
)
|
||||||
|
.loadWorkspaceFromHost('workspace.json' as any)
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
|
let result = {};
|
||||||
|
if (workspace.getSchematics()) {
|
||||||
|
const schematicObject = workspace.getSchematics()[
|
||||||
|
`${collection}:${schematic}`
|
||||||
|
];
|
||||||
|
if (schematicObject) {
|
||||||
|
result = { ...result, ...(schematicObject as {}) };
|
||||||
|
}
|
||||||
|
const collectionObject = workspace.getSchematics()[collection];
|
||||||
|
if (
|
||||||
|
typeof collectionObject == 'object' &&
|
||||||
|
!Array.isArray(collectionObject)
|
||||||
|
) {
|
||||||
|
result = { ...result, ...(collectionObject[schematic] as {}) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runSchematic(
|
||||||
|
root: string,
|
||||||
|
workflow: NodeWorkflow,
|
||||||
|
logger: logging.Logger,
|
||||||
|
opts: GenerateOptions,
|
||||||
|
schematic: Schematic<any, any>
|
||||||
|
): Promise<number> {
|
||||||
|
const flattenedSchema = await workflow.registry
|
||||||
|
.flatten(schematic.description.schemaJson!)
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
|
if (opts.help) {
|
||||||
|
printGenHelp(opts, flattenedSchema as any);
|
||||||
|
} else {
|
||||||
|
const defaults =
|
||||||
|
opts.schematicName === 'tao-new'
|
||||||
|
? {}
|
||||||
|
: await getSchematicDefaults(
|
||||||
|
root,
|
||||||
|
opts.collectionName,
|
||||||
|
opts.schematicName
|
||||||
|
);
|
||||||
|
const record = { loggingQueue: [] as string[], error: false };
|
||||||
|
workflow.reporter.subscribe(createRecorder(record, logger));
|
||||||
|
const schematicOptions = coerceTypes(
|
||||||
|
opts.schematicOptions,
|
||||||
|
flattenedSchema as any
|
||||||
|
);
|
||||||
|
await workflow
|
||||||
|
.execute({
|
||||||
|
collection: opts.collectionName,
|
||||||
|
schematic: opts.schematicName,
|
||||||
|
options: { ...defaults, ...schematicOptions },
|
||||||
|
debug: opts.debug,
|
||||||
|
logger
|
||||||
|
})
|
||||||
|
.toPromise();
|
||||||
|
if (!record.error) {
|
||||||
|
record.loggingQueue.forEach(log => logger.info(log));
|
||||||
|
}
|
||||||
|
if (opts.dryRun) {
|
||||||
|
logger.warn(`\nNOTE: The "dryRun" flag means no changes were made.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function generate(root: string, args: string[]) {
|
||||||
|
return handleErrors(logger, async () => {
|
||||||
|
const fsHost = new virtualFs.ScopedHost(
|
||||||
|
new NodeJsSyncHost(),
|
||||||
|
normalize(root)
|
||||||
|
);
|
||||||
|
const opts = parseGenerateOpts(
|
||||||
|
args,
|
||||||
|
'generate',
|
||||||
|
await readDefaultCollection(fsHost)
|
||||||
|
);
|
||||||
|
const workflow = createWorkflow(fsHost, root, opts);
|
||||||
|
const collection = getCollection(workflow, opts.collectionName);
|
||||||
|
const schematic = collection.createSchematic(opts.schematicName, true);
|
||||||
|
return runSchematic(
|
||||||
|
root,
|
||||||
|
workflow,
|
||||||
|
logger,
|
||||||
|
{ ...opts, schematicName: schematic.description.name },
|
||||||
|
schematic
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readDefaultCollection(host: virtualFs.Host<any>) {
|
||||||
|
const workspaceJson = JSON.parse(
|
||||||
|
new HostTree(host).read('workspace.json')!.toString()
|
||||||
|
);
|
||||||
|
return workspaceJson.cli ? workspaceJson.cli.defaultCollection : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function taoNew(root: string, args: string[]) {
|
||||||
|
return handleErrors(logger, async () => {
|
||||||
|
const fsHost = new virtualFs.ScopedHost(
|
||||||
|
new NodeJsSyncHost(),
|
||||||
|
normalize(root)
|
||||||
|
);
|
||||||
|
const opts = parseGenerateOpts(args, 'new', null);
|
||||||
|
const workflow = createWorkflow(fsHost, root, opts);
|
||||||
|
const collection = getCollection(workflow, opts.collectionName);
|
||||||
|
const schematic = collection.createSchematic('tao-new', true);
|
||||||
|
return runSchematic(
|
||||||
|
root,
|
||||||
|
workflow,
|
||||||
|
logger,
|
||||||
|
{ ...opts, schematicName: schematic.description.name },
|
||||||
|
schematic
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTTY(): boolean {
|
||||||
|
return !!process.stdout.isTTY && !!process.env['CI'];
|
||||||
|
}
|
||||||
35
packages/tao/src/commands/help.ts
Normal file
35
packages/tao/src/commands/help.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { tags } from '@angular-devkit/core';
|
||||||
|
import { logger } from '../shared/logger';
|
||||||
|
import { toolDescription, commandName } from '../shared/print-help';
|
||||||
|
import { terminal } from '@angular-devkit/core';
|
||||||
|
|
||||||
|
export function printHelp() {
|
||||||
|
logger.info(tags.stripIndent`
|
||||||
|
${terminal.bold(toolDescription)}
|
||||||
|
|
||||||
|
${terminal.bold('Create a new project.')}
|
||||||
|
${commandName} new ${terminal.grey(
|
||||||
|
'[project-name] [--collection=schematic-collection] [options, ...]'
|
||||||
|
)}
|
||||||
|
|
||||||
|
${terminal.bold('Generate code.')}
|
||||||
|
${commandName} generate ${terminal.grey(
|
||||||
|
'[schematic-collection:][schematic] [options, ...]'
|
||||||
|
)}
|
||||||
|
${commandName} g ${terminal.grey(
|
||||||
|
'[schematic-collection:][schematic] [options, ...]'
|
||||||
|
)}
|
||||||
|
|
||||||
|
${terminal.bold('Run target.')}
|
||||||
|
${commandName} run ${terminal.grey(
|
||||||
|
'[project][:target][:configuration] [options, ...]'
|
||||||
|
)}
|
||||||
|
${commandName} r ${terminal.grey(
|
||||||
|
'[project][:target][:configuration] [options, ...]'
|
||||||
|
)}
|
||||||
|
|
||||||
|
You can also use the infix notation to run a target:
|
||||||
|
${commandName} [target] [project] [options, ...]
|
||||||
|
`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
123
packages/tao/src/commands/run.ts
Normal file
123
packages/tao/src/commands/run.ts
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import {
|
||||||
|
convertToCamelCase,
|
||||||
|
handleErrors,
|
||||||
|
Schema,
|
||||||
|
coerceTypes
|
||||||
|
} from '../shared/params';
|
||||||
|
import {
|
||||||
|
experimental,
|
||||||
|
json,
|
||||||
|
normalize,
|
||||||
|
schema,
|
||||||
|
tags
|
||||||
|
} from '@angular-devkit/core';
|
||||||
|
import { NodeJsSyncHost } from '@angular-devkit/core/node';
|
||||||
|
import { WorkspaceNodeModulesArchitectHost } from '@angular-devkit/architect/node';
|
||||||
|
import { Architect } from '@angular-devkit/architect';
|
||||||
|
import { logger } from '../shared/logger';
|
||||||
|
import minimist = require('minimist');
|
||||||
|
import { printHelp, commandName } from '../shared/print-help';
|
||||||
|
|
||||||
|
export interface RunOptions {
|
||||||
|
project: string;
|
||||||
|
target: string;
|
||||||
|
configuration: string;
|
||||||
|
help: boolean;
|
||||||
|
runOptions: { [k: string]: any };
|
||||||
|
}
|
||||||
|
|
||||||
|
function throwInvalidInvocation() {
|
||||||
|
throw new Error(
|
||||||
|
`Specify the project name and the target (e.g., ${commandName} run proj:build)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRunOpts(
|
||||||
|
args: string[],
|
||||||
|
defaultProjectName: string | null
|
||||||
|
): RunOptions {
|
||||||
|
const runOptions = convertToCamelCase(
|
||||||
|
minimist(args, {
|
||||||
|
boolean: ['help', 'prod'],
|
||||||
|
string: ['configuration', 'project']
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const help = runOptions.help;
|
||||||
|
if (!runOptions._ || !runOptions._[0]) {
|
||||||
|
throwInvalidInvocation();
|
||||||
|
}
|
||||||
|
let [project, target, configuration] = runOptions._[0].split(':');
|
||||||
|
if (!project && defaultProjectName) project = defaultProjectName;
|
||||||
|
if (!project || !target) {
|
||||||
|
throwInvalidInvocation();
|
||||||
|
}
|
||||||
|
if (runOptions.configuration) {
|
||||||
|
configuration = runOptions.configuration;
|
||||||
|
}
|
||||||
|
if (runOptions.prod) {
|
||||||
|
configuration = 'production';
|
||||||
|
}
|
||||||
|
if (runOptions.project) {
|
||||||
|
project = runOptions.project;
|
||||||
|
}
|
||||||
|
const res = { project, target, configuration, help, runOptions };
|
||||||
|
delete runOptions['help'];
|
||||||
|
delete runOptions['_'];
|
||||||
|
delete runOptions['configuration'];
|
||||||
|
delete runOptions['prod'];
|
||||||
|
delete runOptions['project'];
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printRunHelp(opts: RunOptions, schema: Schema) {
|
||||||
|
printHelp(`${commandName} run ${opts.project}:${opts.target}`, schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function run(root: string, args: string[]) {
|
||||||
|
return handleErrors(logger, async () => {
|
||||||
|
const fsHost = new NodeJsSyncHost();
|
||||||
|
const workspace = await new experimental.workspace.Workspace(
|
||||||
|
normalize(root) as any,
|
||||||
|
fsHost
|
||||||
|
)
|
||||||
|
.loadWorkspaceFromHost('workspace.json' as any)
|
||||||
|
.toPromise();
|
||||||
|
const opts = parseRunOpts(args, workspace.getDefaultProjectName());
|
||||||
|
|
||||||
|
const registry = new json.schema.CoreSchemaRegistry();
|
||||||
|
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
|
||||||
|
const architectHost = new WorkspaceNodeModulesArchitectHost(
|
||||||
|
workspace,
|
||||||
|
root
|
||||||
|
);
|
||||||
|
const architect = new Architect(architectHost, registry);
|
||||||
|
|
||||||
|
const builderConf = await architectHost.getBuilderNameForTarget({
|
||||||
|
project: opts.project,
|
||||||
|
target: opts.target
|
||||||
|
});
|
||||||
|
const builderDesc = await architectHost.resolveBuilder(builderConf);
|
||||||
|
const flattenedSchema = await registry
|
||||||
|
.flatten(builderDesc.optionSchema! as json.JsonObject)
|
||||||
|
.toPromise();
|
||||||
|
if (opts.help) {
|
||||||
|
printRunHelp(opts, flattenedSchema as any);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
const runOptions = coerceTypes(opts.runOptions, flattenedSchema as any);
|
||||||
|
const run = await architect.scheduleTarget(
|
||||||
|
{
|
||||||
|
project: opts.project,
|
||||||
|
target: opts.target,
|
||||||
|
configuration: opts.configuration
|
||||||
|
},
|
||||||
|
runOptions,
|
||||||
|
{ logger }
|
||||||
|
);
|
||||||
|
const result = await run.output.toPromise();
|
||||||
|
await run.stop();
|
||||||
|
return result.success ? 0 : 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
24
packages/tao/src/compat/angular-cli-compat.ts
Normal file
24
packages/tao/src/compat/angular-cli-compat.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
const Module = require('module');
|
||||||
|
const originalRequire = Module.prototype.require;
|
||||||
|
|
||||||
|
Module.prototype.require = function() {
|
||||||
|
const result = originalRequire.apply(this, arguments);
|
||||||
|
if (arguments[0].startsWith('@angular-devkit/core')) {
|
||||||
|
const Workspace = originalRequire.apply(this, [
|
||||||
|
`@angular-devkit/core/src/experimental/workspace`
|
||||||
|
]).Workspace;
|
||||||
|
Workspace._workspaceFileNames = [
|
||||||
|
'workspace.json',
|
||||||
|
...Workspace._workspaceFileNames
|
||||||
|
];
|
||||||
|
const core = originalRequire.apply(this, [
|
||||||
|
`@angular-devkit/core/src/workspace/core`
|
||||||
|
]);
|
||||||
|
core._test_addWorkspaceFile('workspace.json', core.WorkspaceFormat.JSON);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
require('@angular-devkit/build-angular/src/utils/version').Version.assertCompatibleAngularVersion = () => {};
|
||||||
|
} catch (e) {}
|
||||||
13
packages/tao/src/shared/logger.ts
Normal file
13
packages/tao/src/shared/logger.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { createConsoleLogger } from '@angular-devkit/core/node';
|
||||||
|
import { terminal } from '@angular-devkit/core';
|
||||||
|
|
||||||
|
export const logger = createConsoleLogger(
|
||||||
|
false,
|
||||||
|
process.stdout,
|
||||||
|
process.stderr,
|
||||||
|
{
|
||||||
|
warn: s => terminal.bold(terminal.yellow(s)),
|
||||||
|
error: s => terminal.bold(terminal.red(s)),
|
||||||
|
fatal: s => terminal.bold(terminal.red(s))
|
||||||
|
}
|
||||||
|
);
|
||||||
35
packages/tao/src/shared/params.spec.ts
Normal file
35
packages/tao/src/shared/params.spec.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { convertToCamelCase } from './params';
|
||||||
|
|
||||||
|
describe('params', () => {
|
||||||
|
describe('convertToCamelCase', () => {
|
||||||
|
it('should convert dash case to camel case', () => {
|
||||||
|
expect(
|
||||||
|
convertToCamelCase({
|
||||||
|
'one-two': 1
|
||||||
|
})
|
||||||
|
).toEqual({
|
||||||
|
oneTwo: 1
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not convert camel case', () => {
|
||||||
|
expect(
|
||||||
|
convertToCamelCase({
|
||||||
|
oneTwo: 1
|
||||||
|
})
|
||||||
|
).toEqual({
|
||||||
|
oneTwo: 1
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle mixed case', () => {
|
||||||
|
expect(
|
||||||
|
convertToCamelCase({
|
||||||
|
'one-Two': 1
|
||||||
|
})
|
||||||
|
).toEqual({
|
||||||
|
oneTwo: 1
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
50
packages/tao/src/shared/params.ts
Normal file
50
packages/tao/src/shared/params.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { logging } from '@angular-devkit/core';
|
||||||
|
import { UnsuccessfulWorkflowExecution } from '@angular-devkit/schematics';
|
||||||
|
|
||||||
|
export type Schema = {
|
||||||
|
properties: { [p: string]: any };
|
||||||
|
required: string[];
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function handleErrors(logger: logging.Logger, fn: Function) {
|
||||||
|
try {
|
||||||
|
return await fn();
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof UnsuccessfulWorkflowExecution) {
|
||||||
|
logger.fatal('The Schematic workflow failed. See above.');
|
||||||
|
} else {
|
||||||
|
logger.fatal(err.message);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertToCamelCase(parsed: {
|
||||||
|
[k: string]: any;
|
||||||
|
}): { [k: string]: any } {
|
||||||
|
return Object.keys(parsed).reduce(
|
||||||
|
(m, c) => ({ ...m, [camelCase(c)]: parsed[c] }),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function camelCase(input: string): string {
|
||||||
|
if (input.indexOf('-') > 1) {
|
||||||
|
return input
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/-(.)/g, (match, group1) => group1.toUpperCase());
|
||||||
|
} else {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function coerceTypes(opts: { [k: string]: any }, schema: Schema) {
|
||||||
|
Object.keys(opts).forEach(k => {
|
||||||
|
if (schema.properties[k] && schema.properties[k].type == 'boolean') {
|
||||||
|
opts[k] = opts[k] === true || opts[k] === 'true';
|
||||||
|
} else if (schema.properties[k] && schema.properties[k].type == 'number') {
|
||||||
|
opts[k] = Number(opts[k]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
44
packages/tao/src/shared/print-help.ts
Normal file
44
packages/tao/src/shared/print-help.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { Schema } from './params';
|
||||||
|
import { logger } from './logger';
|
||||||
|
import { tags } from '@angular-devkit/core';
|
||||||
|
import { terminal } from '@angular-devkit/core';
|
||||||
|
|
||||||
|
export function printHelp(header: string, schema: Schema) {
|
||||||
|
const allPositional = Object.keys(schema.properties).filter(key => {
|
||||||
|
const p = schema.properties[key];
|
||||||
|
return p['$default'] && p['$default']['$source'] === 'argv';
|
||||||
|
});
|
||||||
|
const positional = allPositional.length > 0 ? ` [${allPositional[0]}]` : '';
|
||||||
|
const args = Object.keys(schema.properties)
|
||||||
|
.map(name => {
|
||||||
|
const d = schema.properties[name];
|
||||||
|
const def = d.default ? ` (default: ${d.default})` : '';
|
||||||
|
return formatOption(name, `${d.description}${def}`);
|
||||||
|
})
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
logger.info(tags.stripIndent`
|
||||||
|
${terminal.bold(header + positional + ' [options,...]')}
|
||||||
|
|
||||||
|
${terminal.bold('Options')}:
|
||||||
|
${args}
|
||||||
|
${formatOption('help', 'Show available options for project target.')}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatOption(name: string, description: string) {
|
||||||
|
return ` --${(name + ' ').substr(0, 22)}${terminal.grey(
|
||||||
|
description
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let commandName = 'nx';
|
||||||
|
export let toolDescription = 'Nx - Extensible Dev Tools for Monorepos.';
|
||||||
|
|
||||||
|
export function setCommandNameAndDescription(
|
||||||
|
name: string,
|
||||||
|
description: string
|
||||||
|
) {
|
||||||
|
commandName = name;
|
||||||
|
toolDescription = description;
|
||||||
|
}
|
||||||
@ -13,15 +13,15 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('not nested', () => {
|
describe('not nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-app'].root).toEqual('apps/my-app');
|
expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app');
|
||||||
expect(angularJson.projects['my-app-e2e'].root).toEqual(
|
expect(workspaceJson.projects['my-app-e2e'].root).toEqual(
|
||||||
'apps/my-app-e2e'
|
'apps/my-app-e2e'
|
||||||
);
|
);
|
||||||
expect(angularJson.defaultProject).toEqual('my-app');
|
expect(workspaceJson.defaultProject).toEqual('my-app');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update nx.json', async () => {
|
it('should update nx.json', async () => {
|
||||||
@ -78,18 +78,18 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('nested', () => {
|
describe('nested', () => {
|
||||||
it('should update angular.json', async () => {
|
it('should update workspace.json', async () => {
|
||||||
const tree = await runSchematic(
|
const tree = await runSchematic(
|
||||||
'app',
|
'app',
|
||||||
{ name: 'myApp', directory: 'myDir' },
|
{ name: 'myApp', directory: 'myDir' },
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||||
|
|
||||||
expect(angularJson.projects['my-dir-my-app'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-app'].root).toEqual(
|
||||||
'apps/my-dir/my-app'
|
'apps/my-dir/my-app'
|
||||||
);
|
);
|
||||||
expect(angularJson.projects['my-dir-my-app-e2e'].root).toEqual(
|
expect(workspaceJson.projects['my-dir-my-app-e2e'].root).toEqual(
|
||||||
'apps/my-dir/my-app-e2e'
|
'apps/my-dir/my-app-e2e'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -217,8 +217,8 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
const architectConfig = angularJson.projects['my-app'].architect;
|
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||||
expect(architectConfig.build.builder).toEqual('@nrwl/web:build');
|
expect(architectConfig.build.builder).toEqual('@nrwl/web:build');
|
||||||
expect(architectConfig.build.options).toEqual({
|
expect(architectConfig.build.options).toEqual({
|
||||||
assets: ['apps/my-app/src/favicon.ico', 'apps/my-app/src/assets'],
|
assets: ['apps/my-app/src/favicon.ico', 'apps/my-app/src/assets'],
|
||||||
@ -262,8 +262,8 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
const architectConfig = angularJson.projects['my-app'].architect;
|
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||||
expect(architectConfig.serve.builder).toEqual('@nrwl/web:dev-server');
|
expect(architectConfig.serve.builder).toEqual('@nrwl/web:dev-server');
|
||||||
expect(architectConfig.serve.options).toEqual({
|
expect(architectConfig.serve.options).toEqual({
|
||||||
buildTarget: 'my-app:build'
|
buildTarget: 'my-app:build'
|
||||||
@ -281,11 +281,12 @@ describe('app', () => {
|
|||||||
},
|
},
|
||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app'].architect.lint).toEqual({
|
|
||||||
|
expect(workspaceJson.projects['my-app'].architect.lint).toEqual({
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
builder: '@angular-devkit/build-angular:tslint',
|
||||||
options: {
|
options: {
|
||||||
exclude: ['**/node_modules/**'],
|
exclude: ['**/node_modules/**', '!apps/my-app/**'],
|
||||||
tsConfig: [
|
tsConfig: [
|
||||||
'apps/my-app/tsconfig.app.json',
|
'apps/my-app/tsconfig.app.json',
|
||||||
'apps/my-app/tsconfig.spec.json'
|
'apps/my-app/tsconfig.spec.json'
|
||||||
@ -318,10 +319,10 @@ describe('app', () => {
|
|||||||
expect(tree.exists('apps/my-app/src/app/app.spec.ts')).toBeFalsy();
|
expect(tree.exists('apps/my-app/src/app/app.spec.ts')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeFalsy();
|
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeFalsy();
|
||||||
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app'].architect.test).toBeUndefined();
|
expect(workspaceJson.projects['my-app'].architect.test).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
angularJson.projects['my-app'].architect.lint.options.tsConfig
|
workspaceJson.projects['my-app'].architect.lint.options.tsConfig
|
||||||
).toEqual(['apps/my-app/tsconfig.app.json']);
|
).toEqual(['apps/my-app/tsconfig.app.json']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -334,8 +335,8 @@ describe('app', () => {
|
|||||||
appTree
|
appTree
|
||||||
);
|
);
|
||||||
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
||||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||||
expect(angularJson.projects['my-app-e2e']).toBeUndefined();
|
expect(workspaceJson.projects['my-app-e2e']).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -21,7 +21,10 @@ import {
|
|||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
getNpmScope,
|
getNpmScope,
|
||||||
formatFiles
|
formatFiles,
|
||||||
|
updateWorkspaceInTree,
|
||||||
|
generateProjectLint,
|
||||||
|
addGlobalLint
|
||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import ngAdd from '../ng-add/ng-add';
|
import ngAdd from '../ng-add/ng-add';
|
||||||
|
|
||||||
@ -58,7 +61,7 @@ function updateNxJson(options: NormalizedSchema): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addProject(options: NormalizedSchema): Rule {
|
function addProject(options: NormalizedSchema): Rule {
|
||||||
return updateJsonInTree('angular.json', json => {
|
return updateWorkspaceInTree(json => {
|
||||||
const architect: { [key: string]: any } = {};
|
const architect: { [key: string]: any } = {};
|
||||||
|
|
||||||
architect.build = {
|
architect.build = {
|
||||||
@ -122,15 +125,11 @@ function addProject(options: NormalizedSchema): Rule {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
architect.lint = {
|
architect.lint = generateProjectLint(
|
||||||
builder: '@angular-devkit/build-angular:tslint',
|
normalize(options.appProjectRoot),
|
||||||
options: {
|
join(normalize(options.appProjectRoot), 'tsconfig.app.json'),
|
||||||
tsConfig: [
|
options.linter
|
||||||
join(normalize(options.appProjectRoot), 'tsconfig.app.json')
|
);
|
||||||
],
|
|
||||||
exclude: ['**/node_modules/**']
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
json.projects[options.projectName] = {
|
json.projects[options.projectName] = {
|
||||||
root: options.appProjectRoot,
|
root: options.appProjectRoot,
|
||||||
@ -154,6 +153,7 @@ export default function(schema: Schema): Rule {
|
|||||||
ngAdd({
|
ngAdd({
|
||||||
skipFormat: true
|
skipFormat: true
|
||||||
}),
|
}),
|
||||||
|
addGlobalLint(options.linter),
|
||||||
createApplicationFiles(options),
|
createApplicationFiles(options),
|
||||||
updateNxJson(options),
|
updateNxJson(options),
|
||||||
addProject(options),
|
addProject(options),
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
name: string;
|
name: string;
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
@ -7,6 +5,7 @@ export interface Schema {
|
|||||||
skipFormat: boolean;
|
skipFormat: boolean;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
tags?: string;
|
tags?: string;
|
||||||
unitTestRunner: UnitTestRunner;
|
unitTestRunner: 'jest' | 'none';
|
||||||
e2eTestRunner: E2eTestRunner;
|
e2eTestRunner: 'cypress' | 'none';
|
||||||
|
linter: 'eslint' | 'tslint';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,12 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "tslint"],
|
||||||
|
"default": "tslint"
|
||||||
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files",
|
"description": "Skip formatting files",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -23,13 +23,13 @@ describe('ng-add', () => {
|
|||||||
describe('defaultCollection', () => {
|
describe('defaultCollection', () => {
|
||||||
it('should be set if none was set before', async () => {
|
it('should be set if none was set before', async () => {
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/web');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/web');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be set if @nrwl/workspace was set before', async () => {
|
it('should be set if @nrwl/workspace was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/workspace'
|
defaultCollection: '@nrwl/workspace'
|
||||||
};
|
};
|
||||||
@ -39,13 +39,13 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/web');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/web');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be set if something else was set before', async () => {
|
it('should not be set if something else was set before', async () => {
|
||||||
tree = await callRule(
|
tree = await callRule(
|
||||||
updateJsonInTree('angular.json', json => {
|
updateJsonInTree('workspace.json', json => {
|
||||||
json.cli = {
|
json.cli = {
|
||||||
defaultCollection: '@nrwl/angular'
|
defaultCollection: '@nrwl/angular'
|
||||||
};
|
};
|
||||||
@ -55,8 +55,8 @@ describe('ng-add', () => {
|
|||||||
tree
|
tree
|
||||||
);
|
);
|
||||||
const result = await runSchematic('ng-add', {}, tree);
|
const result = await runSchematic('ng-add', {}, tree);
|
||||||
const angularJson = readJsonInTree(result, 'angular.json');
|
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -26,12 +26,12 @@ export function _findDefaultServePath(
|
|||||||
/^(\w+:)?\/\//.test(baseHref || '') ||
|
/^(\w+:)?\/\//.test(baseHref || '') ||
|
||||||
/^(\w+:)?\/\//.test(deployUrl || '')
|
/^(\w+:)?\/\//.test(deployUrl || '')
|
||||||
) {
|
) {
|
||||||
// If baseHref or deployUrl is absolute, unsupported by ng serve
|
// If baseHref or deployUrl is absolute, unsupported by nx serve
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize baseHref
|
// normalize baseHref
|
||||||
// for ng serve the starting base is always `/` so a relative
|
// for nx serve the starting base is always `/` so a relative
|
||||||
// and root relative value are identical
|
// and root relative value are identical
|
||||||
const baseHrefParts = (baseHref || '').split('/').filter(part => part !== '');
|
const baseHrefParts = (baseHref || '').split('/').filter(part => part !== '');
|
||||||
if (baseHref && !baseHref.endsWith('/')) {
|
if (baseHref && !baseHref.endsWith('/')) {
|
||||||
@ -42,7 +42,7 @@ export function _findDefaultServePath(
|
|||||||
|
|
||||||
if (deployUrl && deployUrl[0] === '/') {
|
if (deployUrl && deployUrl[0] === '/') {
|
||||||
if (baseHref && baseHref[0] === '/' && normalizedBaseHref !== deployUrl) {
|
if (baseHref && baseHref[0] === '/' && normalizedBaseHref !== deployUrl) {
|
||||||
// If baseHref and deployUrl are root relative and not equivalent, unsupported by ng serve
|
// If baseHref and deployUrl are root relative and not equivalent, unsupported by nx serve
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,13 @@
|
|||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"tao-new": {
|
||||||
|
"factory": "./src/schematics/tao-new/tao-new",
|
||||||
|
"schema": "./src/schematics/tao-new/schema.json",
|
||||||
|
"description": "Create a workspace",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
|
||||||
"library": {
|
"library": {
|
||||||
"factory": "./src/schematics/library/library",
|
"factory": "./src/schematics/library/library",
|
||||||
"schema": "./src/schematics/library/schema.json",
|
"schema": "./src/schematics/library/schema.json",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user