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
|
||||
script:
|
||||
- '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:
|
||||
email: false
|
||||
|
||||
@ -17,6 +17,14 @@ Type: `string`
|
||||
|
||||
A directory where the app is placed
|
||||
|
||||
### linter
|
||||
|
||||
Default: `tslint`
|
||||
|
||||
Type: `string`
|
||||
|
||||
The tool to use for running lint checks.
|
||||
|
||||
### name
|
||||
|
||||
Type: `string`
|
||||
|
||||
@ -23,6 +23,14 @@ Type: `string`
|
||||
|
||||
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
|
||||
|
||||
Type: `string`
|
||||
|
||||
@ -33,6 +33,14 @@ Type: `string`
|
||||
|
||||
Test runner to use for end to end (e2e) tests
|
||||
|
||||
### linter
|
||||
|
||||
Default: `tslint`
|
||||
|
||||
Type: `string`
|
||||
|
||||
The tool to use for running lint checks.
|
||||
|
||||
### name
|
||||
|
||||
Type: `string`
|
||||
|
||||
@ -45,7 +45,7 @@ Use pascal case component file name (e.g. App.tsx)
|
||||
|
||||
Type: `string`
|
||||
|
||||
The name of the project (as specified in angular.json).
|
||||
The name of the project.
|
||||
|
||||
### routing
|
||||
|
||||
|
||||
@ -17,6 +17,14 @@ Type: `string`
|
||||
|
||||
A directory where the app is placed
|
||||
|
||||
### linter
|
||||
|
||||
Default: `tslint`
|
||||
|
||||
Type: `string`
|
||||
|
||||
The tool to use for running lint checks.
|
||||
|
||||
### name
|
||||
|
||||
Type: `string`
|
||||
|
||||
@ -25,6 +25,14 @@ Type: `string`
|
||||
|
||||
Test runner to use for end to end (e2e) tests
|
||||
|
||||
### linter
|
||||
|
||||
Default: `tslint`
|
||||
|
||||
Type: `string`
|
||||
|
||||
The tool to use for running lint checks.
|
||||
|
||||
### name
|
||||
|
||||
Type: `string`
|
||||
|
||||
@ -8,7 +8,7 @@ Run commands
|
||||
|
||||
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
|
||||
|
||||
|
||||
@ -17,6 +17,14 @@ Type: `string`
|
||||
|
||||
A directory where the app is placed
|
||||
|
||||
### linter
|
||||
|
||||
Default: `tslint`
|
||||
|
||||
Type: `string`
|
||||
|
||||
The tool to use for running lint checks.
|
||||
|
||||
### name
|
||||
|
||||
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
|
||||
|
||||
### cli
|
||||
|
||||
Default: `nx`
|
||||
|
||||
Type: `string`
|
||||
|
||||
CLI used for generating code and running tasks
|
||||
|
||||
### commit
|
||||
|
||||
Default: `true`
|
||||
|
||||
@ -3,15 +3,16 @@ import {
|
||||
readFile,
|
||||
readJson,
|
||||
runCommand,
|
||||
runsInWSL,
|
||||
uniq,
|
||||
updateFile,
|
||||
runCLI
|
||||
runCLI,
|
||||
forEachCli,
|
||||
supportUi
|
||||
} from './utils';
|
||||
|
||||
let originalCIValue;
|
||||
|
||||
describe('Affected', () => {
|
||||
forEachCli(() => {
|
||||
/**
|
||||
* Setting CI=true makes it simpler to configure assertions around output, as there
|
||||
* won't be any colors.
|
||||
@ -24,6 +25,7 @@ describe('Affected', () => {
|
||||
process.env.CI = originalCIValue;
|
||||
});
|
||||
|
||||
describe('Affected', () => {
|
||||
it('should print, build, and test affected apps', () => {
|
||||
ensureProject();
|
||||
const myapp = uniq('myapp');
|
||||
@ -104,9 +106,9 @@ describe('Affected', () => {
|
||||
`npm run affected:build -- --files="libs/${mylib}/src/index.ts"`
|
||||
);
|
||||
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('with flags:');
|
||||
|
||||
@ -115,8 +117,8 @@ describe('Affected', () => {
|
||||
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --parallel`
|
||||
);
|
||||
expect(buildParallel).toContain(`Running target build for projects:`);
|
||||
expect(buildParallel).toContain(myapp);
|
||||
expect(buildParallel).toContain(mypublishablelib);
|
||||
expect(buildParallel).toContain(`- ${myapp}`);
|
||||
expect(buildParallel).toContain(`- ${mypublishablelib}`);
|
||||
expect(buildParallel).toContain(
|
||||
'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}`
|
||||
);
|
||||
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
|
||||
const buildWithFlags = runCommand(
|
||||
`npm run affected:build -- --files="libs/${mylib}/src/index.ts" --stats-json`
|
||||
);
|
||||
|
||||
expect(buildWithFlags).toContain(`Running target build for projects:`);
|
||||
expect(buildWithFlags).toContain(myapp);
|
||||
expect(buildWithFlags).toContain(mypublishablelib);
|
||||
expect(buildWithFlags).toContain(`- ${myapp}`);
|
||||
expect(buildWithFlags).toContain(`- ${mypublishablelib}`);
|
||||
expect(buildWithFlags).toContain('With flags: --stats-json=true');
|
||||
|
||||
if (!runsInWSL()) {
|
||||
if (supportUi()) {
|
||||
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');
|
||||
}
|
||||
@ -147,10 +150,9 @@ describe('Affected', () => {
|
||||
`npm run affected:test -- --files="libs/${mylib}/src/index.ts"`
|
||||
);
|
||||
expect(unitTests).toContain(`Running target test for projects:`);
|
||||
expect(unitTests).toContain(mylib);
|
||||
expect(unitTests).toContain(myapp);
|
||||
expect(unitTests).toContain(mypublishablelib);
|
||||
|
||||
expect(unitTests).toContain(`- ${mylib}`);
|
||||
expect(unitTests).toContain(`- ${myapp}`);
|
||||
expect(unitTests).toContain(`- ${mypublishablelib}`);
|
||||
// Fail a Unit Test
|
||||
updateFile(
|
||||
`apps/${myapp}/src/app/app.component.spec.ts`,
|
||||
@ -164,12 +166,10 @@ describe('Affected', () => {
|
||||
`npm run affected:test -- --files="libs/${mylib}/src/index.ts"`
|
||||
);
|
||||
expect(failedTests).toContain(`Running target test for projects:`);
|
||||
expect(failedTests).toContain(mylib);
|
||||
expect(failedTests).toContain(myapp);
|
||||
expect(failedTests).toContain(mypublishablelib);
|
||||
|
||||
expect(failedTests).toContain(`- ${mylib}`);
|
||||
expect(failedTests).toContain(`- ${myapp}`);
|
||||
expect(failedTests).toContain(`- ${mypublishablelib}`);
|
||||
expect(failedTests).toContain(`Failed projects:`);
|
||||
expect(failedTests).toContain(myapp);
|
||||
expect(failedTests).toContain(
|
||||
'You can isolate the above projects by passing: --only-failed'
|
||||
);
|
||||
@ -194,17 +194,17 @@ describe('Affected', () => {
|
||||
const isolatedTests = runCommand(
|
||||
`npm run affected:test -- --files="libs/${mylib}/src/index.ts" --only-failed`
|
||||
);
|
||||
expect(isolatedTests).toContain(`Running target test for projects:`);
|
||||
expect(isolatedTests).toContain(myapp);
|
||||
expect(isolatedTests).toContain(`Running target test for projects`);
|
||||
expect(isolatedTests).toContain(`- ${myapp}`);
|
||||
|
||||
const linting = runCommand(
|
||||
`npm run affected:lint -- --files="libs/${mylib}/src/index.ts"`
|
||||
);
|
||||
expect(linting).toContain(`Running target lint for projects:`);
|
||||
expect(linting).toContain(mylib);
|
||||
expect(linting).toContain(myapp);
|
||||
expect(linting).toContain(`${myapp}-e2e`);
|
||||
expect(linting).toContain(mypublishablelib);
|
||||
expect(linting).toContain(`- ${mylib}`);
|
||||
expect(linting).toContain(`- ${myapp}`);
|
||||
expect(linting).toContain(`- ${myapp}-e2e`);
|
||||
expect(linting).toContain(`- ${mypublishablelib}`);
|
||||
|
||||
const lintWithJsonFormating = runCommand(
|
||||
`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}`
|
||||
);
|
||||
expect(unitTestsExcluded).toContain(`Running target test for projects:`);
|
||||
expect(unitTestsExcluded).toContain(mylib);
|
||||
expect(unitTestsExcluded).toContain(`- ${mylib}`);
|
||||
|
||||
const i18n = runCommand(
|
||||
`npm run affected -- --target extract-i18n --files="libs/${mylib}/src/index.ts"`
|
||||
);
|
||||
expect(i18n).toContain(`Running target extract-i18n for projects:`);
|
||||
expect(i18n).toContain(myapp);
|
||||
expect(i18n).toContain(`- ${myapp}`);
|
||||
|
||||
const interpolatedTests = runCommand(
|
||||
`npm run affected -- --target test --files="libs/${mylib}/src/index.ts" -- --jest-config {project.root}/jest.config.js`
|
||||
);
|
||||
expect(interpolatedTests).toContain(
|
||||
`Running target "test" for affected projects succeeded`
|
||||
`Running target \"test\" for affected projects succeeded`
|
||||
);
|
||||
}, 1000000);
|
||||
});
|
||||
});
|
||||
|
||||
@ -8,9 +8,12 @@ import {
|
||||
updateFile,
|
||||
exists,
|
||||
ensureProject,
|
||||
uniq
|
||||
uniq,
|
||||
forEachCli,
|
||||
workspaceConfigName
|
||||
} from './utils';
|
||||
|
||||
forEachCli(() => {
|
||||
describe('Command line', () => {
|
||||
it('lint should ensure module boundaries', () => {
|
||||
ensureProject();
|
||||
@ -81,8 +84,12 @@ describe('Command line', () => {
|
||||
'The following file(s) do not belong to any projects:'
|
||||
);
|
||||
expect(stdout).toContain(`- apps/${appAfter}/browserslist`);
|
||||
expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.css`);
|
||||
expect(stdout).toContain(`- apps/${appAfter}/src/app/app.component.html`);
|
||||
expect(stdout).toContain(
|
||||
`- apps/${appAfter}/src/app/app.component.css`
|
||||
);
|
||||
expect(stdout).toContain(
|
||||
`- apps/${appAfter}/src/app/app.component.html`
|
||||
);
|
||||
expect(stdout).toContain(
|
||||
`- apps/${appAfter}/src/app/app.component.spec.ts`
|
||||
);
|
||||
@ -169,7 +176,10 @@ describe('Command line', () => {
|
||||
type: 'string',
|
||||
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`);
|
||||
updateFile(
|
||||
@ -185,14 +195,14 @@ describe('Command line', () => {
|
||||
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir -d`
|
||||
);
|
||||
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');
|
||||
|
||||
const output = runCommand(
|
||||
`npm run workspace-schematic ${custom} ${workspace} -- --no-interactive --directory=dir`
|
||||
);
|
||||
checkFilesExist(`libs/dir/${workspace}/src/index.ts`);
|
||||
expect(output).toContain('update angular.json');
|
||||
expect(output).toContain(`update ${workspaceConfigName()}`);
|
||||
expect(output).toContain('update nx.json');
|
||||
|
||||
const another = uniq('another');
|
||||
@ -350,3 +360,4 @@ describe('Command line', () => {
|
||||
}, 1000000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -6,10 +6,12 @@ import {
|
||||
readFile,
|
||||
ensureProject,
|
||||
uniq,
|
||||
runsInWSL,
|
||||
newProject
|
||||
newProject,
|
||||
forEachCli,
|
||||
supportUi
|
||||
} from './utils';
|
||||
|
||||
forEachCli(() => {
|
||||
describe('Cypress E2E Test runner', () => {
|
||||
describe('project scaffolding', () => {
|
||||
it('should generate an app with the Cypress as e2e test runner', () => {
|
||||
@ -34,16 +36,16 @@ describe('Cypress E2E Test runner', () => {
|
||||
}, 1000000);
|
||||
});
|
||||
|
||||
if (!runsInWSL()) {
|
||||
if (supportUi()) {
|
||||
describe('running Cypress', () => {
|
||||
it('should execute e2e tests using Cypress', () => {
|
||||
fit('should execute e2e tests using Cypress', () => {
|
||||
newProject();
|
||||
const myapp = uniq('myapp');
|
||||
runCLI(`generate @nrwl/angular:app ${myapp} --e2eTestRunner=cypress`);
|
||||
|
||||
expect(
|
||||
runCLI(`e2e --project=${myapp}-e2e --headless --watch=false`)
|
||||
).toContain('All specs passed!');
|
||||
expect(runCLI(`e2e ${myapp}-e2e --headless --no-watch`)).toContain(
|
||||
'All specs passed!'
|
||||
);
|
||||
|
||||
const originalContents = JSON.parse(
|
||||
readFile(`apps/${myapp}-e2e/cypress.json`)
|
||||
@ -54,10 +56,11 @@ describe('Cypress E2E Test runner', () => {
|
||||
JSON.stringify(originalContents)
|
||||
);
|
||||
|
||||
expect(
|
||||
runCLI(`e2e --project=${myapp}-e2e --headless --watch=false`)
|
||||
).toContain('All specs passed!');
|
||||
expect(runCLI(`e2e ${myapp}-e2e --headless --no-watch`)).toContain(
|
||||
'All specs passed!'
|
||||
);
|
||||
}, 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', () => {
|
||||
it('should delegate to the Angular CLI all non-standard commands', async () => {
|
||||
it('should delegate to the cli all non-standard commands', async () => {
|
||||
ensureProject();
|
||||
|
||||
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}`);
|
||||
|
||||
checkFilesExist(
|
||||
@ -21,3 +28,4 @@ describe('Delegate to CLI', () => {
|
||||
);
|
||||
}, 120000);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
import {
|
||||
ensureProject,
|
||||
patchKarmaToWorkOnWSL,
|
||||
runCLI,
|
||||
uniq,
|
||||
updateFile
|
||||
updateFile,
|
||||
forEachCli,
|
||||
supportUi
|
||||
} from './utils';
|
||||
|
||||
describe('DowngradeModule', () => {
|
||||
forEachCli(() => {
|
||||
xdescribe('DowngradeModule', () => {
|
||||
it('should generate a downgradeModule setup', async () => {
|
||||
ensureProject();
|
||||
|
||||
const myapp = uniq('myapp');
|
||||
runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner=karma`);
|
||||
patchKarmaToWorkOnWSL();
|
||||
|
||||
updateFile(
|
||||
`apps/${myapp}/src/legacy.js`,
|
||||
@ -24,6 +25,9 @@ describe('DowngradeModule', () => {
|
||||
);
|
||||
|
||||
runCLI(`build ${myapp}`);
|
||||
if (supportUi()) {
|
||||
expect(runCLI(`test ${myapp} --no-watch`)).toContain('3 SUCCESS');
|
||||
}
|
||||
}, 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', () => {
|
||||
it('should be able test projects using jest', async done => {
|
||||
ensureProject();
|
||||
@ -14,10 +15,11 @@ describe('Jest', () => {
|
||||
runCLIAsync(`generate @nrwl/angular:service 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');
|
||||
const libResult = await runCLIAsync(`test ${mylib}`);
|
||||
expect(libResult.stderr).toContain('Test Suites: 3 passed, 3 total');
|
||||
done();
|
||||
}, 45000);
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,22 +3,25 @@ import {
|
||||
runCLIAsync,
|
||||
ensureProject,
|
||||
uniq,
|
||||
patchKarmaToWorkOnWSL
|
||||
forEachCli,
|
||||
supportUi
|
||||
} from './utils';
|
||||
|
||||
describe('Karma', () => {
|
||||
forEachCli(() => {
|
||||
xdescribe('Karma', () => {
|
||||
it('should be able to generate a testable library using karma', async done => {
|
||||
ensureProject();
|
||||
const mylib = uniq('mylib');
|
||||
runCLI(`generate @nrwl/angular:lib ${mylib} --unit-test-runner karma`);
|
||||
patchKarmaToWorkOnWSL();
|
||||
|
||||
await Promise.all([
|
||||
runCLIAsync(`generate @nrwl/angular:service test --project ${mylib}`),
|
||||
runCLIAsync(`generate @nrwl/angular:component test --project ${mylib}`)
|
||||
]);
|
||||
if (supportUi()) {
|
||||
const karmaResult = await runCLIAsync(`test ${mylib}`);
|
||||
expect(karmaResult.stdout).toContain('3 SUCCESS');
|
||||
}
|
||||
done();
|
||||
}, 30000);
|
||||
|
||||
@ -26,14 +29,16 @@ describe('Karma', () => {
|
||||
ensureProject();
|
||||
const myapp = uniq('myapp');
|
||||
runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner karma`);
|
||||
patchKarmaToWorkOnWSL();
|
||||
|
||||
await Promise.all([
|
||||
runCLIAsync(`generate @nrwl/angular:service test --project ${myapp}`),
|
||||
runCLIAsync(`generate @nrwl/angular:component test --project ${myapp}`)
|
||||
]);
|
||||
if (supportUi()) {
|
||||
const karmaResult = await runCLIAsync(`test ${myapp}`);
|
||||
expect(karmaResult.stdout).toContain('5 SUCCESS');
|
||||
}
|
||||
done();
|
||||
}, 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,
|
||||
runCLIAsync,
|
||||
runCommand,
|
||||
runNgNew,
|
||||
updateFile
|
||||
runNew,
|
||||
updateFile,
|
||||
forEachCli,
|
||||
runNgAdd
|
||||
} from './utils';
|
||||
|
||||
forEachCli('angular', () => {
|
||||
describe('Nrwl Convert to Nx Workspace', () => {
|
||||
beforeEach(cleanup);
|
||||
afterAll(cleanup);
|
||||
|
||||
it('should generate a workspace', () => {
|
||||
runNgNew();
|
||||
runNew('', false, false);
|
||||
|
||||
// update 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));
|
||||
|
||||
// run the command
|
||||
runCLI('add @nrwl/workspace --npmScope projscope --skip-install');
|
||||
runNgAdd('add @nrwl/workspace --npmScope projscope --skip-install');
|
||||
copyMissingPackages();
|
||||
|
||||
// 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',
|
||||
help: 'nx help'
|
||||
});
|
||||
expect(updatedPackageJson.devDependencies['@nrwl/workspace']).toBeDefined();
|
||||
expect(
|
||||
updatedPackageJson.devDependencies['@nrwl/workspace']
|
||||
).toBeDefined();
|
||||
expect(updatedPackageJson.devDependencies['@angular/cli']).toBeDefined();
|
||||
|
||||
const nxJson = readJson('nx.json');
|
||||
@ -127,6 +132,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
||||
expect(updatedAngularCLIJson.projects.proj.architect.build).toEqual({
|
||||
builder: '@angular-devkit/build-angular:browser',
|
||||
options: {
|
||||
aot: false,
|
||||
outputPath: 'dist/apps/proj',
|
||||
index: 'apps/proj/src/index.html',
|
||||
main: 'apps/proj/src/main.ts',
|
||||
@ -214,13 +220,15 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
||||
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',
|
||||
options: {
|
||||
tsConfig: 'apps/proj-e2e/tsconfig.json',
|
||||
exclude: ['**/node_modules/**']
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const updatedTslint = readJson('tslint.json');
|
||||
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', () => {
|
||||
// create a new AngularCLI app
|
||||
runNgNew();
|
||||
runNew();
|
||||
const nxVersion = '0.0.0';
|
||||
const schematicsVersion = '0.0.0';
|
||||
const ngrxVersion = '0.0.0';
|
||||
// update 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/effects'] = ngrxVersion;
|
||||
existingPackageJson.dependencies['@ngrx/router-store'] = ngrxVersion;
|
||||
@ -257,7 +267,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
||||
})
|
||||
);
|
||||
// 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
|
||||
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/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(
|
||||
ngrxVersion
|
||||
);
|
||||
@ -282,53 +294,27 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
||||
|
||||
it('should convert a project with common libraries in the ecosystem', () => {
|
||||
// create a new AngularCLI app
|
||||
runNgNew();
|
||||
runNew();
|
||||
|
||||
// Add some Angular libraries
|
||||
runCLI('add @angular/elements');
|
||||
runCLI('add @angular/material');
|
||||
runCLI('add @angular/pwa');
|
||||
runCLI('add @ngrx/store');
|
||||
runCLI('add @ngrx/effects');
|
||||
runNgAdd('add @angular/elements');
|
||||
runNgAdd('add @angular/material');
|
||||
runNgAdd('add @angular/pwa');
|
||||
runNgAdd('add @ngrx/store');
|
||||
runNgAdd('add @ngrx/effects');
|
||||
|
||||
// Add Nx
|
||||
runCLI('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'
|
||||
);
|
||||
runNgAdd('add @nrwl/workspace --skip-install');
|
||||
});
|
||||
|
||||
it('should handle different types of errors', () => {
|
||||
// create a new AngularCLI app
|
||||
runNgNew();
|
||||
runNew();
|
||||
|
||||
// Only remove e2e directory
|
||||
runCommand('mv e2e e2e-bak');
|
||||
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');
|
||||
} catch (e) {
|
||||
expect(e.stderr.toString()).toContain(
|
||||
@ -342,7 +328,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
||||
// Remove package.json
|
||||
runCommand('mv package.json package.json.bak');
|
||||
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');
|
||||
} catch (e) {
|
||||
expect(e.stderr.toString()).toContain(
|
||||
@ -356,7 +342,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
||||
// Remove src
|
||||
runCommand('mv src src-bak');
|
||||
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');
|
||||
} catch (e) {
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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,
|
||||
uniq,
|
||||
ensureProject,
|
||||
readJson
|
||||
readJson,
|
||||
forEachCli
|
||||
} from './utils';
|
||||
|
||||
forEachCli(() => {
|
||||
describe('ngrx', () => {
|
||||
it('should work', async () => {
|
||||
ensureProject();
|
||||
@ -31,7 +33,9 @@ describe('ngrx', () => {
|
||||
`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,');
|
||||
expectTestsPass(await runCLIAsync(`test ${myapp} --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`
|
||||
);
|
||||
|
||||
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,');
|
||||
expectTestsPass(await runCLIAsync(`test ${myapp} --no-watch`));
|
||||
expectTestsPass(await runCLIAsync(`test ${mylib} --no-watch`));
|
||||
}, 1000000);
|
||||
});
|
||||
});
|
||||
|
||||
@ -9,7 +9,11 @@ import {
|
||||
runCLI,
|
||||
runCLIAsync,
|
||||
uniq,
|
||||
updateFile
|
||||
updateFile,
|
||||
forEachCli,
|
||||
checkFilesExist,
|
||||
tmpProjPath,
|
||||
workspaceConfigName
|
||||
} from './utils';
|
||||
|
||||
function getData(): Promise<any> {
|
||||
@ -27,8 +31,9 @@ function getData(): Promise<any> {
|
||||
});
|
||||
}
|
||||
|
||||
forEachCli(() => {
|
||||
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();
|
||||
const nodeapp = uniq('nodeapp');
|
||||
runCLI(`generate @nrwl/express:app ${nodeapp}`);
|
||||
@ -49,23 +54,22 @@ describe('Node Applications', () => {
|
||||
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||
await runCLIAsync(`build ${nodeapp}`);
|
||||
|
||||
expect(exists(`./tmp/proj/dist/apps/${nodeapp}/main.js`)).toBeTruthy();
|
||||
expect(
|
||||
exists(`./tmp/proj/dist/apps/${nodeapp}/assets/file.txt`)
|
||||
).toBeTruthy();
|
||||
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
|
||||
}
|
||||
checkFilesExist(
|
||||
`dist/apps/${nodeapp}/main.js`,
|
||||
`dist/apps/${nodeapp}/assets/file.txt`,
|
||||
`dist/apps/${nodeapp}/main.js.map`
|
||||
);
|
||||
|
||||
const server = fork(`./dist/apps/${nodeapp}/main.js`, [], {
|
||||
cwd: tmpProjPath(),
|
||||
silent: true
|
||||
});
|
||||
expect(server).toBeTruthy();
|
||||
await new Promise(resolve => {
|
||||
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();
|
||||
|
||||
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 = {
|
||||
builder: '@nrwl/workspace:run-commands',
|
||||
options: {
|
||||
@ -87,15 +91,16 @@ describe('Node Applications', () => {
|
||||
readyWhen: 'DONE'
|
||||
}
|
||||
};
|
||||
|
||||
config.projects[nodeapp].architect.serve.options.waitUntilTargets = [
|
||||
`${nodeapp}:waitAndPrint`
|
||||
];
|
||||
updateFile('angular.json', JSON.stringify(config));
|
||||
updateFile(workspaceConfigName(), JSON.stringify(config));
|
||||
const process = spawn(
|
||||
'node',
|
||||
['./node_modules/.bin/ng', 'serve', nodeapp],
|
||||
['./node_modules/.bin/nx', 'serve', nodeapp],
|
||||
{
|
||||
cwd: './tmp/proj'
|
||||
cwd: tmpProjPath()
|
||||
}
|
||||
);
|
||||
let collectedOutput = '';
|
||||
@ -126,20 +131,16 @@ describe('Node Applications', () => {
|
||||
|
||||
await runCLIAsync(`build ${nestapp}`);
|
||||
|
||||
expect(exists(`./tmp/proj/dist/apps/${nestapp}/main.js`)).toBeTruthy();
|
||||
expect(
|
||||
exists(`./tmp/proj/dist/apps/${nestapp}/assets/file.txt`)
|
||||
).toBeTruthy();
|
||||
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
|
||||
}
|
||||
checkFilesExist(
|
||||
`dist/apps/${nestapp}/main.js`,
|
||||
`dist/apps/${nestapp}/assets/file.txt`,
|
||||
`dist/apps/${nestapp}/main.js.map`
|
||||
);
|
||||
|
||||
const server = fork(`./dist/apps/${nestapp}/main.js`, [], {
|
||||
cwd: tmpProjPath(),
|
||||
silent: true
|
||||
});
|
||||
expect(server).toBeTruthy();
|
||||
|
||||
await new Promise(resolve => {
|
||||
@ -159,9 +160,9 @@ describe('Node Applications', () => {
|
||||
|
||||
const process = spawn(
|
||||
'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}`);
|
||||
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
||||
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`, {
|
||||
cwd: './tmp/proj'
|
||||
cwd: tmpProjPath()
|
||||
}).toString();
|
||||
expect(result).toContain('Hello World!');
|
||||
}, 30000);
|
||||
});
|
||||
});
|
||||
|
||||
@ -7,10 +7,14 @@ import {
|
||||
runCLIAsync,
|
||||
checkFilesExist,
|
||||
renameFile,
|
||||
readJson
|
||||
readJson,
|
||||
forEachCli,
|
||||
supportUi,
|
||||
workspaceConfigName
|
||||
} from './utils';
|
||||
import { serializeJson } from '@nrwl/workspace';
|
||||
|
||||
forEachCli(() => {
|
||||
describe('React Applications', () => {
|
||||
it('should be able to generate a react app + lib', async () => {
|
||||
ensureProject();
|
||||
@ -52,7 +56,10 @@ describe('React Applications', () => {
|
||||
runCLI(`generate @nrwl/react:app ${appName} --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(
|
||||
`apps/${appName}/src/app/app.tsx`,
|
||||
`apps/${appName}/src/app/app.jsx`
|
||||
@ -65,7 +72,7 @@ describe('React Applications', () => {
|
||||
`apps/${appName}/src/polyfills.ts`,
|
||||
`apps/${appName}/src/polyfills.js`
|
||||
);
|
||||
const angularJson = readJson('angular.json');
|
||||
const angularJson = readJson(workspaceConfigName());
|
||||
|
||||
angularJson.projects[
|
||||
appName
|
||||
@ -73,7 +80,7 @@ describe('React Applications', () => {
|
||||
angularJson.projects[
|
||||
appName
|
||||
].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`;
|
||||
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');
|
||||
const lintE2eResults = runCLI(`lint ${appName}-e2e`);
|
||||
expect(lintE2eResults).toContain('All files pass linting.');
|
||||
|
||||
if (supportUi()) {
|
||||
const e2eResults = runCLI(`e2e ${appName}-e2e`);
|
||||
expect(e2eResults).toContain('All specs passed!');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
import {
|
||||
ensureProject,
|
||||
patchKarmaToWorkOnWSL,
|
||||
runCLI,
|
||||
uniq,
|
||||
updateFile
|
||||
updateFile,
|
||||
forEachCli,
|
||||
supportUi
|
||||
} from './utils';
|
||||
|
||||
describe('Upgrade', () => {
|
||||
forEachCli(() => {
|
||||
xdescribe('Upgrade', () => {
|
||||
it('should generate an UpgradeModule setup', async () => {
|
||||
ensureProject();
|
||||
const myapp = uniq('myapp');
|
||||
runCLI(`generate @nrwl/angular:app ${myapp} --unit-test-runner=karma`);
|
||||
patchKarmaToWorkOnWSL();
|
||||
|
||||
updateFile(
|
||||
`apps/${myapp}/src/legacy.js`,
|
||||
@ -38,6 +39,9 @@ describe('Upgrade', () => {
|
||||
);
|
||||
|
||||
runCLI(`build ${myapp}`);
|
||||
if (supportUi()) {
|
||||
expect(runCLI(`test ${myapp} --no-watch`)).toContain('1 SUCCESS');
|
||||
}
|
||||
}, 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 * as path from 'path';
|
||||
|
||||
const projectName: string = 'proj';
|
||||
export let cli;
|
||||
|
||||
export function uniq(prefix: string) {
|
||||
return `${prefix}${Math.floor(Math.random() * 10000000)}`;
|
||||
}
|
||||
|
||||
function patchPackageJsonDeps() {
|
||||
const p = readFileSync('./tmp/proj/package.json').toString();
|
||||
export function forEachCli(
|
||||
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 angularPath = path.join(getCwd(), 'build', 'packages', 'angular');
|
||||
writeFileSync(
|
||||
'./tmp/proj/package.json',
|
||||
p
|
||||
.replace(
|
||||
'"@nrwl/workspace": "*"',
|
||||
`"@nrwl/workspace": "file:${workspacePath}"`
|
||||
)
|
||||
.replace('"@nrwl/angular": "*"', `"@nrwl/angular": "file:${angularPath}"`)
|
||||
);
|
||||
const reactPath = path.join(getCwd(), 'build', 'packages', 'react');
|
||||
|
||||
if (addWorkspace) {
|
||||
p.devDependencies['@nrwl/workspace'] = `file:${workspacePath}`;
|
||||
}
|
||||
p.devDependencies['@nrwl/angular'] = `file:${angularPath}`;
|
||||
p.devDependencies['@nrwl/react'] = `file:${reactPath}`;
|
||||
writeFileSync(tmpProjPath('package.json'), JSON.stringify(p, null, 2));
|
||||
}
|
||||
|
||||
function runYarnInstall(silent: boolean = true) {
|
||||
const install = execSync('yarn install', {
|
||||
cwd: './tmp/proj',
|
||||
cwd: tmpProjPath(),
|
||||
...(silent ? { stdio: ['ignore', 'ignore', 'ignore'] } : {})
|
||||
});
|
||||
return install ? install.toString() : '';
|
||||
}
|
||||
|
||||
export function runNgNew(command?: string, silent?: boolean): string {
|
||||
const gen = execSync(
|
||||
`../node_modules/.bin/ng new proj --no-interactive --skip-install ${command ||
|
||||
export function runNew(
|
||||
command?: string,
|
||||
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'] } : {})
|
||||
}
|
||||
);
|
||||
patchPackageJsonDeps();
|
||||
const install = runYarnInstall(silent);
|
||||
} else {
|
||||
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}`;
|
||||
}
|
||||
|
||||
export function newProject(): void {
|
||||
cleanup();
|
||||
if (!directoryExists('./tmp/proj_backup')) {
|
||||
runNgNew('--collection=@nrwl/workspace --npmScope=proj', true);
|
||||
if (!directoryExists(tmpBackupProjPath())) {
|
||||
runNew('--collection=@nrwl/workspace --npmScope=proj', true);
|
||||
copyMissingPackages();
|
||||
|
||||
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";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
@ -67,45 +117,28 @@ function default_1(factoryOptions = {}) {
|
||||
}
|
||||
exports.default = default_1;`
|
||||
);
|
||||
runCLI('add @nrwl/jest');
|
||||
runCLI('add @nrwl/cypress');
|
||||
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(`mv ${tmpProjPath()} ${tmpBackupProjPath()}`);
|
||||
}
|
||||
execSync('cp -a ./tmp/proj_backup ./tmp/proj');
|
||||
execSync(`cp -a ${tmpBackupProjPath()} ${tmpProjPath()}`);
|
||||
}
|
||||
|
||||
export function ensureProject(): void {
|
||||
if (!directoryExists('./tmp/proj')) {
|
||||
if (!directoryExists(tmpProjPath())) {
|
||||
newProject();
|
||||
}
|
||||
}
|
||||
|
||||
export function runsInWSL() {
|
||||
return !!process.env['WINDOWSTMP'];
|
||||
}
|
||||
|
||||
export function patchKarmaToWorkOnWSL(): void {
|
||||
export function supportUi() {
|
||||
// powershell => wsl => no ui for now
|
||||
try {
|
||||
const karma = readFile('karma.conf.js');
|
||||
if (process.env['WINDOWSTMP']) {
|
||||
updateFile(
|
||||
'karma.conf.js',
|
||||
karma.replace(
|
||||
`const { constants } = require('karma');`,
|
||||
`
|
||||
const { constants } = require('karma');
|
||||
process.env['TMPDIR']="${process.env['WINDOWSTMP']}";
|
||||
`
|
||||
)
|
||||
);
|
||||
execSync(`powershell.exe echo 1`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore']
|
||||
});
|
||||
return false;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
export function copyMissingPackages(): void {
|
||||
@ -150,7 +183,7 @@ export function copyMissingPackages(): void {
|
||||
|
||||
'document-register-element'
|
||||
];
|
||||
modulesToCopy.forEach(m => copyNodeModule(projectName, m));
|
||||
modulesToCopy.forEach(m => copyNodeModule(m));
|
||||
updateFile(
|
||||
'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(
|
||||
`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 ./tmp/proj/@types/sinon-chai/node_modules/@types`);
|
||||
execSync(`rm -rf ${tmpProjPath('node_modules/cypress/node_modules/@types')}`);
|
||||
}
|
||||
|
||||
function copyNodeModule(path: string, name: string) {
|
||||
execSync(`rm -rf tmp/${path}/node_modules/${name}`);
|
||||
execSync(`cp -a node_modules/${name} tmp/${path}/node_modules/${name}`);
|
||||
function copyNodeModule(name: string) {
|
||||
execSync(`rm -rf ${tmpProjPath('node_modules/' + name)}`);
|
||||
execSync(`cp -a node_modules/${name} ${tmpProjPath('node_modules/' + name)}`);
|
||||
}
|
||||
|
||||
export function runCommandAsync(
|
||||
@ -190,7 +224,7 @@ export function runCommandAsync(
|
||||
exec(
|
||||
command,
|
||||
{
|
||||
cwd: `./tmp/proj`
|
||||
cwd: tmpProjPath()
|
||||
},
|
||||
(err, stdout, stderr) => {
|
||||
if (!opts.silenceError && err) {
|
||||
@ -208,7 +242,35 @@ export function runCLIAsync(
|
||||
silenceError: false
|
||||
}
|
||||
): 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(
|
||||
@ -218,8 +280,8 @@ export function runCLI(
|
||||
}
|
||||
): string {
|
||||
try {
|
||||
return execSync(`./node_modules/.bin/ng ${command}`, {
|
||||
cwd: `./tmp/${projectName}`
|
||||
return execSync(`node ./node_modules/@nrwl/cli/bin/nx.js ${command}`, {
|
||||
cwd: tmpProjPath()
|
||||
})
|
||||
.toString()
|
||||
.replace(
|
||||
@ -244,7 +306,7 @@ export function expectTestsPass(v: { stdout: string; stderr: string }) {
|
||||
export function runCommand(command: string): string {
|
||||
try {
|
||||
return execSync(command, {
|
||||
cwd: `./tmp/${projectName}`,
|
||||
cwd: tmpProjPath(),
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
}).toString();
|
||||
} catch (e) {
|
||||
@ -253,23 +315,18 @@ export function runCommand(command: string): string {
|
||||
}
|
||||
|
||||
export function updateFile(f: string, content: string): void {
|
||||
ensureDirSync(path.dirname(path.join(getCwd(), 'tmp', 'proj', f)));
|
||||
writeFileSync(path.join(getCwd(), 'tmp', 'proj', f), content);
|
||||
ensureDirSync(path.dirname(tmpProjPath(f)));
|
||||
writeFileSync(tmpProjPath(f), content);
|
||||
}
|
||||
|
||||
export function renameFile(f: string, newPath: string): void {
|
||||
ensureDirSync(path.dirname(path.join(getCwd(), 'tmp', 'proj', newPath)));
|
||||
renameSync(
|
||||
path.join(getCwd(), 'tmp', 'proj', f),
|
||||
path.join(getCwd(), 'tmp', 'proj', newPath)
|
||||
);
|
||||
ensureDirSync(path.dirname(tmpProjPath(newPath)));
|
||||
renameSync(tmpProjPath(f), tmpProjPath(newPath));
|
||||
}
|
||||
|
||||
export function checkFilesExist(...expectedFiles: string[]) {
|
||||
expectedFiles.forEach(f => {
|
||||
const ff = f.startsWith('/')
|
||||
? f
|
||||
: path.join(getCwd(), 'tmp', projectName, f);
|
||||
const ff = f.startsWith('/') ? f : tmpProjPath(f);
|
||||
if (!exists(ff)) {
|
||||
throw new Error(`File '${ff}' does not exist`);
|
||||
}
|
||||
@ -281,12 +338,12 @@ export function readJson(f: string): any {
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
export function cleanup() {
|
||||
execSync('rm -rf ./tmp/proj');
|
||||
execSync(`rm -rf ${tmpProjPath()}`);
|
||||
}
|
||||
|
||||
export function getCwd(): string {
|
||||
@ -316,3 +373,11 @@ export function exists(filePath: string): boolean {
|
||||
export function getSize(filePath: string): number {
|
||||
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,
|
||||
runCLI,
|
||||
runCLIAsync,
|
||||
uniq
|
||||
uniq,
|
||||
forEachCli,
|
||||
supportUi
|
||||
} from './utils';
|
||||
|
||||
forEachCli(() => {
|
||||
describe('Web Components Applications', () => {
|
||||
it('should be able to generate a web app', async () => {
|
||||
ensureProject();
|
||||
@ -54,3 +57,4 @@ describe('Web Components Applications', () => {
|
||||
expect(e2eResults).toContain('All specs passed!');
|
||||
}, 120000);
|
||||
});
|
||||
});
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
"@ngrx/schematics": "8.1.0",
|
||||
"@ngrx/store": "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",
|
||||
"@types/express": "4.16.0",
|
||||
"@types/jasmine": "~2.8.6",
|
||||
@ -94,7 +94,7 @@
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"karma-webpack": "2.0.4",
|
||||
"license-webpack-plugin": "^1.4.0",
|
||||
"ng-packagr": "5.1.0",
|
||||
"ng-packagr": "5.3.0",
|
||||
"ngrx-store-freeze": "0.2.4",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"opn": "^5.3.0",
|
||||
|
||||
@ -13,27 +13,27 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('not nested', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
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(angularJson.projects['my-app-e2e'].root).toEqual(
|
||||
expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app');
|
||||
expect(workspaceJson.projects['my-app-e2e'].root).toEqual(
|
||||
'apps/my-app-e2e'
|
||||
);
|
||||
|
||||
expect(
|
||||
angularJson.projects['my-app'].architect.lint.options.exclude
|
||||
workspaceJson.projects['my-app'].architect.lint.options.exclude
|
||||
).toEqual(['**/node_modules/**', '!apps/my-app/**']);
|
||||
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/**']);
|
||||
});
|
||||
|
||||
it('should remove the e2e target on the application', async () => {
|
||||
const tree = await runSchematic('app', { name: 'myApp' }, appTree);
|
||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
||||
expect(angularJson.projects['my-app'].architect.e2e).not.toBeDefined();
|
||||
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||
expect(workspaceJson.projects['my-app'].architect.e2e).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should update nx.json', async () => {
|
||||
@ -107,8 +107,10 @@ describe('app', () => {
|
||||
let appE2eSpec = noPrefix
|
||||
.read('apps/my-app-e2e/src/app.e2e-spec.ts')
|
||||
.toString();
|
||||
let angularJson = JSON.parse(noPrefix.read('angular.json').toString());
|
||||
let myAppPrefix = angularJson.projects['my-app'].prefix;
|
||||
let workspaceJson = JSON.parse(
|
||||
noPrefix.read('workspace.json').toString()
|
||||
);
|
||||
let myAppPrefix = workspaceJson.projects['my-app'].prefix;
|
||||
|
||||
expect(myAppPrefix).toEqual('proj');
|
||||
expect(appE2eSpec).toContain('Welcome to my-app!');
|
||||
@ -118,8 +120,8 @@ describe('app', () => {
|
||||
appE2eSpec = withPrefix
|
||||
.read('apps/my-app-e2e/src/app.e2e-spec.ts')
|
||||
.toString();
|
||||
angularJson = JSON.parse(withPrefix.read('angular.json').toString());
|
||||
myAppPrefix = angularJson.projects['my-app'].prefix;
|
||||
workspaceJson = JSON.parse(withPrefix.read('workspace.json').toString());
|
||||
myAppPrefix = workspaceJson.projects['my-app'].prefix;
|
||||
|
||||
expect(myAppPrefix).toEqual('custom');
|
||||
expect(appE2eSpec).toContain('Welcome to my-app!');
|
||||
@ -127,7 +129,7 @@ describe('app', () => {
|
||||
|
||||
xit('should work if the new project root is changed', async () => {
|
||||
appTree = await callRule(
|
||||
updateJsonInTree('/angular.json', json => ({
|
||||
updateJsonInTree('/workspace.json', json => ({
|
||||
...json,
|
||||
newProjectRoot: 'newProjectRoot'
|
||||
})),
|
||||
@ -141,26 +143,27 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('nested', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'app',
|
||||
{ name: 'myApp', directory: 'myDir' },
|
||||
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'
|
||||
);
|
||||
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'
|
||||
);
|
||||
|
||||
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/**']);
|
||||
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/**']);
|
||||
});
|
||||
|
||||
@ -314,9 +317,9 @@ describe('app', () => {
|
||||
{ name: 'myApp', style: 'scss' },
|
||||
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': {
|
||||
style: 'scss'
|
||||
}
|
||||
@ -334,12 +337,12 @@ describe('app', () => {
|
||||
|
||||
expect(tree.exists('apps/my-app/tsconfig.spec.json')).toBeTruthy();
|
||||
expect(tree.exists('apps/my-app/karma.conf.js')).toBeTruthy();
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app'].architect.test.builder).toEqual(
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-app'].architect.test.builder).toEqual(
|
||||
'@angular-devkit/build-angular:karma'
|
||||
);
|
||||
expect(
|
||||
angularJson.projects['my-app'].architect.lint.options.tsConfig
|
||||
workspaceJson.projects['my-app'].architect.lint.options.tsConfig
|
||||
).toEqual([
|
||||
'apps/my-app/tsconfig.app.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/jest.config.js')).toBeFalsy();
|
||||
expect(tree.exists('apps/my-app/karma.config.js')).toBeFalsy();
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app'].architect.test).toBeUndefined();
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-app'].architect.test).toBeUndefined();
|
||||
expect(
|
||||
angularJson.projects['my-app'].architect.lint.options.tsConfig
|
||||
workspaceJson.projects['my-app'].architect.lint.options.tsConfig
|
||||
).toEqual(['apps/my-app/tsconfig.app.json']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('--e2e-test-runner', () => {
|
||||
describe('protractor', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'app',
|
||||
{ name: 'myApp', e2eTestRunner: 'protractor' },
|
||||
appTree
|
||||
);
|
||||
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app'].architect.e2e).not.toBeDefined();
|
||||
expect(angularJson.projects['my-app-e2e']).toEqual({
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(
|
||||
workspaceJson.projects['my-app'].architect.e2e
|
||||
).not.toBeDefined();
|
||||
expect(workspaceJson.projects['my-app-e2e']).toEqual({
|
||||
root: 'apps/my-app-e2e',
|
||||
projectType: 'application',
|
||||
architect: {
|
||||
@ -422,30 +427,30 @@ describe('app', () => {
|
||||
appTree
|
||||
);
|
||||
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app-e2e']).toBeUndefined();
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-app-e2e']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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 angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['ui']).toBeDefined();
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['ui']).toBeDefined();
|
||||
expect(
|
||||
angularJson.projects['ui']['architect']['build']['builder']
|
||||
workspaceJson.projects['ui']['architect']['build']['builder']
|
||||
).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(
|
||||
'app',
|
||||
{ name: 'ui', prefix: 'ui' },
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['ui'].prefix).toEqual('ui');
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['ui'].prefix).toEqual('ui');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -15,7 +15,6 @@ import {
|
||||
import { Schema } from './schema';
|
||||
import * as ts from 'typescript';
|
||||
import {
|
||||
angularSchematicNames,
|
||||
formatFiles,
|
||||
getNpmScope,
|
||||
getWorkspacePath,
|
||||
@ -26,7 +25,8 @@ import {
|
||||
replaceNodeValue,
|
||||
toFileName,
|
||||
updateJsonInTree,
|
||||
updateWorkspace
|
||||
updateWorkspace,
|
||||
addGlobalLint
|
||||
} from '@nrwl/workspace';
|
||||
import { join, normalize } from '@angular-devkit/core';
|
||||
import ngAdd from '../ng-add/ng-add';
|
||||
@ -202,6 +202,16 @@ function updateProject(options: NormalizedSchema): Rule {
|
||||
options.appProjectRoot
|
||||
);
|
||||
|
||||
const angularSchematicNames = [
|
||||
'class',
|
||||
'component',
|
||||
'directive',
|
||||
'guard',
|
||||
'module',
|
||||
'pipe',
|
||||
'service'
|
||||
];
|
||||
|
||||
if (fixedProject.schematics) {
|
||||
angularSchematicNames.forEach(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
|
||||
// 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
|
||||
? `${angularJson.newProjectRoot}/${options.name}`
|
||||
const appProjectRoot = workspaceJson.newProjectRoot
|
||||
? `${workspaceJson.newProjectRoot}/${options.name}`
|
||||
: options.name;
|
||||
const e2eProjectRoot = angularJson.newProjectRoot
|
||||
? `${angularJson.newProjectRoot}/${options.e2eProjectName}`
|
||||
const e2eProjectRoot = workspaceJson.newProjectRoot
|
||||
? `${workspaceJson.newProjectRoot}/${options.e2eProjectName}`
|
||||
: `${options.name}/e2e`;
|
||||
|
||||
return chain([
|
||||
@ -359,6 +369,7 @@ export default function(schema: Schema): Rule {
|
||||
...options,
|
||||
skipFormat: true
|
||||
}),
|
||||
addGlobalLint('tslint'),
|
||||
externalSchematic('@schematics/angular', 'application', {
|
||||
name: options.name,
|
||||
inlineStyle: options.inlineStyle,
|
||||
@ -373,11 +384,9 @@ export default function(schema: Schema): Rule {
|
||||
skipPackageJson: false
|
||||
}),
|
||||
addTsconfigs(options),
|
||||
|
||||
options.e2eTestRunner === 'protractor'
|
||||
? move(e2eProjectRoot, options.e2eProjectRoot)
|
||||
: removeE2e(options, e2eProjectRoot),
|
||||
|
||||
options.e2eTestRunner === 'protractor'
|
||||
? updateE2eProject(options)
|
||||
: noop(),
|
||||
@ -388,10 +397,8 @@ export default function(schema: Schema): Rule {
|
||||
project: options.name
|
||||
})
|
||||
: noop(),
|
||||
|
||||
move(appProjectRoot, options.appProjectRoot),
|
||||
updateProject(options),
|
||||
|
||||
updateComponentTemplate(options),
|
||||
options.routing ? addRouterRootConfiguration(options) : noop(),
|
||||
updateLinting(options),
|
||||
|
||||
@ -81,7 +81,7 @@ module.exports = function(config) {
|
||||
});
|
||||
|
||||
describe('library', () => {
|
||||
it('should alter angular.json', async () => {
|
||||
it('should alter workspace.json', async () => {
|
||||
const resultTree = await runSchematic(
|
||||
'karma-project',
|
||||
{
|
||||
@ -89,8 +89,8 @@ module.exports = function(config) {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||
expect(angularJson.projects.lib1.architect.test).toEqual({
|
||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||
expect(workspaceJson.projects.lib1.architect.test).toEqual({
|
||||
builder: '@angular-devkit/build-angular:karma',
|
||||
options: {
|
||||
main: 'libs/lib1/src/test.ts',
|
||||
@ -99,7 +99,7 @@ module.exports = function(config) {
|
||||
}
|
||||
});
|
||||
expect(
|
||||
angularJson.projects.lib1.architect.lint.options.tsConfig
|
||||
workspaceJson.projects.lib1.architect.lint.options.tsConfig
|
||||
).toContain('libs/lib1/tsconfig.spec.json');
|
||||
});
|
||||
|
||||
@ -141,7 +141,7 @@ module.exports = function(config) {
|
||||
});
|
||||
|
||||
describe('applications', () => {
|
||||
it('should alter angular.json', async () => {
|
||||
it('should alter workspace.json', async () => {
|
||||
const resultTree = await runSchematic(
|
||||
'karma-project',
|
||||
{
|
||||
@ -149,8 +149,8 @@ module.exports = function(config) {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||
expect(angularJson.projects.app1.architect.test).toEqual({
|
||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||
expect(workspaceJson.projects.app1.architect.test).toEqual({
|
||||
builder: '@angular-devkit/build-angular:karma',
|
||||
options: {
|
||||
main: 'apps/app1/src/test.ts',
|
||||
@ -163,7 +163,7 @@ module.exports = function(config) {
|
||||
}
|
||||
});
|
||||
expect(
|
||||
angularJson.projects.app1.architect.lint.options.tsConfig
|
||||
workspaceJson.projects.app1.architect.lint.options.tsConfig
|
||||
).toContain('apps/app1/tsconfig.spec.json');
|
||||
});
|
||||
|
||||
|
||||
@ -13,7 +13,8 @@ import {
|
||||
import {
|
||||
readJsonInTree,
|
||||
updateJsonInTree,
|
||||
offsetFromRoot
|
||||
offsetFromRoot,
|
||||
updateWorkspaceInTree
|
||||
} from '@nrwl/workspace';
|
||||
import { join, normalize } from '@angular-devkit/core';
|
||||
import { getProjectConfig } from '@nrwl/workspace';
|
||||
@ -76,8 +77,8 @@ function updateTsSpecConfig(options: KarmaProjectSchema): Rule {
|
||||
};
|
||||
}
|
||||
|
||||
function updateAngularJson(options: KarmaProjectSchema): Rule {
|
||||
return updateJsonInTree('angular.json', json => {
|
||||
function updateworkspaceJson(options: KarmaProjectSchema): Rule {
|
||||
return updateWorkspaceInTree(json => {
|
||||
const projectConfig = json.projects[options.project];
|
||||
projectConfig.architect.test = {
|
||||
builder: '@angular-devkit/build-angular:karma',
|
||||
@ -124,6 +125,6 @@ export default function(options: KarmaProjectSchema): Rule {
|
||||
generateFiles(options),
|
||||
updateTsConfig(options),
|
||||
updateTsSpecConfig(options),
|
||||
updateAngularJson(options)
|
||||
updateworkspaceJson(options)
|
||||
]);
|
||||
}
|
||||
|
||||
@ -5,5 +5,5 @@ This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## 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');
|
||||
});
|
||||
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'lib',
|
||||
{ name: 'myLib', framework: 'angular', publishable: true },
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
||||
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||
|
||||
expect(angularJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||
expect(angularJson.projects['my-lib'].architect.build).toBeDefined();
|
||||
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||
expect(workspaceJson.projects['my-lib'].architect.build).toBeDefined();
|
||||
expect(
|
||||
angularJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||
workspaceJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||
).toEqual([
|
||||
'libs/my-lib/tsconfig.lib.json',
|
||||
'libs/my-lib/tsconfig.spec.json'
|
||||
]);
|
||||
expect(
|
||||
angularJson.projects['my-lib'].architect.lint.options.exclude
|
||||
workspaceJson.projects['my-lib'].architect.lint.options.exclude
|
||||
).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(
|
||||
'lib',
|
||||
{ name: 'myLib', publishable: false },
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
||||
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||
|
||||
expect(angularJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||
expect(angularJson.projects['my-lib'].architect.build).not.toBeDefined();
|
||||
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||
expect(
|
||||
workspaceJson.projects['my-lib'].architect.build
|
||||
).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should update nx.json', async () => {
|
||||
@ -216,8 +218,9 @@ describe('lib', () => {
|
||||
it('should default the prefix to npmScope', async () => {
|
||||
const noPrefix = await runSchematic('lib', { name: 'myLib' }, appTree);
|
||||
expect(
|
||||
JSON.parse(noPrefix.read('angular.json').toString()).projects['my-lib']
|
||||
.prefix
|
||||
JSON.parse(noPrefix.read('workspace.json').toString()).projects[
|
||||
'my-lib'
|
||||
].prefix
|
||||
).toEqual('proj');
|
||||
|
||||
const withPrefix = await runSchematic(
|
||||
@ -226,7 +229,7 @@ describe('lib', () => {
|
||||
appTree
|
||||
);
|
||||
expect(
|
||||
JSON.parse(withPrefix.read('angular.json').toString()).projects[
|
||||
JSON.parse(withPrefix.read('workspace.json').toString()).projects[
|
||||
'my-lib'
|
||||
].prefix
|
||||
).toEqual('custom');
|
||||
@ -381,26 +384,26 @@ describe('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(
|
||||
'lib',
|
||||
{ name: 'myLib', directory: 'myDir' },
|
||||
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'
|
||||
);
|
||||
|
||||
expect(
|
||||
angularJson.projects['my-dir-my-lib'].architect.lint.options.tsConfig
|
||||
workspaceJson.projects['my-dir-my-lib'].architect.lint.options.tsConfig
|
||||
).toEqual([
|
||||
'libs/my-dir/my-lib/tsconfig.lib.json',
|
||||
'libs/my-dir/my-lib/tsconfig.spec.json'
|
||||
]);
|
||||
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/**']);
|
||||
});
|
||||
|
||||
@ -763,9 +766,9 @@ describe('lib', () => {
|
||||
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': {
|
||||
styleext: 'scss'
|
||||
}
|
||||
@ -785,18 +788,18 @@ describe('lib', () => {
|
||||
expect(resultTree.exists('libs/my-lib/tsconfig.spec.json')).toBeTruthy();
|
||||
expect(resultTree.exists('libs/my-lib/karma.conf.js')).toBeTruthy();
|
||||
expect(resultTree.exists('karma.conf.js')).toBeTruthy();
|
||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||
expect(angularJson.projects['my-lib'].architect.test.builder).toEqual(
|
||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-lib'].architect.test.builder).toEqual(
|
||||
'@angular-devkit/build-angular:karma'
|
||||
);
|
||||
expect(
|
||||
angularJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||
workspaceJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||
).toEqual([
|
||||
'libs/my-lib/tsconfig.lib.json',
|
||||
'libs/my-lib/tsconfig.spec.json'
|
||||
]);
|
||||
expect(
|
||||
angularJson.projects['my-lib'].architect.lint.options.exclude
|
||||
workspaceJson.projects['my-lib'].architect.lint.options.exclude
|
||||
).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/jest.config.js')).toBeFalsy();
|
||||
expect(resultTree.exists('libs/my-lib/karma.conf.js')).toBeFalsy();
|
||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||
expect(angularJson.projects['my-lib'].architect.test).toBeUndefined();
|
||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-lib'].architect.test).toBeUndefined();
|
||||
expect(
|
||||
angularJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||
workspaceJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||
).toEqual(['libs/my-lib/tsconfig.lib.json']);
|
||||
});
|
||||
});
|
||||
|
||||
@ -22,7 +22,8 @@ import {
|
||||
NxJson,
|
||||
updateJsonInTree,
|
||||
readJsonInTree,
|
||||
offsetFromRoot
|
||||
offsetFromRoot,
|
||||
addGlobalLint
|
||||
} from '@nrwl/workspace';
|
||||
import { addGlobal, addIncludeToTsConfig, insert } from '@nrwl/workspace';
|
||||
import { toClassName, toFileName, toPropertyName } from '@nrwl/workspace';
|
||||
@ -430,6 +431,7 @@ export default function(schema: Schema): Rule {
|
||||
}
|
||||
|
||||
return chain([
|
||||
addGlobalLint('tslint'),
|
||||
addUnitTestRunner(options),
|
||||
externalSchematic('@schematics/angular', 'library', {
|
||||
name: options.name,
|
||||
|
||||
@ -74,7 +74,7 @@ describe('ng-add', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const { schematics } = readJsonInTree(tree, 'angular.json');
|
||||
const { schematics } = readJsonInTree(tree, 'workspace.json');
|
||||
expect(schematics['@nrwl/angular:application'].unitTestRunner).toEqual(
|
||||
'karma'
|
||||
);
|
||||
@ -118,7 +118,7 @@ describe('ng-add', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const { schematics } = readJsonInTree(tree, 'angular.json');
|
||||
const { schematics } = readJsonInTree(tree, 'workspace.json');
|
||||
expect(schematics['@nrwl/angular:application'].unitTestRunner).toEqual(
|
||||
'jest'
|
||||
);
|
||||
@ -153,7 +153,7 @@ describe('ng-add', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const { schematics } = readJsonInTree(tree, 'angular.json');
|
||||
const { schematics } = readJsonInTree(tree, 'workspace.json');
|
||||
expect(schematics['@nrwl/angular:application'].e2eTestRunner).toEqual(
|
||||
'cypress'
|
||||
);
|
||||
@ -185,7 +185,7 @@ describe('ng-add', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const { schematics } = readJsonInTree(tree, 'angular.json');
|
||||
const { schematics } = readJsonInTree(tree, 'workspace.json');
|
||||
expect(schematics['@nrwl/angular:application'].e2eTestRunner).toEqual(
|
||||
'protractor'
|
||||
);
|
||||
@ -196,13 +196,13 @@ describe('ng-add', () => {
|
||||
describe('defaultCollection', () => {
|
||||
it('should be set if none was set before', async () => {
|
||||
const result = await runSchematic('ng-add', {}, appTree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
});
|
||||
|
||||
it('should be set if @nrwl/workspace was set before', async () => {
|
||||
appTree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/workspace'
|
||||
};
|
||||
@ -212,13 +212,13 @@ describe('ng-add', () => {
|
||||
appTree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, appTree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
});
|
||||
|
||||
it('should not be set if something else was set before', async () => {
|
||||
appTree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/react'
|
||||
};
|
||||
@ -228,8 +228,8 @@ describe('ng-add', () => {
|
||||
appTree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, appTree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/react');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/react');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -94,7 +94,7 @@ export function createApp(
|
||||
})
|
||||
);
|
||||
tree.overwrite(
|
||||
'/angular.json',
|
||||
'/workspace.json',
|
||||
JSON.stringify({
|
||||
newProjectRoot: '',
|
||||
version: 1,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export const nxVersion = '*';
|
||||
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 ngrxVersion = '8.1.0';
|
||||
export const rxjsVersion = '~6.4.0';
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
"dependencies": {
|
||||
"tmp": "0.0.33",
|
||||
"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 { execSync } from 'child_process';
|
||||
import { writeFileSync } from 'fs';
|
||||
import * as inquirer from 'inquirer';
|
||||
import * as path from 'path';
|
||||
import { dirSync } from 'tmp';
|
||||
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, {
|
||||
string: ['directory'],
|
||||
string: ['cli', 'preset'],
|
||||
boolean: ['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(`
|
||||
Usage: create-nx-workspace <directory> [options] [ng new options]
|
||||
Usage: create-nx-workspace <name> [options] [new workspace options]
|
||||
|
||||
Create a new Nx workspace
|
||||
|
||||
Options:
|
||||
|
||||
directory path to the workspace root directory
|
||||
name workspace name
|
||||
|
||||
[ng new options] any 'ng new' options
|
||||
run 'ng new --help' for more information
|
||||
preset What to create in a new workspace (options: ${presetOptions
|
||||
.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 = {
|
||||
name: 'Schematics',
|
||||
packageName: '@nrwl/workspace'
|
||||
};
|
||||
|
||||
function determinePackageManager() {
|
||||
// If you have Angular CLI installed, read Angular CLI config.
|
||||
// If it isn't not installed, default to 'yarn'.
|
||||
let packageManager: string;
|
||||
try {
|
||||
packageManager = execSync('ng config -g cli.packageManager', {
|
||||
stdio: ['ignore', 'pipe', 'ignore']
|
||||
stdio: ['ignore', 'pipe', 'ignore'],
|
||||
timeout: 500
|
||||
})
|
||||
.toString()
|
||||
.trim();
|
||||
@ -51,10 +100,12 @@ try {
|
||||
} catch (e) {
|
||||
packageManager = 'npm';
|
||||
}
|
||||
return packageManager;
|
||||
}
|
||||
|
||||
function validateInput(parsedArgs: any) {
|
||||
const projectName = parsedArgs._[2];
|
||||
|
||||
// check that the workspace name is passed in
|
||||
if (!projectName) {
|
||||
output.error({
|
||||
title: 'A project name is required when creating a new workspace',
|
||||
@ -67,21 +118,102 @@ if (!projectName) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// creating the sandbox
|
||||
output.logSingleLine(`Creating a sandbox...`);
|
||||
return projectName;
|
||||
}
|
||||
|
||||
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 nxVersion = 'NX_VERSION';
|
||||
const cliVersion = 'ANGULAR_CLI_VERSION';
|
||||
const typescriptVersion = 'TYPESCRIPT_VERSION';
|
||||
|
||||
writeFileSync(
|
||||
path.join(tmpDir, 'package.json'),
|
||||
JSON.stringify({
|
||||
dependencies: {
|
||||
[nxTool.packageName]: nxVersion,
|
||||
'@angular/cli': cliVersion,
|
||||
typescript: typescriptVersion
|
||||
'@nrwl/workspace': nxVersion,
|
||||
[cli.package]: cli.version,
|
||||
typescript: tsVersion
|
||||
},
|
||||
license: 'MIT'
|
||||
})
|
||||
@ -92,42 +224,69 @@ execSync(`${packageManager} install --silent`, {
|
||||
stdio: [0, 1, 2]
|
||||
});
|
||||
|
||||
return tmpDir;
|
||||
}
|
||||
|
||||
function createApp(
|
||||
tmpDir: string,
|
||||
cli: { command: string },
|
||||
parsedArgs: any,
|
||||
preset: string
|
||||
) {
|
||||
// creating the app itself
|
||||
const args = process.argv
|
||||
.slice(2)
|
||||
.filter(a => !a.startsWith('--cli')) // not used by the new command
|
||||
.map(a => `"${a}"`)
|
||||
.join(' ');
|
||||
|
||||
output.logSingleLine(
|
||||
`${output.colors.gray('Running:')} ng new ${args} --collection=${
|
||||
nxTool.packageName
|
||||
}`
|
||||
);
|
||||
const presetArg = parsedArgs.preset ? '' : ` --preset=${preset}`;
|
||||
|
||||
console.log(`new ${args}${presetArg} --collection=@nrwl/workspace`);
|
||||
execSync(
|
||||
`"${path.join(
|
||||
tmpDir,
|
||||
'node_modules',
|
||||
'.bin',
|
||||
'ng'
|
||||
)}" new ${args} --collection=${nxTool.packageName}`,
|
||||
cli.command
|
||||
)}" new ${args}${presetArg} --collection=@nrwl/workspace`,
|
||||
{
|
||||
stdio: [0, 1, 2]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: vsavkin: reenable for 8.4
|
||||
// try {
|
||||
// execSync('nx --version');
|
||||
// } catch (e) {
|
||||
// // no nx found
|
||||
// console.log('-----------------------------------------------------------');
|
||||
// console.log(`It looks like you don't have the Nx CLI installed globally.`);
|
||||
// console.log(
|
||||
// `This means that you might have to use "yarn nx" or "npm nx" to execute commands in your workspace.`
|
||||
// );
|
||||
// console.log(
|
||||
// `If you want to execute the nx command directly, run "yarn global add @nrwl/cli" or "npm install -g @nrwl/cli"`
|
||||
// );
|
||||
// console.log('-----------------------------------------------------------');
|
||||
// }
|
||||
function showNxWarning() {
|
||||
try {
|
||||
execSync('nx --version', { stdio: ['ignore', 'ignore', 'ignore'] });
|
||||
} catch (e) {
|
||||
// no nx found
|
||||
console.log('-----------------------------------------------------------');
|
||||
console.log(`It looks like you don't have the Nx CLI installed globally.`);
|
||||
console.log(
|
||||
`This means that you might have to use "yarn nx" or "npm nx" to execute commands in your workspace.`
|
||||
);
|
||||
console.log(
|
||||
`If you want to execute the nx command directly, run "yarn global add @nrwl/cli" or "npm install -g @nrwl/cli"`
|
||||
);
|
||||
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": "*",
|
||||
"tmp": "0.0.33",
|
||||
"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();
|
||||
});
|
||||
|
||||
it('should add update `angular.json` file', async () => {
|
||||
it('should add update `workspace.json` file', async () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-app' },
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
const project = angularJson.projects['my-app-e2e'];
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
const project = workspaceJson.projects['my-app-e2e'];
|
||||
|
||||
expect(project.root).toEqual('apps/my-app-e2e');
|
||||
|
||||
expect(project.architect.lint).toEqual({
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
options: {
|
||||
tsConfig: 'apps/my-app-e2e/tsconfig.e2e.json',
|
||||
tsConfig: ['apps/my-app-e2e/tsconfig.e2e.json'],
|
||||
exclude: ['**/node_modules/**', '!apps/my-app-e2e/**']
|
||||
}
|
||||
});
|
||||
@ -107,13 +107,13 @@ describe('schematic:cypress-project', () => {
|
||||
});
|
||||
|
||||
describe('nested', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'cypress-project',
|
||||
{ name: 'my-app-e2e', project: 'my-dir-my-app', directory: 'my-dir' },
|
||||
appTree
|
||||
);
|
||||
const projectConfig = readJsonInTree(tree, 'angular.json').projects[
|
||||
const projectConfig = readJsonInTree(tree, 'workspace.json').projects[
|
||||
'my-dir-my-app-e2e'
|
||||
];
|
||||
|
||||
@ -121,7 +121,7 @@ describe('schematic:cypress-project', () => {
|
||||
expect(projectConfig.architect.lint).toEqual({
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
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/**']
|
||||
}
|
||||
});
|
||||
|
||||
@ -9,7 +9,13 @@ import {
|
||||
} from '@angular-devkit/schematics';
|
||||
import { join, normalize } from '@angular-devkit/core';
|
||||
// app
|
||||
import { updateJsonInTree, NxJson } from '@nrwl/workspace';
|
||||
import {
|
||||
updateJsonInTree,
|
||||
NxJson,
|
||||
updateWorkspaceInTree,
|
||||
generateProjectLint,
|
||||
addGlobalLint
|
||||
} from '@nrwl/workspace';
|
||||
import { offsetFromRoot } from '@nrwl/workspace';
|
||||
import { toFileName } from '@nrwl/workspace';
|
||||
import { Schema } from './schema';
|
||||
@ -44,8 +50,8 @@ function updateNxJson(options: CypressProjectSchema): Rule {
|
||||
});
|
||||
}
|
||||
|
||||
function updateAngularJson(options: CypressProjectSchema): Rule {
|
||||
return updateJsonInTree('angular.json', json => {
|
||||
function updateWorkspaceJson(options: CypressProjectSchema): Rule {
|
||||
return updateWorkspaceInTree(json => {
|
||||
const architect: any = {};
|
||||
|
||||
architect.e2e = {
|
||||
@ -61,16 +67,13 @@ function updateAngularJson(options: CypressProjectSchema): Rule {
|
||||
}
|
||||
}
|
||||
};
|
||||
architect.lint = {
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
options: {
|
||||
tsConfig: join(normalize(options.projectRoot), 'tsconfig.e2e.json'),
|
||||
exclude: [
|
||||
'**/node_modules/**',
|
||||
'!' + join(normalize(options.projectRoot), '**')
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
architect.lint = generateProjectLint(
|
||||
normalize(options.projectRoot),
|
||||
join(normalize(options.projectRoot), 'tsconfig.e2e.json'),
|
||||
options.linter
|
||||
);
|
||||
|
||||
json.projects[options.projectName] = {
|
||||
root: options.projectRoot,
|
||||
sourceRoot: join(normalize(options.projectRoot), 'src'),
|
||||
@ -84,8 +87,9 @@ function updateAngularJson(options: CypressProjectSchema): Rule {
|
||||
export default function(options: CypressProjectSchema): Rule {
|
||||
options = normalizeOptions(options);
|
||||
return chain([
|
||||
addGlobalLint(options.linter),
|
||||
generateFiles(options),
|
||||
updateAngularJson(options),
|
||||
updateWorkspaceJson(options),
|
||||
updateNxJson(options)
|
||||
]);
|
||||
}
|
||||
|
||||
@ -2,4 +2,5 @@ export interface Schema {
|
||||
project: string;
|
||||
name: string;
|
||||
directory: string;
|
||||
linter: 'eslint' | 'tslint';
|
||||
}
|
||||
|
||||
@ -24,6 +24,12 @@
|
||||
"type": "string",
|
||||
"description": "A directory where the app is placed",
|
||||
"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"]
|
||||
|
||||
@ -32,13 +32,13 @@ describe('ng-add', () => {
|
||||
describe('defaultCollection', () => {
|
||||
it('should be set if none was set before', async () => {
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/express');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/express');
|
||||
});
|
||||
|
||||
it('should be set if @nrwl/workspace was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/workspace'
|
||||
};
|
||||
@ -48,13 +48,13 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/express');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/express');
|
||||
});
|
||||
|
||||
it('should not be set if something else was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/angular'
|
||||
};
|
||||
@ -64,8 +64,8 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -10,7 +10,7 @@ describe('jestProject', () => {
|
||||
appTree = Tree.empty();
|
||||
appTree = createEmptyWorkspace(appTree);
|
||||
appTree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.projects.lib1 = {
|
||||
root: 'libs/lib1',
|
||||
architect: {
|
||||
@ -52,7 +52,7 @@ describe('jestProject', () => {
|
||||
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(
|
||||
'jest-project',
|
||||
{
|
||||
@ -61,8 +61,8 @@ describe('jestProject', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||
expect(angularJson.projects.lib1.architect.test).toEqual({
|
||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||
expect(workspaceJson.projects.lib1.architect.test).toEqual({
|
||||
builder: '@nrwl/jest:jest',
|
||||
options: {
|
||||
jestConfig: 'libs/lib1/jest.config.js',
|
||||
@ -70,9 +70,9 @@ describe('jestProject', () => {
|
||||
tsConfig: 'libs/lib1/tsconfig.spec.json'
|
||||
}
|
||||
});
|
||||
expect(angularJson.projects.lib1.architect.lint.options.tsConfig).toContain(
|
||||
'libs/lib1/tsconfig.spec.json'
|
||||
);
|
||||
expect(
|
||||
workspaceJson.projects.lib1.architect.lint.options.tsConfig
|
||||
).toContain('libs/lib1/tsconfig.spec.json');
|
||||
});
|
||||
|
||||
it('should create a jest.config.js', async () => {
|
||||
@ -144,7 +144,7 @@ describe('jestProject', () => {
|
||||
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(
|
||||
'jest-project',
|
||||
{
|
||||
@ -153,9 +153,9 @@ describe('jestProject', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||
expect(
|
||||
angularJson.projects.lib1.architect.test.options.setupFile
|
||||
workspaceJson.projects.lib1.architect.test.options.setupFile
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
@ -189,7 +189,7 @@ describe('jestProject', () => {
|
||||
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(
|
||||
'jest-project',
|
||||
{
|
||||
@ -198,9 +198,9 @@ describe('jestProject', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||
expect(
|
||||
angularJson.projects.lib1.architect.test.options.setupFile
|
||||
workspaceJson.projects.lib1.architect.test.options.setupFile
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
|
||||
@ -11,7 +11,11 @@ import {
|
||||
noop,
|
||||
filter
|
||||
} from '@angular-devkit/schematics';
|
||||
import { readJsonInTree, updateJsonInTree } from '@nrwl/workspace';
|
||||
import {
|
||||
readJsonInTree,
|
||||
updateJsonInTree,
|
||||
updateWorkspaceInTree
|
||||
} from '@nrwl/workspace';
|
||||
import { getProjectConfig, addDepsToPackageJson } from '@nrwl/workspace';
|
||||
import { offsetFromRoot } from '@nrwl/workspace';
|
||||
import { join, normalize } from '@angular-devkit/core';
|
||||
@ -69,8 +73,8 @@ function updateTsConfig(options: JestProjectSchema): Rule {
|
||||
};
|
||||
}
|
||||
|
||||
function updateAngularJson(options: JestProjectSchema): Rule {
|
||||
return updateJsonInTree('angular.json', json => {
|
||||
function updateWorkspaceJson(options: JestProjectSchema): Rule {
|
||||
return updateWorkspaceInTree(json => {
|
||||
const projectConfig = json.projects[options.project];
|
||||
projectConfig.architect.test = {
|
||||
builder: '@nrwl/jest:jest',
|
||||
@ -106,7 +110,9 @@ function check(options: JestProjectSchema): Rule {
|
||||
const packageJson = readJsonInTree(host, 'package.json');
|
||||
if (!packageJson.devDependencies.jest) {
|
||||
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;
|
||||
};
|
||||
@ -128,6 +134,6 @@ export default function(options: JestProjectSchema): Rule {
|
||||
check(options),
|
||||
generateFiles(options),
|
||||
updateTsConfig(options),
|
||||
updateAngularJson(options)
|
||||
updateWorkspaceJson(options)
|
||||
]);
|
||||
}
|
||||
|
||||
@ -23,13 +23,13 @@ describe('ng-add', () => {
|
||||
describe('defaultCollection', () => {
|
||||
it('should be set if none was set before', async () => {
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/nest');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/nest');
|
||||
});
|
||||
|
||||
it('should be set if @nrwl/workspace was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/workspace'
|
||||
};
|
||||
@ -39,13 +39,13 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/nest');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/nest');
|
||||
});
|
||||
|
||||
it('should not be set if something else was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/angular'
|
||||
};
|
||||
@ -55,8 +55,8 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -14,10 +14,10 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('not nested', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic('app', { name: 'myNodeApp' }, appTree);
|
||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
||||
const project = angularJson.projects['my-node-app'];
|
||||
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||
const project = workspaceJson.projects['my-node-app'];
|
||||
expect(project.root).toEqual('apps/my-node-app');
|
||||
expect(project.architect).toEqual(
|
||||
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',
|
||||
options: {
|
||||
tsConfig: [
|
||||
@ -62,8 +62,8 @@ describe('app', () => {
|
||||
exclude: ['**/node_modules/**', '!apps/my-node-app/**']
|
||||
}
|
||||
});
|
||||
expect(angularJson.projects['my-node-app-e2e']).toBeUndefined();
|
||||
expect(angularJson.defaultProject).toEqual('my-node-app');
|
||||
expect(workspaceJson.projects['my-node-app-e2e']).toBeUndefined();
|
||||
expect(workspaceJson.defaultProject).toEqual('my-node-app');
|
||||
});
|
||||
|
||||
it('should update nx.json', async () => {
|
||||
@ -109,20 +109,21 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('nested', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'app',
|
||||
{ name: 'myNodeApp', directory: 'myDir' },
|
||||
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'
|
||||
);
|
||||
|
||||
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',
|
||||
options: {
|
||||
tsConfig: [
|
||||
@ -131,11 +132,10 @@ describe('app', () => {
|
||||
],
|
||||
exclude: ['**/node_modules/**', '!apps/my-dir/my-node-app/**']
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
expect(angularJson.projects['my-dir-my-node-app-e2e']).toBeUndefined();
|
||||
expect(angularJson.defaultProject).toEqual('my-dir-my-node-app');
|
||||
expect(workspaceJson.projects['my-dir-my-node-app-e2e']).toBeUndefined();
|
||||
expect(workspaceJson.defaultProject).toEqual('my-dir-my-node-app');
|
||||
});
|
||||
|
||||
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/tsconfig.spec.json')).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(
|
||||
angularJson.projects['my-node-app'].architect.test
|
||||
workspaceJson.projects['my-node-app'].architect.test
|
||||
).toBeUndefined();
|
||||
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']);
|
||||
});
|
||||
});
|
||||
@ -234,7 +234,7 @@ describe('app', () => {
|
||||
);
|
||||
|
||||
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'
|
||||
].architect.serve;
|
||||
expect(serve.options.proxyConfig).toEqual(
|
||||
@ -252,7 +252,7 @@ describe('app', () => {
|
||||
);
|
||||
|
||||
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'
|
||||
].architect.serve;
|
||||
expect(serve.options.proxyConfig).toEqual(
|
||||
|
||||
@ -13,7 +13,12 @@ import {
|
||||
} from '@angular-devkit/schematics';
|
||||
import { join, normalize, Path } from '@angular-devkit/core';
|
||||
import { Schema } from './schema';
|
||||
import { updateJsonInTree } from '@nrwl/workspace';
|
||||
import {
|
||||
updateJsonInTree,
|
||||
updateWorkspaceInTree,
|
||||
generateProjectLint,
|
||||
addGlobalLint
|
||||
} from '@nrwl/workspace';
|
||||
import { toFileName } from '@nrwl/workspace';
|
||||
import { getProjectConfig } 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) {
|
||||
return {
|
||||
builder: '@nrwl/node:execute',
|
||||
@ -80,8 +75,8 @@ function getServeConfig(options: NormalizedSchema) {
|
||||
};
|
||||
}
|
||||
|
||||
function updateAngularJson(options: NormalizedSchema): Rule {
|
||||
return updateJsonInTree('angular.json', angularJson => {
|
||||
function updateWorkspaceJson(options: NormalizedSchema): Rule {
|
||||
return updateWorkspaceInTree(workspaceJson => {
|
||||
const project = {
|
||||
root: options.appProjectRoot,
|
||||
sourceRoot: join(options.appProjectRoot, 'src'),
|
||||
@ -93,12 +88,17 @@ function updateAngularJson(options: NormalizedSchema): Rule {
|
||||
|
||||
project.architect.build = getBuildConfig(project, options);
|
||||
project.architect.serve = getServeConfig(options);
|
||||
project.architect.lint = getLintConfig(project);
|
||||
angularJson.projects[options.name] = project;
|
||||
project.architect.lint = generateProjectLint(
|
||||
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;
|
||||
json.projects[options.frontendProject] = projectConfig;
|
||||
return json;
|
||||
@ -151,8 +151,9 @@ export default function(schema: Schema): Rule {
|
||||
ngAdd({
|
||||
skipFormat: true
|
||||
}),
|
||||
addGlobalLint(options.linter),
|
||||
addAppFiles(options),
|
||||
updateAngularJson(options),
|
||||
updateWorkspaceJson(options),
|
||||
updateNxJson(options),
|
||||
options.unitTestRunner === 'jest'
|
||||
? 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 = {
|
||||
production: false
|
||||
};
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { UnitTestRunner } from '../../utils/test-runners';
|
||||
export interface Schema {
|
||||
name: string;
|
||||
skipFormat: boolean;
|
||||
skipPackageJson: boolean;
|
||||
directory?: string;
|
||||
unitTestRunner: UnitTestRunner;
|
||||
unitTestRunner: 'jest' | 'none';
|
||||
linter: 'eslint' | 'tslint';
|
||||
tags?: string;
|
||||
frontendProject?: string;
|
||||
}
|
||||
|
||||
@ -28,6 +28,12 @@
|
||||
"default": false,
|
||||
"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": {
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
|
||||
@ -21,13 +21,13 @@ describe('ng-add', () => {
|
||||
describe('defaultCollection', () => {
|
||||
it('should be set if none was set before', async () => {
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/node');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/node');
|
||||
});
|
||||
|
||||
it('should be set if @nrwl/workspace was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/workspace'
|
||||
};
|
||||
@ -37,13 +37,13 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/node');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/node');
|
||||
});
|
||||
|
||||
it('should not be set if something else was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/angular'
|
||||
};
|
||||
@ -53,8 +53,8 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -13,15 +13,15 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('not nested', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
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(angularJson.projects['my-app-e2e'].root).toEqual(
|
||||
expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app');
|
||||
expect(workspaceJson.projects['my-app-e2e'].root).toEqual(
|
||||
'apps/my-app-e2e'
|
||||
);
|
||||
expect(angularJson.defaultProject).toEqual('my-app');
|
||||
expect(workspaceJson.defaultProject).toEqual('my-app');
|
||||
});
|
||||
|
||||
it('should update nx.json', async () => {
|
||||
@ -76,18 +76,18 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('nested', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'app',
|
||||
{ name: 'myApp', directory: 'myDir' },
|
||||
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'
|
||||
);
|
||||
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'
|
||||
);
|
||||
});
|
||||
@ -225,8 +225,8 @@ describe('app', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
const architectConfig = angularJson.projects['my-app'].architect;
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||
expect(architectConfig.build.builder).toEqual('@nrwl/web:build');
|
||||
expect(architectConfig.build.options).toEqual({
|
||||
assets: ['apps/my-app/src/favicon.ico', 'apps/my-app/src/assets'],
|
||||
@ -270,8 +270,8 @@ describe('app', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
const architectConfig = angularJson.projects['my-app'].architect;
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||
expect(architectConfig.serve.builder).toEqual('@nrwl/web:dev-server');
|
||||
expect(architectConfig.serve.options).toEqual({
|
||||
buildTarget: 'my-app:build'
|
||||
@ -289,8 +289,8 @@ describe('app', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app'].architect.lint).toEqual({
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-app'].architect.lint).toEqual({
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
options: {
|
||||
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/tsconfig.spec.json')).toBeFalsy();
|
||||
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app'].architect.test).toBeUndefined();
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-app'].architect.test).toBeUndefined();
|
||||
expect(
|
||||
angularJson.projects['my-app'].architect.lint.options.tsConfig
|
||||
workspaceJson.projects['my-app'].architect.lint.options.tsConfig
|
||||
).toEqual(['apps/my-app/tsconfig.app.json']);
|
||||
});
|
||||
});
|
||||
@ -328,8 +328,8 @@ describe('app', () => {
|
||||
appTree
|
||||
);
|
||||
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app-e2e']).toBeUndefined();
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-app-e2e']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@ -417,17 +417,17 @@ describe('app', () => {
|
||||
expect(content).toContain('<StyledApp>');
|
||||
});
|
||||
|
||||
it('should exclude styles from angular.json', async () => {
|
||||
it('should exclude styles from workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'app',
|
||||
{ name: 'myApp', style: '@emotion/styled' },
|
||||
appTree
|
||||
);
|
||||
|
||||
const angularJSON = readJsonInTree(tree, 'angular.json');
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
|
||||
expect(
|
||||
angularJSON.projects['my-app'].architect.build.options.styles
|
||||
workspaceJson.projects['my-app'].architect.build.options.styles
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
|
||||
@ -19,9 +19,14 @@ import {
|
||||
NxJson,
|
||||
offsetFromRoot,
|
||||
toFileName,
|
||||
updateJsonInTree
|
||||
updateJsonInTree,
|
||||
generateProjectLint,
|
||||
addGlobalLint
|
||||
} 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 * as ts from 'typescript';
|
||||
|
||||
@ -48,6 +53,7 @@ export default function(schema: Schema): Rule {
|
||||
ngAdd({
|
||||
skipFormat: true
|
||||
}),
|
||||
addGlobalLint(options.linter),
|
||||
createApplicationFiles(options),
|
||||
updateNxJson(options),
|
||||
addProject(options),
|
||||
@ -102,7 +108,7 @@ function updateNxJson(options: NormalizedSchema): Rule {
|
||||
}
|
||||
|
||||
function addProject(options: NormalizedSchema): Rule {
|
||||
return updateJsonInTree('angular.json', json => {
|
||||
return updateWorkspaceInTree(json => {
|
||||
const architect: { [key: string]: any } = {};
|
||||
|
||||
architect.build = {
|
||||
@ -166,16 +172,11 @@ function addProject(options: NormalizedSchema): Rule {
|
||||
}
|
||||
};
|
||||
|
||||
architect.lint = {
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
options: {
|
||||
tsConfig: [join(options.appProjectRoot, 'tsconfig.app.json')],
|
||||
exclude: [
|
||||
'**/node_modules/**',
|
||||
'!' + join(options.appProjectRoot, '**')
|
||||
]
|
||||
}
|
||||
};
|
||||
architect.lint = generateProjectLint(
|
||||
normalize(options.appProjectRoot),
|
||||
join(normalize(options.appProjectRoot), 'tsconfig.app.json'),
|
||||
options.linter
|
||||
);
|
||||
|
||||
json.projects[options.projectName] = {
|
||||
root: options.appProjectRoot,
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
|
||||
export interface Schema {
|
||||
name: string;
|
||||
style?: string;
|
||||
skipFormat: boolean;
|
||||
directory?: string;
|
||||
tags?: string;
|
||||
unitTestRunner: UnitTestRunner;
|
||||
e2eTestRunner: E2eTestRunner;
|
||||
unitTestRunner: 'jest' | 'none';
|
||||
e2eTestRunner: 'cypress' | 'none';
|
||||
linter: 'eslint' | 'tslint';
|
||||
pascalCaseFiles?: boolean;
|
||||
classComponent?: 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": {
|
||||
"type": "boolean",
|
||||
"description": "Generate application with routes",
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"properties": {
|
||||
"project": {
|
||||
"type": "string",
|
||||
"description": "The name of the project (as specified in angular.json).",
|
||||
"description": "The name of the project.",
|
||||
"$default": {
|
||||
"$source": "projectName"
|
||||
},
|
||||
|
||||
@ -4,4 +4,4 @@ This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## 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', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic('lib', { name: 'myLib' }, appTree);
|
||||
const angularJson = readJsonInTree(tree, '/angular.json');
|
||||
|
||||
expect(angularJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||
expect(angularJson.projects['my-lib'].architect.build).toBeUndefined();
|
||||
expect(angularJson.projects['my-lib'].architect.lint).toEqual({
|
||||
const workspaceJson = readJsonInTree(tree, '/workspace.json');
|
||||
expect(workspaceJson.projects['my-lib'].root).toEqual('libs/my-lib');
|
||||
expect(workspaceJson.projects['my-lib'].architect.build).toBeUndefined();
|
||||
expect(workspaceJson.projects['my-lib'].architect.lint).toEqual({
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
options: {
|
||||
exclude: ['**/node_modules/**', '!libs/my-lib/**'],
|
||||
@ -172,18 +171,18 @@ describe('lib', () => {
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'lib',
|
||||
{ name: 'myLib', directory: 'myDir' },
|
||||
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'
|
||||
);
|
||||
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',
|
||||
options: {
|
||||
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/jest.config.js')).toBeFalsy();
|
||||
const angularJson = readJsonInTree(resultTree, 'angular.json');
|
||||
expect(angularJson.projects['my-lib'].architect.test).toBeUndefined();
|
||||
const workspaceJson = readJsonInTree(resultTree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-lib'].architect.test).toBeUndefined();
|
||||
expect(
|
||||
angularJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||
workspaceJson.projects['my-lib'].architect.lint.options.tsConfig
|
||||
).toEqual(['libs/my-lib/tsconfig.lib.json']);
|
||||
});
|
||||
});
|
||||
|
||||
@ -22,7 +22,10 @@ import {
|
||||
readJsonInTree,
|
||||
toClassName,
|
||||
toFileName,
|
||||
updateJsonInTree
|
||||
updateJsonInTree,
|
||||
updateWorkspaceInTree,
|
||||
addGlobalLint,
|
||||
generateProjectLint
|
||||
} from '@nrwl/workspace';
|
||||
import { join, normalize, Path } from '@angular-devkit/core';
|
||||
import * as ts from 'typescript';
|
||||
@ -44,6 +47,7 @@ export default function(schema: Schema): Rule {
|
||||
const options = normalizeOptions(schema);
|
||||
|
||||
return chain([
|
||||
addGlobalLint(options.linter),
|
||||
createFiles(options),
|
||||
!options.skipTsConfig ? updateTsConfig(options) : noop(),
|
||||
addProject(options),
|
||||
@ -71,19 +75,14 @@ export default function(schema: Schema): Rule {
|
||||
}
|
||||
|
||||
function addProject(options: NormalizedSchema): Rule {
|
||||
return updateJsonInTree('angular.json', json => {
|
||||
return updateWorkspaceInTree(json => {
|
||||
const architect: { [key: string]: any } = {};
|
||||
|
||||
architect.lint = {
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
options: {
|
||||
tsConfig: [join(normalize(options.projectRoot), 'tsconfig.lib.json')],
|
||||
exclude: [
|
||||
'**/node_modules/**',
|
||||
'!' + join(normalize(options.projectRoot), '**')
|
||||
]
|
||||
}
|
||||
};
|
||||
architect.lint = generateProjectLint(
|
||||
normalize(options.projectRoot),
|
||||
join(normalize(options.projectRoot), 'tsconfig.lib.json'),
|
||||
options.linter
|
||||
);
|
||||
|
||||
json.projects[options.name] = {
|
||||
root: options.projectRoot,
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import { UnitTestRunner } from '../../utils/test-runners';
|
||||
|
||||
export interface Schema {
|
||||
name: string;
|
||||
directory?: string;
|
||||
@ -11,5 +9,6 @@ export interface Schema {
|
||||
pascalCaseFiles?: boolean;
|
||||
routing?: boolean;
|
||||
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": {
|
||||
"type": "string",
|
||||
"enum": ["jest", "none"],
|
||||
|
||||
@ -27,13 +27,13 @@ describe('ng-add', () => {
|
||||
describe('defaultCollection', () => {
|
||||
it('should be set if none was set before', async () => {
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/react');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/react');
|
||||
});
|
||||
|
||||
it('should be set if @nrwl/workspace was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/workspace'
|
||||
};
|
||||
@ -43,13 +43,13 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/react');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/react');
|
||||
});
|
||||
|
||||
it('should not be set if something else was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/angular'
|
||||
};
|
||||
@ -59,8 +59,8 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
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 { offsetFromRoot } from '@nrwl/workspace';
|
||||
import * as path from 'path';
|
||||
@ -6,7 +6,7 @@ import * as path from 'path';
|
||||
export default {
|
||||
description: 'Create tsconfig.app.json for every app',
|
||||
run: () => {
|
||||
const config = readCliConfigFile();
|
||||
const config = readWorkspaceConfigPath();
|
||||
config.apps.forEach(app => {
|
||||
if (!app.root.startsWith('apps/')) return;
|
||||
const offset = offsetFromRoot(app.root);
|
||||
|
||||
@ -5,7 +5,7 @@ import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||
export default {
|
||||
description: `Create nx.json before migrating to Angular CLI 6.`,
|
||||
run: () => {
|
||||
if (!existsSync('.angular-cli.json') && existsSync('angular.json')) {
|
||||
if (!existsSync('.angular-cli.json') && existsSync('workspace.json')) {
|
||||
console.warn(stripIndents`
|
||||
You have already upgraded to Angular CLI 6.
|
||||
We will not be able to recover information about your project's tags for you.
|
||||
@ -13,8 +13,8 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
const angularJson = readJsonFile('.angular-cli.json');
|
||||
const projects = angularJson.apps.reduce((projects, app) => {
|
||||
const workspaceJson = readJsonFile('.angular-cli.json');
|
||||
const projects = workspaceJson.apps.reduce((projects, app) => {
|
||||
if (app.name === '$workspaceRoot') {
|
||||
return projects;
|
||||
}
|
||||
@ -33,7 +33,7 @@ export default {
|
||||
writeFileSync(
|
||||
'nx.json',
|
||||
serializeJson({
|
||||
npmScope: angularJson.project.npmScope,
|
||||
npmScope: workspaceJson.project.npmScope,
|
||||
projects: projects
|
||||
})
|
||||
);
|
||||
|
||||
@ -7,7 +7,7 @@ import { join } from 'path';
|
||||
export default {
|
||||
description: `Switch to Nx 6.0`,
|
||||
run: () => {
|
||||
if (!existsSync('.angular-cli.json') && existsSync('angular.json')) {
|
||||
if (!existsSync('.angular-cli.json') && existsSync('workspace.json')) {
|
||||
console.warn(stripIndents`
|
||||
You have already upgraded to Angular CLI 6.
|
||||
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 {
|
||||
createOrUpdate,
|
||||
readJsonInTree,
|
||||
updateJsonInTree
|
||||
updateJsonInTree,
|
||||
updateWorkspaceInTree
|
||||
} from '@nrwl/workspace';
|
||||
import { serializeJson, renameSync } from '@nrwl/workspace';
|
||||
import { parseTarget, serializeTarget } from '@nrwl/workspace';
|
||||
@ -256,8 +257,8 @@ function createTsconfigLibJson(host: Tree, project: any) {
|
||||
}
|
||||
|
||||
function createAdditionalFiles(host: Tree) {
|
||||
const angularJson = readJsonInTree(host, 'angular.json');
|
||||
Object.entries<any>(angularJson.projects).forEach(([key, project]) => {
|
||||
const workspaceJson = readJsonInTree(host, 'workspace.json');
|
||||
Object.entries<any>(workspaceJson.projects).forEach(([key, project]) => {
|
||||
if (project.architect.test) {
|
||||
createTsconfigSpecJson(host, project);
|
||||
createKarma(host, project);
|
||||
@ -282,9 +283,9 @@ function createAdditionalFiles(host: Tree) {
|
||||
}
|
||||
|
||||
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) {
|
||||
renameSync(`${p.root}/e2e`, `${p.root}-e2e/src`, err => {
|
||||
if (!err) {
|
||||
@ -320,9 +321,9 @@ function deleteUnneededFiles(host: Tree) {
|
||||
}
|
||||
|
||||
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') {
|
||||
try {
|
||||
// TODO: incorporate this into fileutils.renameSync
|
||||
@ -489,8 +490,8 @@ function createDefaultE2eTsConfig(host: Tree, project: any) {
|
||||
}
|
||||
|
||||
function updateTsConfigs(host: Tree) {
|
||||
const angularJson = readJsonInTree(host, 'angular.json');
|
||||
Object.entries<any>(angularJson.projects).forEach(([key, project]) => {
|
||||
const workspaceJson = readJsonInTree(host, 'workspace.json');
|
||||
Object.entries<any>(workspaceJson.projects).forEach(([key, project]) => {
|
||||
if (
|
||||
project.architect.build &&
|
||||
project.architect.build.options.main.startsWith('apps')
|
||||
@ -562,7 +563,7 @@ function updateTsConfigs(host: Tree) {
|
||||
return host;
|
||||
}
|
||||
|
||||
const updateAngularJson = updateJsonInTree('angular.json', json => {
|
||||
const updateworkspaceJson = updateWorkspaceInTree(json => {
|
||||
json.newProjectRoot = '';
|
||||
json.cli = {
|
||||
...json.cli,
|
||||
@ -681,7 +682,7 @@ function addInstallTask(host: Tree, context: SchematicContext) {
|
||||
}
|
||||
|
||||
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(
|
||||
'Please install the latest version and run ng update @angular/cli first'
|
||||
);
|
||||
@ -701,7 +702,7 @@ export default function(): Rule {
|
||||
return chain([
|
||||
checkCli6Upgraded,
|
||||
updatePackageJson,
|
||||
updateAngularJson,
|
||||
updateworkspaceJson,
|
||||
moveE2eTests,
|
||||
updateTsConfigs,
|
||||
createAdditionalFiles,
|
||||
|
||||
@ -25,7 +25,7 @@ const addImplicitDependencies = updateJsonInTree<NxJson>('nx.json', nxJson => {
|
||||
return {
|
||||
...nxJson,
|
||||
implicitDependencies: {
|
||||
'angular.json': '*',
|
||||
'workspace.json': '*',
|
||||
'package.json': '*',
|
||||
'tsconfig.json': '*',
|
||||
'tslint.json': '*',
|
||||
|
||||
@ -15,7 +15,7 @@ describe('Update 7.2.0', () => {
|
||||
scripts: {}
|
||||
});
|
||||
createJson('tsconfig.json', {});
|
||||
createJson('angular.json', {
|
||||
createJson('workspace.json', {
|
||||
projects: {
|
||||
app1: {
|
||||
root: 'apps/app1',
|
||||
@ -321,7 +321,7 @@ describe('Update 7.2.0', () => {
|
||||
it('should fix cypress lint configs', async () => {
|
||||
initialTree = await schematicRunner
|
||||
.callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.projects['app2-e2e'].architect.lint.options.tsConfig =
|
||||
'e2e/tsconfig.e2e.json';
|
||||
return json;
|
||||
@ -333,8 +333,8 @@ describe('Update 7.2.0', () => {
|
||||
.runSchematicAsync('update-7.2.0', {}, initialTree)
|
||||
.toPromise();
|
||||
expect(
|
||||
readJsonInTree(result, 'angular.json').projects['app2-e2e'].architect.lint
|
||||
.options.tsConfig
|
||||
readJsonInTree(result, 'workspace.json').projects['app2-e2e'].architect
|
||||
.lint.options.tsConfig
|
||||
).toEqual('apps/app2-e2e/tsconfig.e2e.json');
|
||||
[
|
||||
'/apps/app1/tsconfig.app.json',
|
||||
@ -358,7 +358,7 @@ describe('Update 7.2.0', () => {
|
||||
it('should not fail for non-existing tsconfigs', async () => {
|
||||
initialTree = await schematicRunner
|
||||
.callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.projects['app2'].architect.lint.options.tsConfig =
|
||||
'apps/nonexistent/tsconfig.app.json';
|
||||
return json;
|
||||
|
||||
@ -10,7 +10,11 @@ import { normalize, join, Path, dirname } from '@angular-devkit/core';
|
||||
|
||||
import { relative } from 'path';
|
||||
|
||||
import { updateJsonInTree, readJsonInTree } from '@nrwl/workspace';
|
||||
import {
|
||||
updateJsonInTree,
|
||||
readJsonInTree,
|
||||
updateWorkspaceInTree
|
||||
} from '@nrwl/workspace';
|
||||
import { getWorkspacePath } from '@nrwl/workspace';
|
||||
import { offsetFromRoot, addUpdateTask } from '@nrwl/workspace';
|
||||
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 {
|
||||
const angularJson = readJsonInTree(host, 'angular.json');
|
||||
const workspaceJson = readJsonInTree(host, 'workspace.json');
|
||||
return chain(
|
||||
Object.entries<any>(angularJson.projects)
|
||||
Object.entries<any>(workspaceJson.projects)
|
||||
.filter(
|
||||
([key, project]) =>
|
||||
project.architect.e2e &&
|
||||
@ -175,12 +179,12 @@ function fixCypressConfigs(host: Tree, context: SchematicContext): Rule {
|
||||
}
|
||||
|
||||
function fixCypressConfig(project: any, projectKey: string): Rule {
|
||||
return updateJsonInTree('angular.json', angularJson => {
|
||||
angularJson.projects[projectKey].architect.lint.options.tsConfig = join(
|
||||
return updateWorkspaceInTree(workspaceJson => {
|
||||
workspaceJson.projects[projectKey].architect.lint.options.tsConfig = join(
|
||||
project.root,
|
||||
'tsconfig.e2e.json'
|
||||
);
|
||||
return angularJson;
|
||||
return workspaceJson;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -5,15 +5,16 @@ import * as path from 'path';
|
||||
|
||||
import { serializeJson } from '@nrwl/workspace';
|
||||
import { readJsonInTree } from '@nrwl/workspace';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
|
||||
describe('Update 7.5.0', () => {
|
||||
let initialTree: Tree;
|
||||
let schematicRunner: SchematicTestRunner;
|
||||
|
||||
beforeEach(() => {
|
||||
initialTree = Tree.empty();
|
||||
initialTree = createEmptyWorkspace(Tree.empty());
|
||||
|
||||
initialTree.create(
|
||||
initialTree.overwrite(
|
||||
'package.json',
|
||||
serializeJson({
|
||||
devDependencies: {
|
||||
|
||||
@ -9,6 +9,7 @@ import { join } from 'path';
|
||||
import { serializeJson } from '@nrwl/workspace';
|
||||
import { readJsonInTree, updateJsonInTree } from '@nrwl/workspace';
|
||||
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
|
||||
const effectContents = `
|
||||
import { Injectable } from '@angular/core';
|
||||
@ -77,9 +78,9 @@ describe('Update 7.6.0', () => {
|
||||
let schematicRunner: SchematicTestRunner;
|
||||
|
||||
beforeEach(() => {
|
||||
initialTree = new UnitTestTree(Tree.empty());
|
||||
initialTree = createEmptyWorkspace(Tree.empty());
|
||||
|
||||
initialTree.create(
|
||||
initialTree.overwrite(
|
||||
'package.json',
|
||||
serializeJson({
|
||||
dependencies: {
|
||||
@ -159,22 +160,22 @@ describe('Update 7.6.0', () => {
|
||||
.toPromise();
|
||||
|
||||
expect(
|
||||
readJsonInTree(result, 'angular.json').schematics[
|
||||
readJsonInTree(result, 'workspace.json').schematics[
|
||||
'@nrwl/schematics:library'
|
||||
].unitTestRunner
|
||||
).toEqual('karma');
|
||||
expect(
|
||||
readJsonInTree(result, 'angular.json').schematics[
|
||||
readJsonInTree(result, 'workspace.json').schematics[
|
||||
'@nrwl/schematics:application'
|
||||
].unitTestRunner
|
||||
).toEqual('karma');
|
||||
expect(
|
||||
readJsonInTree(result, 'angular.json').schematics[
|
||||
readJsonInTree(result, 'workspace.json').schematics[
|
||||
'@nrwl/schematics:application'
|
||||
].e2eTestRunner
|
||||
).toEqual('protractor');
|
||||
expect(
|
||||
readJsonInTree(result, 'angular.json').schematics[
|
||||
readJsonInTree(result, 'workspace.json').schematics[
|
||||
'@nrwl/schematics:node-application'
|
||||
].framework
|
||||
).toEqual('express');
|
||||
|
||||
@ -8,7 +8,8 @@ import {
|
||||
formatFiles,
|
||||
insert,
|
||||
readJsonInTree,
|
||||
updateJsonInTree
|
||||
updateJsonInTree,
|
||||
updateWorkspaceInTree
|
||||
} from '@nrwl/workspace';
|
||||
import {
|
||||
getSourceNodes,
|
||||
@ -371,7 +372,7 @@ const addDotEnv = updateJsonInTree('package.json', json => {
|
||||
return json;
|
||||
});
|
||||
|
||||
const setDefaults = updateJsonInTree('angular.json', json => {
|
||||
const setDefaults = updateWorkspaceInTree(json => {
|
||||
if (!json.schematics) {
|
||||
json.schematics = {};
|
||||
}
|
||||
|
||||
@ -7,13 +7,14 @@ import {
|
||||
import { join } from 'path';
|
||||
import { readJsonInTree } from '@nrwl/workspace';
|
||||
import { serializeJson } from '@nrwl/workspace';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
|
||||
describe('Update 7.7.0', () => {
|
||||
let initialTree: Tree;
|
||||
let schematicRunner: SchematicTestRunner;
|
||||
|
||||
beforeEach(() => {
|
||||
initialTree = new UnitTestTree(Tree.empty());
|
||||
initialTree = createEmptyWorkspace(Tree.empty());
|
||||
|
||||
schematicRunner = new SchematicTestRunner(
|
||||
'@nrwl/schematics',
|
||||
@ -28,7 +29,7 @@ describe('Update 7.7.0', () => {
|
||||
.toPromise();
|
||||
|
||||
expect(
|
||||
readJsonInTree(result, 'angular.json').schematics[
|
||||
readJsonInTree(result, 'workspace.json').schematics[
|
||||
'@nrwl/schematics:library'
|
||||
].framework
|
||||
).toEqual('angular');
|
||||
@ -37,7 +38,7 @@ describe('Update 7.7.0', () => {
|
||||
|
||||
describe('jest update', () => {
|
||||
beforeEach(() => {
|
||||
initialTree.create(
|
||||
initialTree.overwrite(
|
||||
'package.json',
|
||||
serializeJson({
|
||||
devDependencies: {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { chain, Rule, Tree } from '@angular-devkit/schematics';
|
||||
|
||||
import { updateJsonInTree, insert } from '@nrwl/workspace';
|
||||
import { formatFiles } from '@nrwl/workspace';
|
||||
import { formatFiles, updateWorkspaceInTree } from '@nrwl/workspace';
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import {
|
||||
@ -9,7 +9,7 @@ import {
|
||||
ReplaceChange
|
||||
} from '@nrwl/workspace/src/utils/ast-utils';
|
||||
|
||||
const setDefaults = updateJsonInTree('angular.json', json => {
|
||||
const setDefaults = updateWorkspaceInTree(json => {
|
||||
if (!json.schematics) {
|
||||
json.schematics = {};
|
||||
}
|
||||
|
||||
@ -3,14 +3,15 @@ import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||
import { serializeJson } from '@nrwl/workspace';
|
||||
|
||||
import * as path from 'path';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
|
||||
describe('Update 7.8.1', () => {
|
||||
let initialTree: Tree;
|
||||
let schematicRunner: SchematicTestRunner;
|
||||
|
||||
beforeEach(() => {
|
||||
initialTree = Tree.empty();
|
||||
initialTree.create(
|
||||
initialTree = createEmptyWorkspace(Tree.empty());
|
||||
initialTree.overwrite(
|
||||
'package.json',
|
||||
serializeJson({
|
||||
scripts: {}
|
||||
|
||||
@ -3,13 +3,14 @@ import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||
import { updateJsonInTree, readJsonInTree } from '@nrwl/workspace';
|
||||
|
||||
import * as path from 'path';
|
||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
|
||||
describe('Update 8-0-0', () => {
|
||||
let initialTree: Tree;
|
||||
let schematicRunner: SchematicTestRunner;
|
||||
|
||||
beforeEach(async () => {
|
||||
initialTree = Tree.empty();
|
||||
initialTree = createEmptyWorkspace(Tree.empty());
|
||||
schematicRunner = new SchematicTestRunner(
|
||||
'@nrwl/schematics',
|
||||
path.join(__dirname, '../migrations.json')
|
||||
@ -56,7 +57,7 @@ describe('Update 8-0-0', () => {
|
||||
.toPromise();
|
||||
initialTree = await schematicRunner
|
||||
.callRule(
|
||||
updateJsonInTree('angular.json', json => ({
|
||||
updateJsonInTree('workspace.json', json => ({
|
||||
projects: {
|
||||
'my-app': {
|
||||
architect: {
|
||||
@ -158,7 +159,7 @@ describe('Update 8-0-0', () => {
|
||||
const tree = await schematicRunner
|
||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||
.toPromise();
|
||||
const { projects } = readJsonInTree(tree, 'angular.json');
|
||||
const { projects } = readJsonInTree(tree, 'workspace.json');
|
||||
const { architect } = projects['my-app'];
|
||||
expect(architect.cypress.builder).toEqual('@nrwl/cypress:cypress');
|
||||
expect(architect.jest.builder).toEqual('@nrwl/jest:jest');
|
||||
@ -281,7 +282,7 @@ describe('Update 8-0-0', () => {
|
||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||
.toPromise();
|
||||
|
||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
||||
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||
.defaultCollection;
|
||||
expect(defaultCollection).toEqual('@nrwl/angular');
|
||||
});
|
||||
@ -304,7 +305,7 @@ describe('Update 8-0-0', () => {
|
||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||
.toPromise();
|
||||
|
||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
||||
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||
.defaultCollection;
|
||||
expect(defaultCollection).toEqual('@nrwl/react');
|
||||
});
|
||||
@ -326,7 +327,7 @@ describe('Update 8-0-0', () => {
|
||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||
.toPromise();
|
||||
|
||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
||||
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||
.defaultCollection;
|
||||
expect(defaultCollection).toEqual('@nrwl/nest');
|
||||
});
|
||||
@ -347,7 +348,7 @@ describe('Update 8-0-0', () => {
|
||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||
.toPromise();
|
||||
|
||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
||||
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||
.defaultCollection;
|
||||
expect(defaultCollection).toEqual('@nrwl/express');
|
||||
});
|
||||
@ -368,7 +369,7 @@ describe('Update 8-0-0', () => {
|
||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||
.toPromise();
|
||||
|
||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
||||
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||
.defaultCollection;
|
||||
expect(defaultCollection).toEqual('@nrwl/express');
|
||||
});
|
||||
@ -385,7 +386,7 @@ describe('Update 8-0-0', () => {
|
||||
.toPromise();
|
||||
initialTree = await schematicRunner
|
||||
.callRule(
|
||||
updateJsonInTree('angular.json', json => ({
|
||||
updateJsonInTree('workspace.json', json => ({
|
||||
...json,
|
||||
projects: {}
|
||||
})),
|
||||
@ -396,7 +397,7 @@ describe('Update 8-0-0', () => {
|
||||
.runSchematicAsync('update-8.0.0', {}, initialTree)
|
||||
.toPromise();
|
||||
|
||||
const defaultCollection = readJsonInTree(tree, 'angular.json').cli
|
||||
const defaultCollection = readJsonInTree(tree, 'workspace.json').cli
|
||||
.defaultCollection;
|
||||
expect(defaultCollection).toEqual('@nrwl/workspace');
|
||||
});
|
||||
|
||||
@ -11,7 +11,8 @@ import {
|
||||
insert,
|
||||
readJsonInTree,
|
||||
updateJsonInTree,
|
||||
addUpdateTask
|
||||
addUpdateTask,
|
||||
updateWorkspaceInTree
|
||||
} from '@nrwl/workspace';
|
||||
import {
|
||||
createSourceFile,
|
||||
@ -31,7 +32,7 @@ function addDependencies() {
|
||||
return (host: Tree, context: SchematicContext) => {
|
||||
const dependencies = readJsonInTree(host, 'package.json').dependencies;
|
||||
const builders = new Set<string>();
|
||||
const projects = readJsonInTree(host, 'angular.json').projects;
|
||||
const projects = readJsonInTree(host, 'workspace.json').projects;
|
||||
Object.values<any>(projects)
|
||||
.filter(
|
||||
project =>
|
||||
@ -110,7 +111,7 @@ const updateUpdateScript = updateJsonInTree('package.json', json => {
|
||||
return json;
|
||||
});
|
||||
|
||||
const updateBuilders = updateJsonInTree('angular.json', json => {
|
||||
const updateBuilders = updateWorkspaceInTree(json => {
|
||||
if (!json.projects) {
|
||||
return json;
|
||||
}
|
||||
@ -285,7 +286,7 @@ const updateDefaultCollection = (host: Tree, context: SchematicContext) => {
|
||||
'package.json'
|
||||
);
|
||||
|
||||
return updateJsonInTree('angular.json', json => {
|
||||
return updateWorkspaceInTree(json => {
|
||||
json.cli = json.cli || {};
|
||||
if (dependencies['@nrwl/angular']) {
|
||||
json.cli.defaultCollection = '@nrwl/angular';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { updateJsonFile, readCliConfigFile } from '@nrwl/workspace';
|
||||
import { updateJsonFile, readWorkspaceConfigPath } from '@nrwl/workspace';
|
||||
|
||||
type Migration = { description: string; run(): void };
|
||||
type MigrationName = { name: string; migration: Migration };
|
||||
@ -32,7 +32,7 @@ updateLatestMigration();
|
||||
console.log('All migrations run successfully');
|
||||
|
||||
function readLatestMigration(): string {
|
||||
const angularCli = readCliConfigFile();
|
||||
const angularCli = readWorkspaceConfigPath();
|
||||
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', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
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(angularJson.projects['my-app-e2e'].root).toEqual(
|
||||
expect(workspaceJson.projects['my-app'].root).toEqual('apps/my-app');
|
||||
expect(workspaceJson.projects['my-app-e2e'].root).toEqual(
|
||||
'apps/my-app-e2e'
|
||||
);
|
||||
expect(angularJson.defaultProject).toEqual('my-app');
|
||||
expect(workspaceJson.defaultProject).toEqual('my-app');
|
||||
});
|
||||
|
||||
it('should update nx.json', async () => {
|
||||
@ -78,18 +78,18 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('nested', () => {
|
||||
it('should update angular.json', async () => {
|
||||
it('should update workspace.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'app',
|
||||
{ name: 'myApp', directory: 'myDir' },
|
||||
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'
|
||||
);
|
||||
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'
|
||||
);
|
||||
});
|
||||
@ -217,8 +217,8 @@ describe('app', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
const architectConfig = angularJson.projects['my-app'].architect;
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||
expect(architectConfig.build.builder).toEqual('@nrwl/web:build');
|
||||
expect(architectConfig.build.options).toEqual({
|
||||
assets: ['apps/my-app/src/favicon.ico', 'apps/my-app/src/assets'],
|
||||
@ -262,8 +262,8 @@ describe('app', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
const architectConfig = angularJson.projects['my-app'].architect;
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
const architectConfig = workspaceJson.projects['my-app'].architect;
|
||||
expect(architectConfig.serve.builder).toEqual('@nrwl/web:dev-server');
|
||||
expect(architectConfig.serve.options).toEqual({
|
||||
buildTarget: 'my-app:build'
|
||||
@ -281,11 +281,12 @@ describe('app', () => {
|
||||
},
|
||||
appTree
|
||||
);
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app'].architect.lint).toEqual({
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
|
||||
expect(workspaceJson.projects['my-app'].architect.lint).toEqual({
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
options: {
|
||||
exclude: ['**/node_modules/**'],
|
||||
exclude: ['**/node_modules/**', '!apps/my-app/**'],
|
||||
tsConfig: [
|
||||
'apps/my-app/tsconfig.app.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/tsconfig.spec.json')).toBeFalsy();
|
||||
expect(tree.exists('apps/my-app/jest.config.js')).toBeFalsy();
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app'].architect.test).toBeUndefined();
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-app'].architect.test).toBeUndefined();
|
||||
expect(
|
||||
angularJson.projects['my-app'].architect.lint.options.tsConfig
|
||||
workspaceJson.projects['my-app'].architect.lint.options.tsConfig
|
||||
).toEqual(['apps/my-app/tsconfig.app.json']);
|
||||
});
|
||||
});
|
||||
@ -334,8 +335,8 @@ describe('app', () => {
|
||||
appTree
|
||||
);
|
||||
expect(tree.exists('apps/my-app-e2e')).toBeFalsy();
|
||||
const angularJson = readJsonInTree(tree, 'angular.json');
|
||||
expect(angularJson.projects['my-app-e2e']).toBeUndefined();
|
||||
const workspaceJson = readJsonInTree(tree, 'workspace.json');
|
||||
expect(workspaceJson.projects['my-app-e2e']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -21,7 +21,10 @@ import {
|
||||
names,
|
||||
offsetFromRoot,
|
||||
getNpmScope,
|
||||
formatFiles
|
||||
formatFiles,
|
||||
updateWorkspaceInTree,
|
||||
generateProjectLint,
|
||||
addGlobalLint
|
||||
} from '@nrwl/workspace';
|
||||
import ngAdd from '../ng-add/ng-add';
|
||||
|
||||
@ -58,7 +61,7 @@ function updateNxJson(options: NormalizedSchema): Rule {
|
||||
}
|
||||
|
||||
function addProject(options: NormalizedSchema): Rule {
|
||||
return updateJsonInTree('angular.json', json => {
|
||||
return updateWorkspaceInTree(json => {
|
||||
const architect: { [key: string]: any } = {};
|
||||
|
||||
architect.build = {
|
||||
@ -122,15 +125,11 @@ function addProject(options: NormalizedSchema): Rule {
|
||||
}
|
||||
};
|
||||
|
||||
architect.lint = {
|
||||
builder: '@angular-devkit/build-angular:tslint',
|
||||
options: {
|
||||
tsConfig: [
|
||||
join(normalize(options.appProjectRoot), 'tsconfig.app.json')
|
||||
],
|
||||
exclude: ['**/node_modules/**']
|
||||
}
|
||||
};
|
||||
architect.lint = generateProjectLint(
|
||||
normalize(options.appProjectRoot),
|
||||
join(normalize(options.appProjectRoot), 'tsconfig.app.json'),
|
||||
options.linter
|
||||
);
|
||||
|
||||
json.projects[options.projectName] = {
|
||||
root: options.appProjectRoot,
|
||||
@ -154,6 +153,7 @@ export default function(schema: Schema): Rule {
|
||||
ngAdd({
|
||||
skipFormat: true
|
||||
}),
|
||||
addGlobalLint(options.linter),
|
||||
createApplicationFiles(options),
|
||||
updateNxJson(options),
|
||||
addProject(options),
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
|
||||
export interface Schema {
|
||||
name: string;
|
||||
prefix?: string;
|
||||
@ -7,6 +5,7 @@ export interface Schema {
|
||||
skipFormat: boolean;
|
||||
directory?: string;
|
||||
tags?: string;
|
||||
unitTestRunner: UnitTestRunner;
|
||||
e2eTestRunner: E2eTestRunner;
|
||||
unitTestRunner: 'jest' | 'none';
|
||||
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": {
|
||||
"description": "Skip formatting files",
|
||||
"type": "boolean",
|
||||
|
||||
@ -23,13 +23,13 @@ describe('ng-add', () => {
|
||||
describe('defaultCollection', () => {
|
||||
it('should be set if none was set before', async () => {
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/web');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/web');
|
||||
});
|
||||
|
||||
it('should be set if @nrwl/workspace was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/workspace'
|
||||
};
|
||||
@ -39,13 +39,13 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/web');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/web');
|
||||
});
|
||||
|
||||
it('should not be set if something else was set before', async () => {
|
||||
tree = await callRule(
|
||||
updateJsonInTree('angular.json', json => {
|
||||
updateJsonInTree('workspace.json', json => {
|
||||
json.cli = {
|
||||
defaultCollection: '@nrwl/angular'
|
||||
};
|
||||
@ -55,8 +55,8 @@ describe('ng-add', () => {
|
||||
tree
|
||||
);
|
||||
const result = await runSchematic('ng-add', {}, tree);
|
||||
const angularJson = readJsonInTree(result, 'angular.json');
|
||||
expect(angularJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
const workspaceJson = readJsonInTree(result, 'workspace.json');
|
||||
expect(workspaceJson.cli.defaultCollection).toEqual('@nrwl/angular');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -26,12 +26,12 @@ export function _findDefaultServePath(
|
||||
/^(\w+:)?\/\//.test(baseHref || '') ||
|
||||
/^(\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;
|
||||
}
|
||||
|
||||
// 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
|
||||
const baseHrefParts = (baseHref || '').split('/').filter(part => part !== '');
|
||||
if (baseHref && !baseHref.endsWith('/')) {
|
||||
@ -42,7 +42,7 @@ export function _findDefaultServePath(
|
||||
|
||||
if (deployUrl && deployUrl[0] === '/') {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,13 @@
|
||||
"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": {
|
||||
"factory": "./src/schematics/library/library",
|
||||
"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