switch to prettier
This commit is contained in:
parent
bc548c596e
commit
a43fbaeb9a
@ -1,3 +0,0 @@
|
|||||||
Language: JavaScript
|
|
||||||
BasedOnStyle: Google
|
|
||||||
ColumnLimit: 120
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import {checkFilesExist, cleanup, copyMissingPackages, ngNewBazel, readFile, runCLI, runSchematic} from '../utils';
|
import { checkFilesExist, cleanup, copyMissingPackages, ngNewBazel, readFile, runCLI, runSchematic } from '../utils';
|
||||||
|
|
||||||
describe('application', () => {
|
describe('application', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
@ -9,8 +9,14 @@ describe('application', () => {
|
|||||||
runSchematic('@nrwl/bazel:app --name=myApp');
|
runSchematic('@nrwl/bazel:app --name=myApp');
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
`tsconfig.json`, `WORKSPACE`, `BUILD.bazel`, `apps/my-app/BUILD.bazel`, `apps/my-app/src/index.html`,
|
`tsconfig.json`,
|
||||||
`apps/my-app/src/app/app.module.ts`, `apps/my-app/src/app/app.component.ts`);
|
`WORKSPACE`,
|
||||||
|
`BUILD.bazel`,
|
||||||
|
`apps/my-app/BUILD.bazel`,
|
||||||
|
`apps/my-app/src/index.html`,
|
||||||
|
`apps/my-app/src/app/app.module.ts`,
|
||||||
|
`apps/my-app/src/app/app.component.ts`
|
||||||
|
);
|
||||||
|
|
||||||
expect(readFile('apps/my-app/src/app/app.module.ts')).toContain('bootstrap: [AppComponent]');
|
expect(readFile('apps/my-app/src/app/app.module.ts')).toContain('bootstrap: [AppComponent]');
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {checkFilesExist, cleanup, copyMissingPackages, ngNewBazel, readFile, runCLI, runSchematic} from '../utils';
|
import { checkFilesExist, cleanup, copyMissingPackages, ngNewBazel, readFile, runCLI, runSchematic } from '../utils';
|
||||||
|
|
||||||
describe('library', () => {
|
describe('library', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
@ -9,8 +9,13 @@ describe('library', () => {
|
|||||||
runSchematic('@nrwl/bazel:lib --name=myLib');
|
runSchematic('@nrwl/bazel:lib --name=myLib');
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
'tsconfig.json', 'WORKSPACE', 'BUILD.bazel', 'libs/my-lib/BUILD.bazel', 'libs/my-lib/index.ts',
|
'tsconfig.json',
|
||||||
'libs/my-lib/src/my-lib.ts');
|
'WORKSPACE',
|
||||||
|
'BUILD.bazel',
|
||||||
|
'libs/my-lib/BUILD.bazel',
|
||||||
|
'libs/my-lib/index.ts',
|
||||||
|
'libs/my-lib/src/my-lib.ts'
|
||||||
|
);
|
||||||
|
|
||||||
const cliConfig = JSON.parse(readFile('.angular-cli.json'));
|
const cliConfig = JSON.parse(readFile('.angular-cli.json'));
|
||||||
expect(cliConfig.apps[0].name).toEqual('myLib');
|
expect(cliConfig.apps[0].name).toEqual('myLib');
|
||||||
|
|||||||
@ -1,4 +1,15 @@
|
|||||||
import {checkFilesExist, cleanup, copyMissingPackages, ngNew, ngNewBazel, readFile, runCLI, runCommand, runSchematic, updateFile} from '../utils';
|
import {
|
||||||
|
checkFilesExist,
|
||||||
|
cleanup,
|
||||||
|
copyMissingPackages,
|
||||||
|
ngNew,
|
||||||
|
ngNewBazel,
|
||||||
|
readFile,
|
||||||
|
runCLI,
|
||||||
|
runCommand,
|
||||||
|
runSchematic,
|
||||||
|
updateFile
|
||||||
|
} from '../utils';
|
||||||
|
|
||||||
describe('angular library', () => {
|
describe('angular library', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
@ -9,8 +20,13 @@ describe('angular library', () => {
|
|||||||
runSchematic('@nrwl/bazel:nglib --name=myLib');
|
runSchematic('@nrwl/bazel:nglib --name=myLib');
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
'tsconfig.json', 'WORKSPACE', 'BUILD.bazel', 'libs/my-lib/BUILD.bazel', 'libs/my-lib/index.ts',
|
'tsconfig.json',
|
||||||
'libs/my-lib/src/my-lib.module.ts');
|
'WORKSPACE',
|
||||||
|
'BUILD.bazel',
|
||||||
|
'libs/my-lib/BUILD.bazel',
|
||||||
|
'libs/my-lib/index.ts',
|
||||||
|
'libs/my-lib/src/my-lib.module.ts'
|
||||||
|
);
|
||||||
|
|
||||||
const cliConfig = JSON.parse(readFile('.angular-cli.json'));
|
const cliConfig = JSON.parse(readFile('.angular-cli.json'));
|
||||||
expect(cliConfig.apps[0].name).toEqual('myLib');
|
expect(cliConfig.apps[0].name).toEqual('myLib');
|
||||||
|
|||||||
@ -1,4 +1,15 @@
|
|||||||
import {checkFilesExist, cleanup, copyMissingPackages, ngNew, ngNewBazel, readFile, runCLI, runCommand, runSchematic, updateFile} from '../utils';
|
import {
|
||||||
|
checkFilesExist,
|
||||||
|
cleanup,
|
||||||
|
copyMissingPackages,
|
||||||
|
ngNew,
|
||||||
|
ngNewBazel,
|
||||||
|
readFile,
|
||||||
|
runCLI,
|
||||||
|
runCommand,
|
||||||
|
runSchematic,
|
||||||
|
updateFile
|
||||||
|
} from '../utils';
|
||||||
|
|
||||||
describe('workspace', () => {
|
describe('workspace', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
|
|||||||
@ -1,4 +1,14 @@
|
|||||||
import {checkFilesExist, cleanup, copyMissingPackages, newApp, newLib, ngNew, readFile, runCLI, updateFile} from '../utils';
|
import {
|
||||||
|
checkFilesExist,
|
||||||
|
cleanup,
|
||||||
|
copyMissingPackages,
|
||||||
|
newApp,
|
||||||
|
newLib,
|
||||||
|
ngNew,
|
||||||
|
readFile,
|
||||||
|
runCLI,
|
||||||
|
updateFile
|
||||||
|
} from '../utils';
|
||||||
|
|
||||||
describe('Nrwl Workspace', () => {
|
describe('Nrwl Workspace', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
@ -16,6 +26,7 @@ describe('Nrwl Workspace', () => {
|
|||||||
expect(packageJson.dependencies['@ngrx/effects']).toBeDefined();
|
expect(packageJson.dependencies['@ngrx/effects']).toBeDefined();
|
||||||
expect(packageJson.dependencies['@ngrx/router-store']).toBeDefined();
|
expect(packageJson.dependencies['@ngrx/router-store']).toBeDefined();
|
||||||
expect(packageJson.dependencies['@ngrx/store-devtools']).toBeDefined();
|
expect(packageJson.dependencies['@ngrx/store-devtools']).toBeDefined();
|
||||||
|
|
||||||
checkFilesExist('test.js', 'tsconfig.app.json', 'tsconfig.spec.json', 'tsconfig.e2e.json', 'apps', 'libs');
|
checkFilesExist('test.js', 'tsconfig.app.json', 'tsconfig.spec.json', 'tsconfig.e2e.json', 'apps', 'libs');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -28,18 +39,25 @@ describe('Nrwl Workspace', () => {
|
|||||||
expect(angularCliJson.apps[0].name).toEqual('myapp');
|
expect(angularCliJson.apps[0].name).toEqual('myapp');
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
'apps/myapp/src/main.ts', 'apps/myapp/src/app/app.module.ts', 'apps/myapp/src/app/app.component.ts',
|
'apps/myapp/src/main.ts',
|
||||||
'apps/myapp/e2e/app.po.ts');
|
'apps/myapp/src/app/app.module.ts',
|
||||||
|
'apps/myapp/src/app/app.component.ts',
|
||||||
|
'apps/myapp/e2e/app.po.ts'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should build app', () => {
|
it(
|
||||||
ngNew('--collection=@nrwl/schematics');
|
'should build app',
|
||||||
copyMissingPackages();
|
() => {
|
||||||
newApp('myapp');
|
ngNew('--collection=@nrwl/schematics');
|
||||||
runCLI('build --aot');
|
copyMissingPackages();
|
||||||
checkFilesExist('dist/apps/myapp/main.bundle.js');
|
newApp('myapp');
|
||||||
expect(runCLI('test --single-run')).toContain('Executed 1 of 1 SUCCESS');
|
runCLI('build --aot');
|
||||||
}, 100000);
|
checkFilesExist('dist/apps/myapp/main.bundle.js');
|
||||||
|
expect(runCLI('test --single-run')).toContain('Executed 1 of 1 SUCCESS');
|
||||||
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('lib', () => {
|
describe('lib', () => {
|
||||||
@ -53,14 +71,18 @@ describe('Nrwl Workspace', () => {
|
|||||||
checkFilesExist('libs/mylib/src/mylib.ts', 'libs/mylib/src/mylib.spec.ts', 'libs/mylib/index.ts');
|
checkFilesExist('libs/mylib/src/mylib.ts', 'libs/mylib/src/mylib.spec.ts', 'libs/mylib/index.ts');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should test a lib', () => {
|
it(
|
||||||
ngNew('--collection=@nrwl/schematics');
|
'should test a lib',
|
||||||
copyMissingPackages();
|
() => {
|
||||||
newApp('myapp');
|
ngNew('--collection=@nrwl/schematics');
|
||||||
newLib('generate lib mylib');
|
copyMissingPackages();
|
||||||
|
newApp('myapp');
|
||||||
|
newLib('generate lib mylib');
|
||||||
|
|
||||||
expect(runCLI('test --single-run')).toContain('Executed 2 of 2 SUCCESS');
|
expect(runCLI('test --single-run')).toContain('Executed 2 of 2 SUCCESS');
|
||||||
}, 100000);
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('nglib', () => {
|
describe('nglib', () => {
|
||||||
@ -71,22 +93,30 @@ describe('Nrwl Workspace', () => {
|
|||||||
checkFilesExist('libs/mylib/src/mylib.module.ts', 'libs/mylib/src/mylib.module.spec.ts', 'libs/mylib/index.ts');
|
checkFilesExist('libs/mylib/src/mylib.module.ts', 'libs/mylib/src/mylib.module.spec.ts', 'libs/mylib/index.ts');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should test an ng lib', () => {
|
it(
|
||||||
ngNew('--collection=@nrwl/schematics');
|
'should test an ng lib',
|
||||||
copyMissingPackages();
|
() => {
|
||||||
newApp('myapp');
|
ngNew('--collection=@nrwl/schematics');
|
||||||
newLib('mylib --ngmodule');
|
copyMissingPackages();
|
||||||
|
newApp('myapp');
|
||||||
|
newLib('mylib --ngmodule');
|
||||||
|
|
||||||
expect(runCLI('test --single-run')).toContain('Executed 2 of 2 SUCCESS');
|
expect(runCLI('test --single-run')).toContain('Executed 2 of 2 SUCCESS');
|
||||||
}, 100000);
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
|
|
||||||
it('should resolve dependencies on the lib', () => {
|
it(
|
||||||
ngNew('--collection=@nrwl/schematics --npmScope=nrwl');
|
'should resolve dependencies on the lib',
|
||||||
copyMissingPackages();
|
() => {
|
||||||
newApp('myapp');
|
ngNew('--collection=@nrwl/schematics --npmScope=nrwl');
|
||||||
newLib('mylib --ngmodule');
|
copyMissingPackages();
|
||||||
|
newApp('myapp');
|
||||||
|
newLib('mylib --ngmodule');
|
||||||
|
|
||||||
updateFile('apps/myapp/src/app/app.module.ts', `
|
updateFile(
|
||||||
|
'apps/myapp/src/app/app.module.ts',
|
||||||
|
`
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { MylibModule } from '@nrwl/mylib';
|
import { MylibModule } from '@nrwl/mylib';
|
||||||
@ -98,9 +128,12 @@ describe('Nrwl Workspace', () => {
|
|||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
`);
|
`
|
||||||
|
);
|
||||||
|
|
||||||
runCLI('build --aot');
|
runCLI('build --aot');
|
||||||
}, 100000);
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import {checkFilesExist, cleanup, copyMissingPackages, ngNew, readFile, runCLI} from '../utils';
|
import { checkFilesExist, cleanup, copyMissingPackages, ngNew, readFile, runCLI } from '../utils';
|
||||||
|
|
||||||
describe('ngrx', () => {
|
describe('ngrx', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
@ -9,35 +9,48 @@ describe('ngrx', () => {
|
|||||||
runCLI('generate ngrx app --module=src/app/app.module.ts --root --collection=@nrwl/schematics');
|
runCLI('generate ngrx app --module=src/app/app.module.ts --root --collection=@nrwl/schematics');
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
`src/app/+state/app.actions.ts`, `src/app/+state/app.effects.ts`, `src/app/+state/app.effects.spec.ts`,
|
`src/app/+state/app.actions.ts`,
|
||||||
`src/app/+state/app.init.ts`, `src/app/+state/app.interfaces.ts`, `src/app/+state/app.reducer.ts`,
|
`src/app/+state/app.effects.ts`,
|
||||||
`src/app/+state/app.reducer.spec.ts`);
|
`src/app/+state/app.effects.spec.ts`,
|
||||||
|
`src/app/+state/app.init.ts`,
|
||||||
|
`src/app/+state/app.interfaces.ts`,
|
||||||
|
`src/app/+state/app.reducer.ts`,
|
||||||
|
`src/app/+state/app.reducer.spec.ts`
|
||||||
|
);
|
||||||
|
|
||||||
const contents = readFile('src/app/app.module.ts');
|
const contents = readFile('src/app/app.module.ts');
|
||||||
expect(contents).toContain('StoreModule.forRoot');
|
expect(contents).toContain('StoreModule.forRoot');
|
||||||
expect(contents).toContain('EffectsModule.forRoot');
|
expect(contents).toContain('EffectsModule.forRoot');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should build', () => {
|
it(
|
||||||
ngNew();
|
'should build',
|
||||||
copyMissingPackages();
|
() => {
|
||||||
runCLI('generate ngrx app --module=src/app/app.module.ts --root --collection=@nrwl/schematics');
|
ngNew();
|
||||||
|
copyMissingPackages();
|
||||||
|
runCLI('generate ngrx app --module=src/app/app.module.ts --root --collection=@nrwl/schematics');
|
||||||
|
|
||||||
runCLI('build');
|
runCLI('build');
|
||||||
runCLI('test --single-run');
|
runCLI('test --single-run');
|
||||||
}, 100000);
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
|
|
||||||
it('should add empty root configuration', () => {
|
it(
|
||||||
ngNew();
|
'should add empty root configuration',
|
||||||
copyMissingPackages();
|
() => {
|
||||||
runCLI('generate ngrx app --module=src/app/app.module.ts --onlyEmptyRoot --collection=@nrwl/schematics');
|
ngNew();
|
||||||
|
copyMissingPackages();
|
||||||
|
runCLI('generate ngrx app --module=src/app/app.module.ts --onlyEmptyRoot --collection=@nrwl/schematics');
|
||||||
|
|
||||||
const contents = readFile('src/app/app.module.ts');
|
const contents = readFile('src/app/app.module.ts');
|
||||||
expect(contents).toContain('StoreModule.forRoot');
|
expect(contents).toContain('StoreModule.forRoot');
|
||||||
expect(contents).toContain('EffectsModule.forRoot');
|
expect(contents).toContain('EffectsModule.forRoot');
|
||||||
|
|
||||||
runCLI('build');
|
runCLI('build');
|
||||||
}, 100000);
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('feature', () => {
|
describe('feature', () => {
|
||||||
@ -46,9 +59,14 @@ describe('ngrx', () => {
|
|||||||
runCLI('generate ngrx app --module=src/app/app.module.ts --collection=@nrwl/schematics');
|
runCLI('generate ngrx app --module=src/app/app.module.ts --collection=@nrwl/schematics');
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
`src/app/+state/app.actions.ts`, `src/app/+state/app.effects.ts`, `src/app/+state/app.effects.spec.ts`,
|
`src/app/+state/app.actions.ts`,
|
||||||
`src/app/+state/app.init.ts`, `src/app/+state/app.interfaces.ts`, `src/app/+state/app.reducer.ts`,
|
`src/app/+state/app.effects.ts`,
|
||||||
`src/app/+state/app.reducer.spec.ts`);
|
`src/app/+state/app.effects.spec.ts`,
|
||||||
|
`src/app/+state/app.init.ts`,
|
||||||
|
`src/app/+state/app.interfaces.ts`,
|
||||||
|
`src/app/+state/app.reducer.ts`,
|
||||||
|
`src/app/+state/app.reducer.spec.ts`
|
||||||
|
);
|
||||||
|
|
||||||
const contents = readFile('src/app/app.module.ts');
|
const contents = readFile('src/app/app.module.ts');
|
||||||
expect(contents).toContain('StoreModule.forFeature');
|
expect(contents).toContain('StoreModule.forFeature');
|
||||||
@ -61,9 +79,14 @@ describe('ngrx', () => {
|
|||||||
runCLI('generate ngrx app --module=src/app/app.module.ts --onlyAddFiles --collection=@nrwl/schematics');
|
runCLI('generate ngrx app --module=src/app/app.module.ts --onlyAddFiles --collection=@nrwl/schematics');
|
||||||
|
|
||||||
checkFilesExist(
|
checkFilesExist(
|
||||||
`src/app/+state/app.actions.ts`, `src/app/+state/app.effects.ts`, `src/app/+state/app.effects.spec.ts`,
|
`src/app/+state/app.actions.ts`,
|
||||||
`src/app/+state/app.init.ts`, `src/app/+state/app.interfaces.ts`, `src/app/+state/app.reducer.ts`,
|
`src/app/+state/app.effects.ts`,
|
||||||
`src/app/+state/app.reducer.spec.ts`);
|
`src/app/+state/app.effects.spec.ts`,
|
||||||
|
`src/app/+state/app.init.ts`,
|
||||||
|
`src/app/+state/app.interfaces.ts`,
|
||||||
|
`src/app/+state/app.reducer.ts`,
|
||||||
|
`src/app/+state/app.reducer.spec.ts`
|
||||||
|
);
|
||||||
|
|
||||||
const contents = readFile('src/app/app.module.ts');
|
const contents = readFile('src/app/app.module.ts');
|
||||||
expect(contents).not.toContain('StoreModule');
|
expect(contents).not.toContain('StoreModule');
|
||||||
|
|||||||
@ -1,26 +1,43 @@
|
|||||||
import {checkFilesExist, cleanup, copyMissingPackages, newApp, newLib, ngNew, readFile, runCLI, updateFile} from '../utils';
|
import {
|
||||||
|
checkFilesExist,
|
||||||
|
cleanup,
|
||||||
|
copyMissingPackages,
|
||||||
|
newApp,
|
||||||
|
newLib,
|
||||||
|
ngNew,
|
||||||
|
readFile,
|
||||||
|
runCLI,
|
||||||
|
updateFile
|
||||||
|
} from '../utils';
|
||||||
|
|
||||||
describe('Lint', () => {
|
describe('Lint', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
|
|
||||||
it('should ensure module boundaries', () => {
|
it(
|
||||||
ngNew('--collection=@nrwl/schematics');
|
'should ensure module boundaries',
|
||||||
copyMissingPackages();
|
() => {
|
||||||
newApp('myapp');
|
ngNew('--collection=@nrwl/schematics');
|
||||||
newLib('mylib');
|
copyMissingPackages();
|
||||||
newLib('lazylib');
|
newApp('myapp');
|
||||||
|
newLib('mylib');
|
||||||
|
newLib('lazylib');
|
||||||
|
|
||||||
const tslint = JSON.parse(readFile('tslint.json'));
|
const tslint = JSON.parse(readFile('tslint.json'));
|
||||||
tslint.rules['nx-enforce-module-boundaries'][1].lazyLoad.push('lazylib');
|
tslint.rules['nx-enforce-module-boundaries'][1].lazyLoad.push('lazylib');
|
||||||
updateFile('tslint.json', JSON.stringify(tslint, null, 2));
|
updateFile('tslint.json', JSON.stringify(tslint, null, 2));
|
||||||
|
|
||||||
updateFile('apps/myapp/src/main.ts', `
|
updateFile(
|
||||||
|
'apps/myapp/src/main.ts',
|
||||||
|
`
|
||||||
import '../../../libs/mylib';
|
import '../../../libs/mylib';
|
||||||
import '@proj/lazylib';
|
import '@proj/lazylib';
|
||||||
`);
|
`
|
||||||
|
);
|
||||||
|
|
||||||
const out = runCLI('lint --type-check', {silenceError: true});
|
const out = runCLI('lint --type-check', { silenceError: true });
|
||||||
expect(out).toContain('relative imports of libraries are forbidden');
|
expect(out).toContain('relative imports of libraries are forbidden');
|
||||||
expect(out).toContain('import of lazy-loaded libraries are forbidden');
|
expect(out).toContain('import of lazy-loaded libraries are forbidden');
|
||||||
}, 100000);
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,39 +1,51 @@
|
|||||||
import {cleanup, copyMissingPackages, newApp, ngNew, readFile, runCLI, runSchematic, updateFile} from '../utils';
|
import { cleanup, copyMissingPackages, newApp, ngNew, readFile, runCLI, runSchematic, updateFile } from '../utils';
|
||||||
|
|
||||||
describe('Upgrade', () => {
|
describe('Upgrade', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
|
|
||||||
it('should generate an upgrade shell', () => {
|
it(
|
||||||
ngNew('--collection=@nrwl/schematics');
|
'should generate an upgrade shell',
|
||||||
newApp('myapp');
|
() => {
|
||||||
|
ngNew('--collection=@nrwl/schematics');
|
||||||
|
newApp('myapp');
|
||||||
|
|
||||||
copyMissingPackages();
|
copyMissingPackages();
|
||||||
updateFile('apps/myapp/src/legacy.js', `
|
updateFile(
|
||||||
|
'apps/myapp/src/legacy.js',
|
||||||
|
`
|
||||||
const angular = window.angular.module('legacy', []);
|
const angular = window.angular.module('legacy', []);
|
||||||
angular.component('rootLegacyCmp', {
|
angular.component('rootLegacyCmp', {
|
||||||
template: 'Expected Value'
|
template: 'Expected Value'
|
||||||
});
|
});
|
||||||
`);
|
`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile('apps/myapp/src/app/app.component.html', `
|
updateFile(
|
||||||
|
'apps/myapp/src/app/app.component.html',
|
||||||
|
`
|
||||||
EXPECTED [<rootLegacyCmp></rootLegacyCmp>]
|
EXPECTED [<rootLegacyCmp></rootLegacyCmp>]
|
||||||
`);
|
`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile('apps/myapp/src/app/app.component.spec.ts', ``);
|
updateFile('apps/myapp/src/app/app.component.spec.ts', ``);
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
'generate upgrade-shell legacy --module=apps/myapp/src/app/app.module.ts --angularJsImport=../legacy ' +
|
'generate upgrade-shell legacy --module=apps/myapp/src/app/app.module.ts --angularJsImport=../legacy ' +
|
||||||
'--angularJsCmpSelector=rootLegacyCmp');
|
'--angularJsCmpSelector=rootLegacyCmp'
|
||||||
|
);
|
||||||
|
|
||||||
runCLI('build');
|
runCLI('build');
|
||||||
runCLI('test --single-run');
|
runCLI('test --single-run');
|
||||||
}, 100000);
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
|
|
||||||
it('should update package.json', () => {
|
it('should update package.json', () => {
|
||||||
ngNew('--skip-install');
|
ngNew('--skip-install');
|
||||||
runCLI(
|
runCLI(
|
||||||
'generate upgrade-shell legacy --module=src/app/app.module.ts --angularJsImport=../legacy ' +
|
'generate upgrade-shell legacy --module=src/app/app.module.ts --angularJsImport=../legacy ' +
|
||||||
'--angularJsCmpSelector=rootLegacyCmp --collection=@nrwl/schematics');
|
'--angularJsCmpSelector=rootLegacyCmp --collection=@nrwl/schematics'
|
||||||
|
);
|
||||||
|
|
||||||
const contents = JSON.parse(readFile('package.json'));
|
const contents = JSON.parse(readFile('package.json'));
|
||||||
expect(contents.dependencies['@angular/upgrade']).toBeDefined();
|
expect(contents.dependencies['@angular/upgrade']).toBeDefined();
|
||||||
@ -43,8 +55,9 @@ describe('Upgrade', () => {
|
|||||||
it('should not update package.json when --skipPackageJson', () => {
|
it('should not update package.json when --skipPackageJson', () => {
|
||||||
ngNew('--skipInstall');
|
ngNew('--skipInstall');
|
||||||
runCLI(
|
runCLI(
|
||||||
'generate upgrade-shell legacy --module=src/app/app.module.ts --angularJsImport=../legacy ' +
|
'generate upgrade-shell legacy --module=src/app/app.module.ts --angularJsImport=../legacy ' +
|
||||||
'--angularJsCmpSelector=rootLegacyCmp --skipPackageJson --collection=@nrwl/schematics');
|
'--angularJsCmpSelector=rootLegacyCmp --skipPackageJson --collection=@nrwl/schematics'
|
||||||
|
);
|
||||||
|
|
||||||
const contents = JSON.parse(readFile('package.json'));
|
const contents = JSON.parse(readFile('package.json'));
|
||||||
expect(contents.dependencies['@angular/upgrade']).not.toBeDefined();
|
expect(contents.dependencies['@angular/upgrade']).not.toBeDefined();
|
||||||
|
|||||||
@ -1,4 +1,13 @@
|
|||||||
import {checkFilesExist, cleanup, copyMissingPackages, ngNew, readFile, runCLI, runSchematic, updateFile} from '../utils';
|
import {
|
||||||
|
checkFilesExist,
|
||||||
|
cleanup,
|
||||||
|
copyMissingPackages,
|
||||||
|
ngNew,
|
||||||
|
readFile,
|
||||||
|
runCLI,
|
||||||
|
runSchematic,
|
||||||
|
updateFile
|
||||||
|
} from '../utils';
|
||||||
|
|
||||||
describe('Nrwl Convert to Nx Workspace', () => {
|
describe('Nrwl Convert to Nx Workspace', () => {
|
||||||
beforeEach(cleanup);
|
beforeEach(cleanup);
|
||||||
@ -20,7 +29,7 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
|
|
||||||
// update tsconfig.json
|
// update tsconfig.json
|
||||||
const tsconfigJson = JSON.parse(readFile('tsconfig.json'));
|
const tsconfigJson = JSON.parse(readFile('tsconfig.json'));
|
||||||
tsconfigJson.compilerOptions.paths = {'a': ['b']};
|
tsconfigJson.compilerOptions.paths = { a: ['b'] };
|
||||||
updateFile('tsconfig.json', JSON.stringify(tsconfigJson, null, 2));
|
updateFile('tsconfig.json', JSON.stringify(tsconfigJson, null, 2));
|
||||||
|
|
||||||
// update angular-cli.json
|
// update angular-cli.json
|
||||||
@ -56,8 +65,10 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
|
|
||||||
// check if tsconfig.json get merged
|
// check if tsconfig.json get merged
|
||||||
const updatedTsConfig = JSON.parse(readFile('tsconfig.json'));
|
const updatedTsConfig = JSON.parse(readFile('tsconfig.json'));
|
||||||
expect(updatedTsConfig.compilerOptions.paths).toEqual({'a': ['b'], '@proj/*': ['libs/*']});
|
expect(updatedTsConfig.compilerOptions.paths).toEqual({
|
||||||
|
a: ['b'],
|
||||||
|
'@proj/*': ['libs/*']
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate a workspace and not change dependencies or devDependencies if they already exist', () => {
|
it('should generate a workspace and not change dependencies or devDependencies if they already exist', () => {
|
||||||
@ -87,14 +98,18 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
expect(packageJson.dependencies['@ngrx/store-devtools']).toEqual(ngrxVersion);
|
expect(packageJson.dependencies['@ngrx/store-devtools']).toEqual(ngrxVersion);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should build and test and support the existing AngularCLI generators', () => {
|
it(
|
||||||
ngNew();
|
'should build and test and support the existing AngularCLI generators',
|
||||||
copyMissingPackages();
|
() => {
|
||||||
|
ngNew();
|
||||||
|
copyMissingPackages();
|
||||||
|
|
||||||
runCLI('generate workspace proj --collection=@nrwl/schematics');
|
runCLI('generate workspace proj --collection=@nrwl/schematics');
|
||||||
runCLI('generate lib mylib --ngmodule');
|
runCLI('generate lib mylib --ngmodule');
|
||||||
|
|
||||||
updateFile('apps/proj/src/app/app.module.ts', `
|
updateFile(
|
||||||
|
'apps/proj/src/app/app.module.ts',
|
||||||
|
`
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { MylibModule } from '@proj/mylib';
|
import { MylibModule } from '@proj/mylib';
|
||||||
@ -106,20 +121,23 @@ describe('Nrwl Convert to Nx Workspace', () => {
|
|||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
`);
|
`
|
||||||
|
);
|
||||||
|
|
||||||
expect(runCLI('build --aot')).toContain('{main} main.bundle.js');
|
expect(runCLI('build --aot')).toContain('{main} main.bundle.js');
|
||||||
expect(runCLI('test --single-run')).toContain('Executed 4 of 4 SUCCESS');
|
expect(runCLI('test --single-run')).toContain('Executed 4 of 4 SUCCESS');
|
||||||
expect(runCLI('e2e')).toContain('Executed 1 of 1 spec SUCCESS');
|
expect(runCLI('e2e')).toContain('Executed 1 of 1 spec SUCCESS');
|
||||||
const generatorHelpText = runCLI('g -h');
|
const generatorHelpText = runCLI('g -h');
|
||||||
expect(generatorHelpText).toContain('class');
|
expect(generatorHelpText).toContain('class');
|
||||||
expect(generatorHelpText).toContain('component');
|
expect(generatorHelpText).toContain('component');
|
||||||
expect(generatorHelpText).toContain('directive');
|
expect(generatorHelpText).toContain('directive');
|
||||||
expect(generatorHelpText).toContain('enum');
|
expect(generatorHelpText).toContain('enum');
|
||||||
expect(generatorHelpText).toContain('guard');
|
expect(generatorHelpText).toContain('guard');
|
||||||
expect(generatorHelpText).toContain('interface');
|
expect(generatorHelpText).toContain('interface');
|
||||||
expect(generatorHelpText).toContain('module');
|
expect(generatorHelpText).toContain('module');
|
||||||
expect(generatorHelpText).toContain('pipe');
|
expect(generatorHelpText).toContain('pipe');
|
||||||
expect(generatorHelpText).toContain('service');
|
expect(generatorHelpText).toContain('service');
|
||||||
}, 100000);
|
},
|
||||||
|
100000
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
35
e2e/utils.ts
35
e2e/utils.ts
@ -1,11 +1,13 @@
|
|||||||
import {execSync} from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import {linkSync, mkdirSync, readFileSync, statSync, symlinkSync, writeFileSync} from 'fs';
|
import { linkSync, mkdirSync, readFileSync, statSync, symlinkSync, writeFileSync } from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
const projectName: string = 'proj';
|
const projectName: string = 'proj';
|
||||||
|
|
||||||
export function ngNew(command?: string): string {
|
export function ngNew(command?: string): string {
|
||||||
return execSync(`../node_modules/.bin/ng new proj ${command}`, {cwd: `./tmp`}).toString();
|
return execSync(`../node_modules/.bin/ng new proj ${command}`, {
|
||||||
|
cwd: `./tmp`
|
||||||
|
}).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ngNewBazel(command?: string): string {
|
export function ngNewBazel(command?: string): string {
|
||||||
@ -16,13 +18,18 @@ export function ngNewBazel(command?: string): string {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runCLI(command?: string, opts = {
|
export function runCLI(
|
||||||
silenceError: false
|
command?: string,
|
||||||
}): string {
|
opts = {
|
||||||
|
silenceError: false
|
||||||
|
}
|
||||||
|
): string {
|
||||||
try {
|
try {
|
||||||
return execSync(`../../node_modules/.bin/ng ${command}`, {cwd: `./tmp/${projectName}`})
|
return execSync(`../../node_modules/.bin/ng ${command}`, {
|
||||||
.toString()
|
cwd: `./tmp/${projectName}`
|
||||||
.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
|
})
|
||||||
|
.toString()
|
||||||
|
.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (opts.silenceError) {
|
if (opts.silenceError) {
|
||||||
return e.stdout.toString();
|
return e.stdout.toString();
|
||||||
@ -35,24 +42,26 @@ export function runCLI(command?: string, opts = {
|
|||||||
|
|
||||||
// switch to ng generate, once CLI is fixed
|
// switch to ng generate, once CLI is fixed
|
||||||
export function newApp(name: string): string {
|
export function newApp(name: string): string {
|
||||||
return runCLI(`generate app ${name}`)
|
return runCLI(`generate app ${name}`);
|
||||||
// return execSync(`../../node_modules/.bin/schematics @nrwl/schematics:app --name=${name}
|
// return execSync(`../../node_modules/.bin/schematics @nrwl/schematics:app --name=${name}
|
||||||
// --collection=@nrwl/schematics`, { cwd: `./tmp/${projectName}` }).toString();
|
// --collection=@nrwl/schematics`, { cwd: `./tmp/${projectName}` }).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch to ng generate, once CLI is fixed
|
// switch to ng generate, once CLI is fixed
|
||||||
export function newLib(name: string): string {
|
export function newLib(name: string): string {
|
||||||
return runCLI(`generate lib ${name}`)
|
return runCLI(`generate lib ${name}`);
|
||||||
// return execSync(`../../node_modules/.bin/schematics @nrwl/schematics:lib --name=${name}
|
// return execSync(`../../node_modules/.bin/schematics @nrwl/schematics:lib --name=${name}
|
||||||
// --collection=@nrwl/schematics`, { cwd: `./tmp/${projectName}` }).toString();
|
// --collection=@nrwl/schematics`, { cwd: `./tmp/${projectName}` }).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runSchematic(command: string): string {
|
export function runSchematic(command: string): string {
|
||||||
return execSync(`../../node_modules/.bin/schematics ${command}`, {cwd: `./tmp/${projectName}`}).toString();
|
return execSync(`../../node_modules/.bin/schematics ${command}`, {
|
||||||
|
cwd: `./tmp/${projectName}`
|
||||||
|
}).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runCommand(command: string): string {
|
export function runCommand(command: string): string {
|
||||||
return execSync(command, {cwd: `./tmp/${projectName}`}).toString();
|
return execSync(command, { cwd: `./tmp/${projectName}` }).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateFile(f: string, content: string): void {
|
export function updateFile(f: string, content: string): void {
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
"@types/jasmine": "2.5.53",
|
"@types/jasmine": "2.5.53",
|
||||||
"@types/node": "8.0.7",
|
"@types/node": "8.0.7",
|
||||||
"angular": "1.6.6",
|
"angular": "1.6.6",
|
||||||
"clang-format": "1.0.55",
|
"prettier": "1.7.4",
|
||||||
"jasmine-core": "~2.6.2",
|
"jasmine-core": "~2.6.2",
|
||||||
"jest": "20.0.4",
|
"jest": "20.0.4",
|
||||||
"karma": "~1.7.0",
|
"karma": "~1.7.0",
|
||||||
|
|||||||
@ -1,9 +1,19 @@
|
|||||||
import {apply, chain, mergeWith, move, Rule, externalSchematic, template, url, Tree,} from '@angular-devkit/schematics';
|
import {
|
||||||
import {Schema} from './schema';
|
apply,
|
||||||
import {names, toFileName, insert} from '@nrwl/schematics';
|
chain,
|
||||||
|
mergeWith,
|
||||||
|
move,
|
||||||
|
Rule,
|
||||||
|
externalSchematic,
|
||||||
|
template,
|
||||||
|
url,
|
||||||
|
Tree
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
import { Schema } from './schema';
|
||||||
|
import { names, toFileName, insert } from '@nrwl/schematics';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {addBootstrapToModule, addImportToModule} from '@schematics/angular/utility/ast-utils';
|
import { addBootstrapToModule, addImportToModule } from '@schematics/angular/utility/ast-utils';
|
||||||
|
|
||||||
function addBootstrap(path: string): Rule {
|
function addBootstrap(path: string): Rule {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
@ -32,7 +42,10 @@ function addAppToAngularCliJson(fullPath: string, options: Schema): Rule {
|
|||||||
styles: ['styles.css'],
|
styles: ['styles.css'],
|
||||||
scripts: [],
|
scripts: [],
|
||||||
environmentSource: 'environments/environment.ts',
|
environmentSource: 'environments/environment.ts',
|
||||||
environments: {'dev': 'environments/environment.ts', 'prod': 'environments/environment.prod.ts'}
|
environments: {
|
||||||
|
dev: 'environments/environment.ts',
|
||||||
|
prod: 'environments/environment.prod.ts'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
host.overwrite('.angular-cli.json', JSON.stringify(config, null, 2));
|
host.overwrite('.angular-cli.json', JSON.stringify(config, null, 2));
|
||||||
@ -40,18 +53,17 @@ function addAppToAngularCliJson(fullPath: string, options: Schema): Rule {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default function(options: Schema): Rule {
|
export default function(options: Schema): Rule {
|
||||||
const fullPath = path.join(options.directory, toFileName(options.name), options.sourceDir);
|
const fullPath = path.join(options.directory, toFileName(options.name), options.sourceDir);
|
||||||
return chain([
|
return chain([
|
||||||
mergeWith(apply(url('./files'), [template({...options, ...names(options.name), 'dot': '.', 'tmpl': ''})])),
|
mergeWith(apply(url('./files'), [template({ ...options, ...names(options.name), dot: '.', tmpl: '' })])),
|
||||||
externalSchematic('@schematics/angular', 'module', {
|
externalSchematic('@schematics/angular', 'module', {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
commonModule: false,
|
commonModule: false,
|
||||||
flat: true,
|
flat: true,
|
||||||
routing: options.routing,
|
routing: options.routing,
|
||||||
sourceDir: fullPath,
|
sourceDir: fullPath,
|
||||||
spec: false,
|
spec: false
|
||||||
}),
|
}),
|
||||||
externalSchematic('@schematics/angular', 'component', {
|
externalSchematic('@schematics/angular', 'component', {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
@ -65,6 +77,7 @@ export default function(options: Schema): Rule {
|
|||||||
viewEncapsulation: options.viewEncapsulation,
|
viewEncapsulation: options.viewEncapsulation,
|
||||||
changeDetection: options.changeDetection
|
changeDetection: options.changeDetection
|
||||||
}),
|
}),
|
||||||
addBootstrap(fullPath), addAppToAngularCliJson(fullPath, options)
|
addBootstrap(fullPath),
|
||||||
|
addAppToAngularCliJson(fullPath, options)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
4
packages/bazel/src/app/schema.d.ts
vendored
4
packages/bazel/src/app/schema.d.ts
vendored
@ -4,8 +4,8 @@ export interface Schema {
|
|||||||
sourceDir?: string;
|
sourceDir?: string;
|
||||||
inlineStyle?: boolean;
|
inlineStyle?: boolean;
|
||||||
inlineTemplate?: boolean;
|
inlineTemplate?: boolean;
|
||||||
viewEncapsulation?: ('Emulated'|'Native'|'None');
|
viewEncapsulation?: 'Emulated' | 'Native' | 'None';
|
||||||
changeDetection?: ('Default'|'OnPush');
|
changeDetection?: 'Default' | 'OnPush';
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
style?: string;
|
style?: string;
|
||||||
skipTests?: boolean;
|
skipTests?: boolean;
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import {apply, branchAndMerge, chain, mergeWith, Rule, template, Tree, url} from '@angular-devkit/schematics';
|
import { apply, branchAndMerge, chain, mergeWith, Rule, template, Tree, url } from '@angular-devkit/schematics';
|
||||||
import {Schema} from './schema';
|
import { Schema } from './schema';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {names, toFileName} from '@nrwl/schematics';
|
import { names, toFileName } from '@nrwl/schematics';
|
||||||
|
|
||||||
function addLibToAngularCliJson(fullPath: string, schema: Schema): Rule {
|
function addLibToAngularCliJson(fullPath: string, schema: Schema): Rule {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
const source = JSON.parse(host.read('.angular-cli.json')!.toString('utf-8'));
|
const source = JSON.parse(host.read('.angular-cli.json')!.toString('utf-8'));
|
||||||
source.apps.push({name: schema.name, root: fullPath, appDir: false});
|
source.apps.push({ name: schema.name, root: fullPath, appDir: false });
|
||||||
host.overwrite('.angular-cli.json', JSON.stringify(source, null, 2));
|
host.overwrite('.angular-cli.json', JSON.stringify(source, null, 2));
|
||||||
return host;
|
return host;
|
||||||
};
|
};
|
||||||
@ -15,9 +15,7 @@ function addLibToAngularCliJson(fullPath: string, schema: Schema): Rule {
|
|||||||
export default function(options: any): Rule {
|
export default function(options: any): Rule {
|
||||||
const fullPath = path.join(options.directory, toFileName(options.name), options.sourceDir);
|
const fullPath = path.join(options.directory, toFileName(options.name), options.sourceDir);
|
||||||
|
|
||||||
const templateSource = apply(url('./files'), [template({...options, ...names(options.name), dot: '.', tmpl: ''})]);
|
const templateSource = apply(url('./files'), [template({ ...options, ...names(options.name), dot: '.', tmpl: '' })]);
|
||||||
|
|
||||||
return chain([
|
return chain([branchAndMerge(chain([mergeWith(templateSource), addLibToAngularCliJson(fullPath, options)]))]);
|
||||||
branchAndMerge(chain([mergeWith(templateSource), addLibToAngularCliJson(fullPath, options)])),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,17 @@
|
|||||||
import {apply, branchAndMerge, chain, mergeWith, Rule, template, Tree, url} from '@angular-devkit/schematics';
|
import { apply, branchAndMerge, chain, mergeWith, Rule, template, Tree, url } from '@angular-devkit/schematics';
|
||||||
import {Schema} from './schema';
|
import { Schema } from './schema';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {names, toFileName} from '@nrwl/schematics';
|
import { names, toFileName } from '@nrwl/schematics';
|
||||||
|
|
||||||
function addLibToAngularCliJson(fullPath: string, schema: Schema): Rule {
|
function addLibToAngularCliJson(fullPath: string, schema: Schema): Rule {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
const source = JSON.parse(host.read('.angular-cli.json')!.toString('utf-8'));
|
const source = JSON.parse(host.read('.angular-cli.json')!.toString('utf-8'));
|
||||||
source.apps.push(
|
source.apps.push({
|
||||||
{name: schema.name, root: fullPath, appDir: false, prefix: schema.prefix ? schema.prefix : schema.name});
|
name: schema.name,
|
||||||
|
root: fullPath,
|
||||||
|
appDir: false,
|
||||||
|
prefix: schema.prefix ? schema.prefix : schema.name
|
||||||
|
});
|
||||||
host.overwrite('.angular-cli.json', JSON.stringify(source, null, 2));
|
host.overwrite('.angular-cli.json', JSON.stringify(source, null, 2));
|
||||||
return host;
|
return host;
|
||||||
};
|
};
|
||||||
@ -16,9 +20,7 @@ function addLibToAngularCliJson(fullPath: string, schema: Schema): Rule {
|
|||||||
export default function(options: any): Rule {
|
export default function(options: any): Rule {
|
||||||
const fullPath = path.join(options.directory, toFileName(options.name), options.sourceDir);
|
const fullPath = path.join(options.directory, toFileName(options.name), options.sourceDir);
|
||||||
|
|
||||||
const templateSource = apply(url('./files'), [template({...options, ...names(options.name), dot: '.', tmpl: ''})]);
|
const templateSource = apply(url('./files'), [template({ ...options, ...names(options.name), dot: '.', tmpl: '' })]);
|
||||||
|
|
||||||
return chain([
|
return chain([branchAndMerge(chain([mergeWith(templateSource), addLibToAngularCliJson(fullPath, options)]))]);
|
||||||
branchAndMerge(chain([mergeWith(templateSource), addLibToAngularCliJson(fullPath, options)])),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import {apply, chain, mergeWith, move, Rule, schematic, template, url,} from '@angular-devkit/schematics';
|
import { apply, chain, mergeWith, move, Rule, schematic, template, url } from '@angular-devkit/schematics';
|
||||||
import {Schema} from './schema';
|
import { Schema } from './schema';
|
||||||
import {names} from '@nrwl/schematics';
|
import { names } from '@nrwl/schematics';
|
||||||
|
|
||||||
export default function(options: Schema): Rule {
|
export default function(options: Schema): Rule {
|
||||||
return chain([mergeWith(apply(
|
return chain([
|
||||||
url('./files'), [template({...options, ...names(options.name), 'dot': '.', 'tmpl': ''}), move(options.name!)]))]);
|
mergeWith(
|
||||||
|
apply(url('./files'), [template({ ...options, ...names(options.name), dot: '.', tmpl: '' }), move(options.name!)])
|
||||||
|
)
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
export {DataPersistence} from './src/data-persistence';
|
export { DataPersistence } from './src/data-persistence';
|
||||||
export {NxModule} from './src/nx.module';
|
export { NxModule } from './src/nx.module';
|
||||||
|
|||||||
@ -1,49 +1,51 @@
|
|||||||
import 'rxjs/add/operator/delay';
|
import 'rxjs/add/operator/delay';
|
||||||
|
|
||||||
import {Component, Injectable} from '@angular/core';
|
import { Component, Injectable } from '@angular/core';
|
||||||
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
|
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
import {ActivatedRouteSnapshot, Router} from '@angular/router';
|
import { ActivatedRouteSnapshot, Router } from '@angular/router';
|
||||||
import {RouterTestingModule} from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import {Actions, Effect, EffectsModule} from '@ngrx/effects';
|
import { Actions, Effect, EffectsModule } from '@ngrx/effects';
|
||||||
import {provideMockActions} from '@ngrx/effects/testing';
|
import { provideMockActions } from '@ngrx/effects/testing';
|
||||||
import {StoreRouterConnectingModule} from '@ngrx/router-store';
|
import { StoreRouterConnectingModule } from '@ngrx/router-store';
|
||||||
import {Store, StoreModule} from '@ngrx/store';
|
import { Store, StoreModule } from '@ngrx/store';
|
||||||
import {Observable} from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import {of} from 'rxjs/observable/of';
|
import { of } from 'rxjs/observable/of';
|
||||||
import {_throw} from 'rxjs/observable/throw';
|
import { _throw } from 'rxjs/observable/throw';
|
||||||
import {delay} from 'rxjs/operator/delay';
|
import { delay } from 'rxjs/operator/delay';
|
||||||
import {Subject} from 'rxjs/Subject';
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
|
||||||
import {DataPersistence} from '../index';
|
import { DataPersistence } from '../index';
|
||||||
import {NxModule} from '../src/nx.module';
|
import { NxModule } from '../src/nx.module';
|
||||||
import {readAll} from '../testing';
|
import { readAll } from '../testing';
|
||||||
|
|
||||||
// interfaces
|
// interfaces
|
||||||
type Todo = {
|
type Todo = {
|
||||||
id: number; user: string;
|
id: number;
|
||||||
|
user: string;
|
||||||
};
|
};
|
||||||
type Todos = {
|
type Todos = {
|
||||||
selected: Todo;
|
selected: Todo;
|
||||||
};
|
};
|
||||||
type TodosState = {
|
type TodosState = {
|
||||||
todos: Todos; user: string;
|
todos: Todos;
|
||||||
|
user: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
type TodoLoaded = {
|
type TodoLoaded = {
|
||||||
type: 'TODO_LOADED',
|
type: 'TODO_LOADED';
|
||||||
payload: Todo
|
payload: Todo;
|
||||||
};
|
};
|
||||||
type UpdateTodo = {
|
type UpdateTodo = {
|
||||||
type: 'UPDATE_TODO',
|
type: 'UPDATE_TODO';
|
||||||
payload: {newTitle: string;}
|
payload: { newTitle: string };
|
||||||
};
|
};
|
||||||
type Action = TodoLoaded;
|
type Action = TodoLoaded;
|
||||||
|
|
||||||
// reducers
|
// reducers
|
||||||
function todosReducer(state: Todos, action: Action): Todos {
|
function todosReducer(state: Todos, action: Action): Todos {
|
||||||
if (action.type === 'TODO_LOADED') {
|
if (action.type === 'TODO_LOADED') {
|
||||||
return {selected: action.payload};
|
return { selected: action.payload };
|
||||||
} else {
|
} else {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@ -53,9 +55,7 @@ function userReducer(state: string, action: Action): string {
|
|||||||
return 'bob';
|
return 'bob';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component({ template: `ROOT[<router-outlet></router-outlet>]` })
|
||||||
|
|
||||||
@Component({template: `ROOT[<router-outlet></router-outlet>]`})
|
|
||||||
class RootCmp {}
|
class RootCmp {}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -79,8 +79,10 @@ describe('DataPersistence', () => {
|
|||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [RootCmp, TodoComponent],
|
declarations: [RootCmp, TodoComponent],
|
||||||
imports: [
|
imports: [
|
||||||
StoreModule.forRoot({todos: todosReducer, user: userReducer}), StoreRouterConnectingModule,
|
StoreModule.forRoot({ todos: todosReducer, user: userReducer }),
|
||||||
RouterTestingModule.withRoutes([{path: 'todo/:id', component: TodoComponent}]), NxModule.forRoot()
|
StoreRouterConnectingModule,
|
||||||
|
RouterTestingModule.withRoutes([{ path: 'todo/:id', component: TodoComponent }]),
|
||||||
|
NxModule.forRoot()
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -91,28 +93,37 @@ describe('DataPersistence', () => {
|
|||||||
@Effect()
|
@Effect()
|
||||||
loadTodo = this.s.navigation(TodoComponent, {
|
loadTodo = this.s.navigation(TodoComponent, {
|
||||||
run: (a: ActivatedRouteSnapshot, state: TodosState) => {
|
run: (a: ActivatedRouteSnapshot, state: TodosState) => {
|
||||||
return ({type: 'TODO_LOADED', payload: {id: a.params['id'], user: state.user}});
|
return {
|
||||||
|
type: 'TODO_LOADED',
|
||||||
|
payload: { id: a.params['id'], user: state.user }
|
||||||
|
};
|
||||||
},
|
},
|
||||||
onError: () => null
|
onError: () => null
|
||||||
});
|
});
|
||||||
constructor(private s: DataPersistence<any>) {}
|
constructor(private s: DataPersistence<any>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(
|
beforeEach(() => {
|
||||||
() => {TestBed.configureTestingModule(
|
TestBed.configureTestingModule({
|
||||||
{providers: [TodoEffects], imports: [EffectsModule.forRoot([TodoEffects])]})});
|
providers: [TodoEffects],
|
||||||
|
imports: [EffectsModule.forRoot([TodoEffects])]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should work', fakeAsync(() => {
|
it(
|
||||||
const root = TestBed.createComponent(RootCmp);
|
'should work',
|
||||||
|
fakeAsync(() => {
|
||||||
|
const root = TestBed.createComponent(RootCmp);
|
||||||
|
|
||||||
const router: Router = TestBed.get(Router);
|
const router: Router = TestBed.get(Router);
|
||||||
router.navigateByUrl('/todo/123');
|
router.navigateByUrl('/todo/123');
|
||||||
tick(0);
|
tick(0);
|
||||||
root.detectChanges(false);
|
root.detectChanges(false);
|
||||||
|
|
||||||
expect(root.elementRef.nativeElement.innerHTML).toContain('ID 123');
|
expect(root.elementRef.nativeElement.innerHTML).toContain('ID 123');
|
||||||
expect(root.elementRef.nativeElement.innerHTML).toContain('User bob');
|
expect(root.elementRef.nativeElement.innerHTML).toContain('User bob');
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('`run` throwing an error', () => {
|
describe('`run` throwing an error', () => {
|
||||||
@ -124,38 +135,47 @@ describe('DataPersistence', () => {
|
|||||||
if (a.params['id'] === '123') {
|
if (a.params['id'] === '123') {
|
||||||
throw new Error('boom');
|
throw new Error('boom');
|
||||||
} else {
|
} else {
|
||||||
return ({type: 'TODO_LOADED', payload: {id: a.params['id'], user: state.user}});
|
return {
|
||||||
|
type: 'TODO_LOADED',
|
||||||
|
payload: { id: a.params['id'], user: state.user }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (a, e) => ({type: 'ERROR', payload: {error: e}})
|
onError: (a, e) => ({ type: 'ERROR', payload: { error: e } })
|
||||||
});
|
});
|
||||||
constructor(private s: DataPersistence<any>) {}
|
constructor(private s: DataPersistence<any>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(
|
beforeEach(() => {
|
||||||
() => {TestBed.configureTestingModule(
|
TestBed.configureTestingModule({
|
||||||
{providers: [TodoEffects], imports: [EffectsModule.forRoot([TodoEffects])]})});
|
providers: [TodoEffects],
|
||||||
|
imports: [EffectsModule.forRoot([TodoEffects])]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should work', fakeAsync(() => {
|
it(
|
||||||
const root = TestBed.createComponent(RootCmp);
|
'should work',
|
||||||
|
fakeAsync(() => {
|
||||||
|
const root = TestBed.createComponent(RootCmp);
|
||||||
|
|
||||||
const router: Router = TestBed.get(Router);
|
const router: Router = TestBed.get(Router);
|
||||||
let action;
|
let action;
|
||||||
TestBed.get(Actions).subscribe(a => action = a);
|
TestBed.get(Actions).subscribe(a => (action = a));
|
||||||
|
|
||||||
router.navigateByUrl('/todo/123');
|
router.navigateByUrl('/todo/123');
|
||||||
tick(0);
|
tick(0);
|
||||||
root.detectChanges(false);
|
root.detectChanges(false);
|
||||||
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
||||||
expect(action.type).toEqual('ERROR');
|
expect(action.type).toEqual('ERROR');
|
||||||
expect(action.payload.error.message).toEqual('boom');
|
expect(action.payload.error.message).toEqual('boom');
|
||||||
|
|
||||||
// can recover after an error
|
// can recover after an error
|
||||||
router.navigateByUrl('/todo/456');
|
router.navigateByUrl('/todo/456');
|
||||||
tick(0);
|
tick(0);
|
||||||
root.detectChanges(false);
|
root.detectChanges(false);
|
||||||
expect(root.elementRef.nativeElement.innerHTML).toContain('ID 456');
|
expect(root.elementRef.nativeElement.innerHTML).toContain('ID 456');
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('`run` returning an error observable', () => {
|
describe('`run` returning an error observable', () => {
|
||||||
@ -167,43 +187,52 @@ describe('DataPersistence', () => {
|
|||||||
if (a.params['id'] === '123') {
|
if (a.params['id'] === '123') {
|
||||||
return _throw('boom');
|
return _throw('boom');
|
||||||
} else {
|
} else {
|
||||||
return ({type: 'TODO_LOADED', payload: {id: a.params['id'], user: state.user}});
|
return {
|
||||||
|
type: 'TODO_LOADED',
|
||||||
|
payload: { id: a.params['id'], user: state.user }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (a, e) => ({type: 'ERROR', payload: {error: e}})
|
onError: (a, e) => ({ type: 'ERROR', payload: { error: e } })
|
||||||
});
|
});
|
||||||
constructor(private s: DataPersistence<any>) {}
|
constructor(private s: DataPersistence<any>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(
|
beforeEach(() => {
|
||||||
() => {TestBed.configureTestingModule(
|
TestBed.configureTestingModule({
|
||||||
{providers: [TodoEffects], imports: [EffectsModule.forRoot([TodoEffects])]})});
|
providers: [TodoEffects],
|
||||||
|
imports: [EffectsModule.forRoot([TodoEffects])]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should work', fakeAsync(() => {
|
it(
|
||||||
const root = TestBed.createComponent(RootCmp);
|
'should work',
|
||||||
|
fakeAsync(() => {
|
||||||
|
const root = TestBed.createComponent(RootCmp);
|
||||||
|
|
||||||
const router: Router = TestBed.get(Router);
|
const router: Router = TestBed.get(Router);
|
||||||
let action;
|
let action;
|
||||||
TestBed.get(Actions).subscribe(a => action = a);
|
TestBed.get(Actions).subscribe(a => (action = a));
|
||||||
|
|
||||||
router.navigateByUrl('/todo/123');
|
router.navigateByUrl('/todo/123');
|
||||||
tick(0);
|
tick(0);
|
||||||
root.detectChanges(false);
|
root.detectChanges(false);
|
||||||
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
expect(root.elementRef.nativeElement.innerHTML).not.toContain('ID 123');
|
||||||
expect(action.type).toEqual('ERROR');
|
expect(action.type).toEqual('ERROR');
|
||||||
expect(action.payload.error).toEqual('boom');
|
expect(action.payload.error).toEqual('boom');
|
||||||
|
|
||||||
router.navigateByUrl('/todo/456');
|
router.navigateByUrl('/todo/456');
|
||||||
tick(0);
|
tick(0);
|
||||||
root.detectChanges(false);
|
root.detectChanges(false);
|
||||||
expect(root.elementRef.nativeElement.innerHTML).toContain('ID 456');
|
expect(root.elementRef.nativeElement.innerHTML).toContain('ID 456');
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fetch', () => {
|
describe('fetch', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({providers: [DataPersistence]});
|
TestBed.configureTestingModule({ providers: [DataPersistence] });
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('no id', () => {
|
describe('no id', () => {
|
||||||
@ -213,7 +242,10 @@ describe('DataPersistence', () => {
|
|||||||
loadTodos = this.s.fetch('GET_TODOS', {
|
loadTodos = this.s.fetch('GET_TODOS', {
|
||||||
run: (a: any, state: TodosState) => {
|
run: (a: any, state: TodosState) => {
|
||||||
// we need to introduce the delay to "enable" switchMap
|
// we need to introduce the delay to "enable" switchMap
|
||||||
return of ({type: 'TODOS', payload: {user: state.user, todos: 'some todos'}}).delay(1);
|
return of({
|
||||||
|
type: 'TODOS',
|
||||||
|
payload: { user: state.user, todos: 'some todos' }
|
||||||
|
}).delay(1);
|
||||||
},
|
},
|
||||||
|
|
||||||
onError: (a: UpdateTodo, e: any) => null
|
onError: (a: UpdateTodo, e: any) => null
|
||||||
@ -232,16 +264,16 @@ describe('DataPersistence', () => {
|
|||||||
actions = new Subject<any>();
|
actions = new Subject<any>();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [TodoEffects, provideMockActions(() => actions)],
|
providers: [TodoEffects, provideMockActions(() => actions)],
|
||||||
imports: [StoreModule.forRoot({user: userReducer})]
|
imports: [StoreModule.forRoot({ user: userReducer })]
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work', async (done) => {
|
it('should work', async done => {
|
||||||
actions = of({type: 'GET_TODOS', payload: {}}, {type: 'GET_TODOS', payload: {}});
|
actions = of({ type: 'GET_TODOS', payload: {} }, { type: 'GET_TODOS', payload: {} });
|
||||||
|
|
||||||
expect(await readAll(TestBed.get(TodoEffects).loadTodos)).toEqual([
|
expect(await readAll(TestBed.get(TodoEffects).loadTodos)).toEqual([
|
||||||
{type: 'TODOS', payload: {user: 'bob', todos: 'some todos'}},
|
{ type: 'TODOS', payload: { user: 'bob', todos: 'some todos' } },
|
||||||
{type: 'TODOS', payload: {user: 'bob', todos: 'some todos'}}
|
{ type: 'TODOS', payload: { user: 'bob', todos: 'some todos' } }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
@ -254,7 +286,7 @@ describe('DataPersistence', () => {
|
|||||||
@Effect()
|
@Effect()
|
||||||
loadTodo = this.s.fetch('GET_TODO', {
|
loadTodo = this.s.fetch('GET_TODO', {
|
||||||
id: (a: any, state: TodosState) => a.payload.id,
|
id: (a: any, state: TodosState) => a.payload.id,
|
||||||
run: (a: any, state: TodosState) => of({type: 'TODO', payload: a.payload}).delay(1),
|
run: (a: any, state: TodosState) => of({ type: 'TODO', payload: a.payload }).delay(1),
|
||||||
onError: (a: UpdateTodo, e: any) => null
|
onError: (a: UpdateTodo, e: any) => null
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -271,17 +303,20 @@ describe('DataPersistence', () => {
|
|||||||
actions = new Subject<any>();
|
actions = new Subject<any>();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [TodoEffects, provideMockActions(() => actions)],
|
providers: [TodoEffects, provideMockActions(() => actions)],
|
||||||
imports: [StoreModule.forRoot({user: userReducer})]
|
imports: [StoreModule.forRoot({ user: userReducer })]
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work', async (done) => {
|
it('should work', async done => {
|
||||||
actions =
|
actions = of(
|
||||||
of({type: 'GET_TODO', payload: {id: 1, value: '1'}}, {type: 'GET_TODO', payload: {id: 2, value: '2a'}},
|
{ type: 'GET_TODO', payload: { id: 1, value: '1' } },
|
||||||
{type: 'GET_TODO', payload: {id: 2, value: '2b'}});
|
{ type: 'GET_TODO', payload: { id: 2, value: '2a' } },
|
||||||
|
{ type: 'GET_TODO', payload: { id: 2, value: '2b' } }
|
||||||
|
);
|
||||||
|
|
||||||
expect(await readAll(TestBed.get(TodoEffects).loadTodo)).toEqual([
|
expect(await readAll(TestBed.get(TodoEffects).loadTodo)).toEqual([
|
||||||
{type: 'TODO', payload: {id: 1, value: '1'}}, {type: 'TODO', payload: {id: 2, value: '2b'}}
|
{ type: 'TODO', payload: { id: 1, value: '1' } },
|
||||||
|
{ type: 'TODO', payload: { id: 2, value: '2b' } }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
@ -291,7 +326,7 @@ describe('DataPersistence', () => {
|
|||||||
|
|
||||||
describe('pessimisticUpdate', () => {
|
describe('pessimisticUpdate', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({providers: [DataPersistence]});
|
TestBed.configureTestingModule({ providers: [DataPersistence] });
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('successful', () => {
|
describe('successful', () => {
|
||||||
@ -299,8 +334,10 @@ describe('DataPersistence', () => {
|
|||||||
class TodoEffects {
|
class TodoEffects {
|
||||||
@Effect()
|
@Effect()
|
||||||
loadTodo = this.s.pessimisticUpdate('UPDATE_TODO', {
|
loadTodo = this.s.pessimisticUpdate('UPDATE_TODO', {
|
||||||
run: (a: UpdateTodo, state: TodosState) =>
|
run: (a: UpdateTodo, state: TodosState) => ({
|
||||||
({type: 'TODO_UPDATED', payload: {user: state.user, newTitle: a.payload.newTitle}}),
|
type: 'TODO_UPDATED',
|
||||||
|
payload: { user: state.user, newTitle: a.payload.newTitle }
|
||||||
|
}),
|
||||||
onError: (a: UpdateTodo, e: any) => null
|
onError: (a: UpdateTodo, e: any) => null
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -317,15 +354,21 @@ describe('DataPersistence', () => {
|
|||||||
actions = new Subject<any>();
|
actions = new Subject<any>();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [TodoEffects, provideMockActions(() => actions)],
|
providers: [TodoEffects, provideMockActions(() => actions)],
|
||||||
imports: [StoreModule.forRoot({user: userReducer})]
|
imports: [StoreModule.forRoot({ user: userReducer })]
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work', async (done) => {
|
it('should work', async done => {
|
||||||
actions = of({type: 'UPDATE_TODO', payload: {newTitle: 'newTitle'}});
|
actions = of({
|
||||||
|
type: 'UPDATE_TODO',
|
||||||
|
payload: { newTitle: 'newTitle' }
|
||||||
|
});
|
||||||
|
|
||||||
expect(await readAll(TestBed.get(TodoEffects).loadTodo)).toEqual([
|
expect(await readAll(TestBed.get(TodoEffects).loadTodo)).toEqual([
|
||||||
{type: 'TODO_UPDATED', payload: {user: 'bob', newTitle: 'newTitle'}}
|
{
|
||||||
|
type: 'TODO_UPDATED',
|
||||||
|
payload: { user: 'bob', newTitle: 'newTitle' }
|
||||||
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
@ -341,7 +384,10 @@ describe('DataPersistence', () => {
|
|||||||
throw new Error('boom');
|
throw new Error('boom');
|
||||||
},
|
},
|
||||||
|
|
||||||
onError: (a: UpdateTodo, e: any) => ({type: 'ERROR', payload: {error: e}})
|
onError: (a: UpdateTodo, e: any) => ({
|
||||||
|
type: 'ERROR',
|
||||||
|
payload: { error: e }
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(private s: DataPersistence<any>) {}
|
constructor(private s: DataPersistence<any>) {}
|
||||||
@ -357,12 +403,15 @@ describe('DataPersistence', () => {
|
|||||||
actions = new Subject<any>();
|
actions = new Subject<any>();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [TodoEffects, provideMockActions(() => actions)],
|
providers: [TodoEffects, provideMockActions(() => actions)],
|
||||||
imports: [StoreModule.forRoot({user: userReducer})]
|
imports: [StoreModule.forRoot({ user: userReducer })]
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work', async (done) => {
|
it('should work', async done => {
|
||||||
actions = of({type: 'UPDATE_TODO', payload: {newTitle: 'newTitle'}});
|
actions = of({
|
||||||
|
type: 'UPDATE_TODO',
|
||||||
|
payload: { newTitle: 'newTitle' }
|
||||||
|
});
|
||||||
|
|
||||||
const [a]: any = await readAll(TestBed.get(TodoEffects).loadTodo);
|
const [a]: any = await readAll(TestBed.get(TodoEffects).loadTodo);
|
||||||
|
|
||||||
@ -382,7 +431,10 @@ describe('DataPersistence', () => {
|
|||||||
return _throw('boom');
|
return _throw('boom');
|
||||||
},
|
},
|
||||||
|
|
||||||
onError: (a: UpdateTodo, e: any) => ({type: 'ERROR', payload: {error: e}})
|
onError: (a: UpdateTodo, e: any) => ({
|
||||||
|
type: 'ERROR',
|
||||||
|
payload: { error: e }
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(private s: DataPersistence<any>) {}
|
constructor(private s: DataPersistence<any>) {}
|
||||||
@ -398,12 +450,15 @@ describe('DataPersistence', () => {
|
|||||||
actions = new Subject<any>();
|
actions = new Subject<any>();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [TodoEffects, provideMockActions(() => actions)],
|
providers: [TodoEffects, provideMockActions(() => actions)],
|
||||||
imports: [StoreModule.forRoot({user: userReducer})]
|
imports: [StoreModule.forRoot({ user: userReducer })]
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work', async (done) => {
|
it('should work', async done => {
|
||||||
actions = of({type: 'UPDATE_TODO', payload: {newTitle: 'newTitle'}});
|
actions = of({
|
||||||
|
type: 'UPDATE_TODO',
|
||||||
|
payload: { newTitle: 'newTitle' }
|
||||||
|
});
|
||||||
|
|
||||||
const [a]: any = await readAll(TestBed.get(TodoEffects).loadTodo);
|
const [a]: any = await readAll(TestBed.get(TodoEffects).loadTodo);
|
||||||
|
|
||||||
@ -412,12 +467,12 @@ describe('DataPersistence', () => {
|
|||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('optimisticUpdate', () => {
|
describe('optimisticUpdate', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({providers: [DataPersistence]});
|
TestBed.configureTestingModule({ providers: [DataPersistence] });
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('`run` throws an error', () => {
|
describe('`run` throws an error', () => {
|
||||||
@ -429,7 +484,10 @@ describe('DataPersistence', () => {
|
|||||||
throw new Error('boom');
|
throw new Error('boom');
|
||||||
},
|
},
|
||||||
|
|
||||||
undoAction: (a: UpdateTodo, e: any) => ({type: 'UNDO_UPDATE_TODO', payload: a.payload})
|
undoAction: (a: UpdateTodo, e: any) => ({
|
||||||
|
type: 'UNDO_UPDATE_TODO',
|
||||||
|
payload: a.payload
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(private s: DataPersistence<any>) {}
|
constructor(private s: DataPersistence<any>) {}
|
||||||
@ -445,12 +503,15 @@ describe('DataPersistence', () => {
|
|||||||
actions = new Subject<any>();
|
actions = new Subject<any>();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [TodoEffects, provideMockActions(() => actions)],
|
providers: [TodoEffects, provideMockActions(() => actions)],
|
||||||
imports: [StoreModule.forRoot({user: userReducer})]
|
imports: [StoreModule.forRoot({ user: userReducer })]
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work', async (done) => {
|
it('should work', async done => {
|
||||||
actions = of({type: 'UPDATE_TODO', payload: {newTitle: 'newTitle'}});
|
actions = of({
|
||||||
|
type: 'UPDATE_TODO',
|
||||||
|
payload: { newTitle: 'newTitle' }
|
||||||
|
});
|
||||||
|
|
||||||
const [a]: any = await readAll(TestBed.get(TodoEffects).loadTodo);
|
const [a]: any = await readAll(TestBed.get(TodoEffects).loadTodo);
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import {from} from 'rxjs/observable/from'
|
import { from } from 'rxjs/observable/from';
|
||||||
import {readAll, readFirst} from '../src/testing-utils';
|
import { readAll, readFirst } from '../src/testing-utils';
|
||||||
|
|
||||||
describe('TestingUtils', () => {
|
describe('TestingUtils', () => {
|
||||||
describe('readAll', () => {
|
describe('readAll', () => {
|
||||||
it('should transform Observable<T> to Promise<Array<T>>', async (done) => {
|
it('should transform Observable<T> to Promise<Array<T>>', async done => {
|
||||||
const obs = from([1, 2, 3]);
|
const obs = from([1, 2, 3]);
|
||||||
const result = await readAll(obs);
|
const result = await readAll(obs);
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ describe('TestingUtils', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('readFirst', () => {
|
describe('readFirst', () => {
|
||||||
it('should transform first item emitted from Observable<T> to Promise<T>', async (done) => {
|
it('should transform first item emitted from Observable<T> to Promise<T>', async done => {
|
||||||
const obs = from([1, 2, 3]);
|
const obs = from([1, 2, 3]);
|
||||||
const result = await readFirst(obs);
|
const result = await readFirst(obs);
|
||||||
|
|
||||||
|
|||||||
@ -1,32 +1,32 @@
|
|||||||
import {Injectable, Type} from '@angular/core';
|
import { Injectable, Type } from '@angular/core';
|
||||||
import {ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
|
import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
import {Actions} from '@ngrx/effects';
|
import { Actions } from '@ngrx/effects';
|
||||||
import {ROUTER_NAVIGATION, RouterNavigationAction} from '@ngrx/router-store';
|
import { ROUTER_NAVIGATION, RouterNavigationAction } from '@ngrx/router-store';
|
||||||
import {Action, State, Store} from '@ngrx/store';
|
import { Action, State, Store } from '@ngrx/store';
|
||||||
import {Observable} from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import {of} from 'rxjs/observable/of';
|
import { of } from 'rxjs/observable/of';
|
||||||
import {_catch} from 'rxjs/operator/catch';
|
import { _catch } from 'rxjs/operator/catch';
|
||||||
import {concatMap} from 'rxjs/operator/concatMap';
|
import { concatMap } from 'rxjs/operator/concatMap';
|
||||||
import {filter} from 'rxjs/operator/filter';
|
import { filter } from 'rxjs/operator/filter';
|
||||||
import {groupBy} from 'rxjs/operator/groupBy';
|
import { groupBy } from 'rxjs/operator/groupBy';
|
||||||
import {map} from 'rxjs/operator/map';
|
import { map } from 'rxjs/operator/map';
|
||||||
import {mergeMap} from 'rxjs/operator/mergeMap';
|
import { mergeMap } from 'rxjs/operator/mergeMap';
|
||||||
import {switchMap} from 'rxjs/operator/switchMap';
|
import { switchMap } from 'rxjs/operator/switchMap';
|
||||||
import {withLatestFrom} from 'rxjs/operator/withLatestFrom';
|
import { withLatestFrom } from 'rxjs/operator/withLatestFrom';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link DataPersistence.pessimisticUpdate} for more information.
|
* See {@link DataPersistence.pessimisticUpdate} for more information.
|
||||||
*/
|
*/
|
||||||
export interface PessimisticUpdateOpts {
|
export interface PessimisticUpdateOpts {
|
||||||
run(a: Action, state?: any): Observable<Action>|Action|void;
|
run(a: Action, state?: any): Observable<Action> | Action | void;
|
||||||
onError(a: Action, e: any): Observable<any>|any;
|
onError(a: Action, e: any): Observable<any> | any;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* See {@link DataPersistence.pessimisticUpdate} for more information.
|
* See {@link DataPersistence.pessimisticUpdate} for more information.
|
||||||
*/
|
*/
|
||||||
export interface OptimisticUpdateOpts {
|
export interface OptimisticUpdateOpts {
|
||||||
run(a: Action, state?: any): Observable<any>|any;
|
run(a: Action, state?: any): Observable<any> | any;
|
||||||
undoAction(a: Action, e: any): Observable<Action>|Action;
|
undoAction(a: Action, e: any): Observable<Action> | Action;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,16 +34,16 @@ export interface OptimisticUpdateOpts {
|
|||||||
*/
|
*/
|
||||||
export interface FetchOpts {
|
export interface FetchOpts {
|
||||||
id?(a: Action, state?: any): any;
|
id?(a: Action, state?: any): any;
|
||||||
run(a: Action, state?: any): Observable<Action>|Action|void;
|
run(a: Action, state?: any): Observable<Action> | Action | void;
|
||||||
onError?(a: Action, e: any): Observable<any>|any;
|
onError?(a: Action, e: any): Observable<any> | any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link DataPersistence.navigation} for more information.
|
* See {@link DataPersistence.navigation} for more information.
|
||||||
*/
|
*/
|
||||||
export interface HandleNavigationOpts {
|
export interface HandleNavigationOpts {
|
||||||
run(a: ActivatedRouteSnapshot, state?: any): Observable<Action>|Action|void;
|
run(a: ActivatedRouteSnapshot, state?: any): Observable<Action> | Action | void;
|
||||||
onError?(a: ActivatedRouteSnapshot, e: any): Observable<any>|any;
|
onError?(a: ActivatedRouteSnapshot, e: any): Observable<any> | any;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Pair = [Action, any];
|
type Pair = [Action, any];
|
||||||
@ -211,10 +211,10 @@ export class DataPersistence<T> {
|
|||||||
const allPairs = withLatestFrom.call(nav, this.store);
|
const allPairs = withLatestFrom.call(nav, this.store);
|
||||||
|
|
||||||
if (opts.id) {
|
if (opts.id) {
|
||||||
const groupedFetches: Observable<Observable<Pair>> = groupBy.call(allPairs, (p) => opts.id(p[0], p[1]));
|
const groupedFetches: Observable<Observable<Pair>> = groupBy.call(allPairs, p => opts.id(p[0], p[1]));
|
||||||
return mergeMap.call(
|
return mergeMap.call(groupedFetches, (pairs: Observable<Pair>) =>
|
||||||
groupedFetches,
|
switchMap.call(pairs, this.runWithErrorHandling(opts.run, opts.onError))
|
||||||
(pairs: Observable<Pair>) => switchMap.call(pairs, this.runWithErrorHandling(opts.run, opts.onError)));
|
);
|
||||||
} else {
|
} else {
|
||||||
return concatMap.call(allPairs, this.runWithErrorHandling(opts.run, opts.onError));
|
return concatMap.call(allPairs, this.runWithErrorHandling(opts.run, opts.onError));
|
||||||
}
|
}
|
||||||
@ -256,10 +256,11 @@ export class DataPersistence<T> {
|
|||||||
*/
|
*/
|
||||||
navigation(component: Type<any>, opts: HandleNavigationOpts): Observable<any> {
|
navigation(component: Type<any>, opts: HandleNavigationOpts): Observable<any> {
|
||||||
const nav = filter.call(
|
const nav = filter.call(
|
||||||
map.call(
|
map.call(this.actions.ofType(ROUTER_NAVIGATION), (a: RouterNavigationAction<RouterStateSnapshot>) =>
|
||||||
this.actions.ofType(ROUTER_NAVIGATION),
|
findSnapshot(component, a.payload.routerState.root)
|
||||||
(a: RouterNavigationAction<RouterStateSnapshot>) => findSnapshot(component, a.payload.routerState.root)),
|
),
|
||||||
s => !!s);
|
s => !!s
|
||||||
|
);
|
||||||
|
|
||||||
const pairs = withLatestFrom.call(nav, this.store);
|
const pairs = withLatestFrom.call(nav, this.store);
|
||||||
return switchMap.call(pairs, this.runWithErrorHandling(opts.run, opts.onError));
|
return switchMap.call(pairs, this.runWithErrorHandling(opts.run, opts.onError));
|
||||||
@ -269,11 +270,11 @@ export class DataPersistence<T> {
|
|||||||
return a => {
|
return a => {
|
||||||
try {
|
try {
|
||||||
const r = wrapIntoObservable(run(a[0], a[1]));
|
const r = wrapIntoObservable(run(a[0], a[1]));
|
||||||
return _catch.call(r, e => wrapIntoObservable(onError(a[0], e)))
|
return _catch.call(r, e => wrapIntoObservable(onError(a[0], e)));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return wrapIntoObservable(onError(a[0], e));
|
return wrapIntoObservable(onError(a[0], e));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,8 +295,8 @@ function wrapIntoObservable(obj: any): Observable<any> {
|
|||||||
if (!!obj && typeof obj.subscribe === 'function') {
|
if (!!obj && typeof obj.subscribe === 'function') {
|
||||||
return obj;
|
return obj;
|
||||||
} else if (!obj) {
|
} else if (!obj) {
|
||||||
return of ();
|
return of();
|
||||||
} else {
|
} else {
|
||||||
return of (obj);
|
return of(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {ModuleWithProviders, NgModule} from '@angular/core';
|
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||||
import {DataPersistence} from './data-persistence';
|
import { DataPersistence } from './data-persistence';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes Provides services for enterprise Angular applications.
|
* @whatItDoes Provides services for enterprise Angular applications.
|
||||||
@ -9,6 +9,6 @@ import {DataPersistence} from './data-persistence';
|
|||||||
@NgModule({})
|
@NgModule({})
|
||||||
export class NxModule {
|
export class NxModule {
|
||||||
static forRoot(): ModuleWithProviders {
|
static forRoot(): ModuleWithProviders {
|
||||||
return {ngModule: NxModule, providers: [DataPersistence]};
|
return { ngModule: NxModule, providers: [DataPersistence] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {Observable} from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import {first} from 'rxjs/operator/first';
|
import { first } from 'rxjs/operator/first';
|
||||||
import {toArray} from 'rxjs/operator/toArray';
|
import { toArray } from 'rxjs/operator/toArray';
|
||||||
import {toPromise} from 'rxjs/operator/toPromise';
|
import { toPromise } from 'rxjs/operator/toPromise';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes reads all the values from an observable and returns a promise
|
* @whatItDoes reads all the values from an observable and returns a promise
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
export {cold, hot} from 'jasmine-marbles';
|
export { cold, hot } from 'jasmine-marbles';
|
||||||
export {readAll, readFirst} from './src/testing-utils';
|
export { readAll, readFirst } from './src/testing-utils';
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
export {addImportToModule, addProviderToModule, insert} from './src/utility/ast-utils';
|
export { addImportToModule, addProviderToModule, insert } from './src/utility/ast-utils';
|
||||||
export {names, toClassName, toFileName, toPropertyName} from './src/utility/name-utils';
|
export { names, toClassName, toFileName, toPropertyName } from './src/utility/name-utils';
|
||||||
|
|||||||
@ -1,12 +1,26 @@
|
|||||||
import {apply, branchAndMerge, chain, externalSchematic, mergeWith, move, Rule, template, Tree, url, MergeStrategy, filter, noop} from '@angular-devkit/schematics';
|
import {
|
||||||
import {Schema} from './schema';
|
apply,
|
||||||
|
branchAndMerge,
|
||||||
|
chain,
|
||||||
|
externalSchematic,
|
||||||
|
mergeWith,
|
||||||
|
move,
|
||||||
|
Rule,
|
||||||
|
template,
|
||||||
|
Tree,
|
||||||
|
url,
|
||||||
|
MergeStrategy,
|
||||||
|
filter,
|
||||||
|
noop
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
import { Schema } from './schema';
|
||||||
import * as stringUtils from '@schematics/angular/strings';
|
import * as stringUtils from '@schematics/angular/strings';
|
||||||
import {addImportToModule, insert, toFileName} from '@nrwl/schematics';
|
import { addImportToModule, insert, toFileName } from '@nrwl/schematics';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {addBootstrapToModule} from '@schematics/angular/utility/ast-utils';
|
import { addBootstrapToModule } from '@schematics/angular/utility/ast-utils';
|
||||||
import {insertImport} from '@schematics/angular/utility/route-utils';
|
import { insertImport } from '@schematics/angular/utility/route-utils';
|
||||||
import {addApp} from '../utility/config-file-utils';
|
import { addApp } from '../utility/config-file-utils';
|
||||||
|
|
||||||
function addBootstrap(path: string): Rule {
|
function addBootstrap(path: string): Rule {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
@ -29,7 +43,7 @@ function addNxModule(path: string): Rule {
|
|||||||
const sourceFile = ts.createSourceFile(modulePath, moduleSource, ts.ScriptTarget.Latest, true);
|
const sourceFile = ts.createSourceFile(modulePath, moduleSource, ts.ScriptTarget.Latest, true);
|
||||||
insert(host, modulePath, [
|
insert(host, modulePath, [
|
||||||
insertImport(sourceFile, modulePath, 'NxModule', '@nrwl/nx'),
|
insertImport(sourceFile, modulePath, 'NxModule', '@nrwl/nx'),
|
||||||
...addImportToModule(sourceFile, modulePath, 'NxModule.forRoot()'),
|
...addImportToModule(sourceFile, modulePath, 'NxModule.forRoot()')
|
||||||
]);
|
]);
|
||||||
return host;
|
return host;
|
||||||
};
|
};
|
||||||
@ -43,21 +57,24 @@ function addAppToAngularCliJson(options: Schema): Rule {
|
|||||||
const sourceText = host.read('.angular-cli.json')!.toString('utf-8');
|
const sourceText = host.read('.angular-cli.json')!.toString('utf-8');
|
||||||
const json = JSON.parse(sourceText);
|
const json = JSON.parse(sourceText);
|
||||||
json.apps = addApp(json.apps, {
|
json.apps = addApp(json.apps, {
|
||||||
'name': options.name,
|
name: options.name,
|
||||||
'root': fullPath(options),
|
root: fullPath(options),
|
||||||
'outDir': `dist/apps/${options.name}`,
|
outDir: `dist/apps/${options.name}`,
|
||||||
'assets': ['assets', 'favicon.ico'],
|
assets: ['assets', 'favicon.ico'],
|
||||||
'index': 'index.html',
|
index: 'index.html',
|
||||||
'main': 'main.ts',
|
main: 'main.ts',
|
||||||
'polyfills': 'polyfills.ts',
|
polyfills: 'polyfills.ts',
|
||||||
'test': '../../../test.js',
|
test: '../../../test.js',
|
||||||
'tsconfig': '../../../tsconfig.app.json',
|
tsconfig: '../../../tsconfig.app.json',
|
||||||
'testTsconfig': '../../../tsconfig.spec.json',
|
testTsconfig: '../../../tsconfig.spec.json',
|
||||||
'prefix': options.prefix,
|
prefix: options.prefix,
|
||||||
'styles': [`styles.${options.style}`],
|
styles: [`styles.${options.style}`],
|
||||||
'scripts': [],
|
scripts: [],
|
||||||
'environmentSource': 'environments/environment.ts',
|
environmentSource: 'environments/environment.ts',
|
||||||
'environments': {'dev': 'environments/environment.ts', 'prod': 'environments/environment.prod.ts'}
|
environments: {
|
||||||
|
dev: 'environments/environment.ts',
|
||||||
|
prod: 'environments/environment.prod.ts'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
host.overwrite('.angular-cli.json', JSON.stringify(json, null, 2));
|
host.overwrite('.angular-cli.json', JSON.stringify(json, null, 2));
|
||||||
@ -66,19 +83,21 @@ function addAppToAngularCliJson(options: Schema): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function(schema: Schema): Rule {
|
export default function(schema: Schema): Rule {
|
||||||
const options = {...schema, name: toFileName(schema.name)};
|
const options = { ...schema, name: toFileName(schema.name) };
|
||||||
const templateSource =
|
const templateSource = apply(url('./files'), [
|
||||||
apply(url('./files'), [template({utils: stringUtils, dot: '.', tmpl: '', ...options as object})]);
|
template({ utils: stringUtils, dot: '.', tmpl: '', ...(options as object) })
|
||||||
|
]);
|
||||||
|
|
||||||
const selector = `${options.prefix}-root`;
|
const selector = `${options.prefix}-root`;
|
||||||
return chain([
|
return chain([
|
||||||
branchAndMerge(chain([mergeWith(templateSource)])), externalSchematic('@schematics/angular', 'module', {
|
branchAndMerge(chain([mergeWith(templateSource)])),
|
||||||
|
externalSchematic('@schematics/angular', 'module', {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
commonModule: false,
|
commonModule: false,
|
||||||
flat: true,
|
flat: true,
|
||||||
routing: options.routing,
|
routing: options.routing,
|
||||||
sourceDir: fullPath(options),
|
sourceDir: fullPath(options),
|
||||||
spec: false,
|
spec: false
|
||||||
}),
|
}),
|
||||||
externalSchematic('@schematics/angular', 'component', {
|
externalSchematic('@schematics/angular', 'component', {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
@ -94,15 +113,16 @@ export default function(schema: Schema): Rule {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
mergeWith(
|
mergeWith(
|
||||||
apply(
|
apply(url('./component-files'), [
|
||||||
url('./component-files'),
|
options.inlineTemplate ? filter(path => !path.endsWith('.html')) : noop(),
|
||||||
[
|
template({ ...options, tmpl: '' }),
|
||||||
options.inlineTemplate ? filter(path => !path.endsWith('.html')) : noop(),
|
move(path.join(fullPath(options), 'app'))
|
||||||
template({...options, tmpl: ''}),
|
]),
|
||||||
move(path.join(fullPath(options), 'app')),
|
MergeStrategy.Overwrite
|
||||||
]),
|
),
|
||||||
MergeStrategy.Overwrite),
|
addBootstrap(fullPath(options)),
|
||||||
addBootstrap(fullPath(options)), addNxModule(fullPath(options)), addAppToAngularCliJson(options)
|
addNxModule(fullPath(options)),
|
||||||
|
addAppToAngularCliJson(options)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
packages/schematics/src/app/schema.d.ts
vendored
4
packages/schematics/src/app/schema.d.ts
vendored
@ -3,8 +3,8 @@ export interface Schema {
|
|||||||
sourceDir?: string;
|
sourceDir?: string;
|
||||||
inlineStyle?: boolean;
|
inlineStyle?: boolean;
|
||||||
inlineTemplate?: boolean;
|
inlineTemplate?: boolean;
|
||||||
viewEncapsulation?: ('Emulated'|'Native'|'None');
|
viewEncapsulation?: 'Emulated' | 'Native' | 'None';
|
||||||
changeDetection?: ('Default'|'OnPush');
|
changeDetection?: 'Default' | 'OnPush';
|
||||||
routing?: boolean;
|
routing?: boolean;
|
||||||
skipTests?: boolean;
|
skipTests?: boolean;
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
Language: JavaScript
|
|
||||||
BasedOnStyle: Google
|
|
||||||
ColumnLimit: 120
|
|
||||||
@ -9,7 +9,7 @@
|
|||||||
"test": "ng test",
|
"test": "ng test",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "ng e2e",
|
"e2e": "ng e2e",
|
||||||
"format": "find apps/ -iname '*.ts' | xargs clang-format -i && find libs/ -iname '*.ts' | xargs clang-format -i"
|
"format": "prettier --single-quote --print-width 120 --write '{apps,libs}/**/*.ts'"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -52,6 +52,6 @@
|
|||||||
"ts-node": "~3.2.0",
|
"ts-node": "~3.2.0",
|
||||||
"tslint": "~5.3.2",<% } %>
|
"tslint": "~5.3.2",<% } %>
|
||||||
"typescript": "~2.3.3",
|
"typescript": "~2.3.3",
|
||||||
"clang-format": "1.0.55"
|
"prettier": "<%= prettierVersion %>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,19 @@
|
|||||||
import {apply, branchAndMerge, chain, mergeWith, move, Rule, template, Tree, url} from '@angular-devkit/schematics';
|
import { apply, branchAndMerge, chain, mergeWith, move, Rule, template, Tree, url } from '@angular-devkit/schematics';
|
||||||
import {Schema} from './schema';
|
import { Schema } from './schema';
|
||||||
import * as stringUtils from '@schematics/angular/strings';
|
import * as stringUtils from '@schematics/angular/strings';
|
||||||
import {libVersions} from '../utility/lib-versions';
|
import { libVersions } from '../utility/lib-versions';
|
||||||
|
|
||||||
export default function(options: Schema): Rule {
|
export default function(options: Schema): Rule {
|
||||||
const npmScope = options.npmScope ? options.npmScope : options.name;
|
const npmScope = options.npmScope ? options.npmScope : options.name;
|
||||||
const templateSource =
|
const templateSource = apply(url('./files'), [
|
||||||
apply(url('./files'), [template({utils: stringUtils, dot: '.', ...libVersions, ...options as object, npmScope})]);
|
template({
|
||||||
|
utils: stringUtils,
|
||||||
|
dot: '.',
|
||||||
|
...libVersions,
|
||||||
|
...(options as object),
|
||||||
|
npmScope
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
return chain([branchAndMerge(chain([mergeWith(templateSource)]))]);
|
return chain([branchAndMerge(chain([mergeWith(templateSource)]))]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,19 @@
|
|||||||
import {apply, branchAndMerge, chain, externalSchematic, mergeWith, move, Rule, template, Tree, url} from '@angular-devkit/schematics';
|
import {
|
||||||
import {Schema} from './schema';
|
apply,
|
||||||
import {names, toFileName} from '@nrwl/schematics';
|
branchAndMerge,
|
||||||
|
chain,
|
||||||
|
externalSchematic,
|
||||||
|
mergeWith,
|
||||||
|
move,
|
||||||
|
Rule,
|
||||||
|
template,
|
||||||
|
Tree,
|
||||||
|
url
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
import { Schema } from './schema';
|
||||||
|
import { names, toFileName } from '@nrwl/schematics';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {addApp} from '../utility/config-file-utils';
|
import { addApp } from '../utility/config-file-utils';
|
||||||
|
|
||||||
function addLibToAngularCliJson(options: Schema): Rule {
|
function addLibToAngularCliJson(options: Schema): Rule {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
@ -12,8 +23,12 @@ function addLibToAngularCliJson(options: Schema): Rule {
|
|||||||
|
|
||||||
const sourceText = host.read('.angular-cli.json')!.toString('utf-8');
|
const sourceText = host.read('.angular-cli.json')!.toString('utf-8');
|
||||||
const json = JSON.parse(sourceText);
|
const json = JSON.parse(sourceText);
|
||||||
json.apps =
|
json.apps = addApp(json.apps, {
|
||||||
addApp(json.apps, {'name': options.name, 'root': fullPath(options), 'test': '../../../test.js', 'appRoot': ''});
|
name: options.name,
|
||||||
|
root: fullPath(options),
|
||||||
|
test: '../../../test.js',
|
||||||
|
appRoot: ''
|
||||||
|
});
|
||||||
|
|
||||||
host.overwrite('.angular-cli.json', JSON.stringify(json, null, 2));
|
host.overwrite('.angular-cli.json', JSON.stringify(json, null, 2));
|
||||||
return host;
|
return host;
|
||||||
@ -21,12 +36,17 @@ function addLibToAngularCliJson(options: Schema): Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function(schema: Schema): Rule {
|
export default function(schema: Schema): Rule {
|
||||||
const options = {...schema, name: toFileName(schema.name)};
|
const options = { ...schema, name: toFileName(schema.name) };
|
||||||
const fullPath = path.join('libs', toFileName(options.name), options.sourceDir);
|
const fullPath = path.join('libs', toFileName(options.name), options.sourceDir);
|
||||||
|
|
||||||
const templateSource = apply(
|
const templateSource = apply(url(options.ngmodule ? './ngfiles' : './files'), [
|
||||||
url(options.ngmodule ? './ngfiles' : './files'),
|
template({
|
||||||
[template({...names(options.name), dot: '.', tmpl: '', ...options as object})]);
|
...names(options.name),
|
||||||
|
dot: '.',
|
||||||
|
tmpl: '',
|
||||||
|
...(options as object)
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
return chain([branchAndMerge(chain([mergeWith(templateSource)])), addLibToAngularCliJson(options)]);
|
return chain([branchAndMerge(chain([mergeWith(templateSource)])), addLibToAngularCliJson(options)]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,24 @@
|
|||||||
import {apply, branchAndMerge, chain, mergeWith, move, noop, Rule, template, Tree, url} from '@angular-devkit/schematics';
|
import {
|
||||||
|
apply,
|
||||||
|
branchAndMerge,
|
||||||
|
chain,
|
||||||
|
mergeWith,
|
||||||
|
move,
|
||||||
|
noop,
|
||||||
|
Rule,
|
||||||
|
template,
|
||||||
|
Tree,
|
||||||
|
url
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
|
||||||
import {names, toClassName, toFileName, toPropertyName} from '../utility/name-utils';
|
import { names, toClassName, toFileName, toPropertyName } from '../utility/name-utils';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {addImportToModule, addProviderToModule, insert, offset} from '../utility/ast-utils';
|
import { addImportToModule, addProviderToModule, insert, offset } from '../utility/ast-utils';
|
||||||
import {insertImport} from '@schematics/angular/utility/route-utils';
|
import { insertImport } from '@schematics/angular/utility/route-utils';
|
||||||
import {Schema} from './schema';
|
import { Schema } from './schema';
|
||||||
import {InsertChange} from '@schematics/angular/utility/change';
|
import { InsertChange } from '@schematics/angular/utility/change';
|
||||||
import {ngrxVersion} from '../utility/lib-versions';
|
import { ngrxVersion } from '../utility/lib-versions';
|
||||||
|
|
||||||
function addImportsToModule(name: string, options: Schema): Rule {
|
function addImportsToModule(name: string, options: Schema): Rule {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
@ -35,7 +46,6 @@ function addImportsToModule(name: string, options: Schema): Rule {
|
|||||||
...addImportToModule(source, modulePath, `!environment.production ? StoreDevtoolsModule.instrument() : []`)
|
...addImportToModule(source, modulePath, `!environment.production ? StoreDevtoolsModule.instrument() : []`)
|
||||||
]);
|
]);
|
||||||
return host;
|
return host;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const reducerPath = `./+state/${toFileName(name)}.reducer`;
|
const reducerPath = `./+state/${toFileName(name)}.reducer`;
|
||||||
const effectsPath = `./+state/${toFileName(name)}.effects`;
|
const effectsPath = `./+state/${toFileName(name)}.effects`;
|
||||||
@ -61,14 +71,16 @@ function addImportsToModule(name: string, options: Schema): Rule {
|
|||||||
insertImport(source, modulePath, 'environment', '../environments/environment'),
|
insertImport(source, modulePath, 'environment', '../environments/environment'),
|
||||||
...addImportToModule(source, modulePath, `StoreModule.forRoot(${reducerName}, {initialState: ${initName}})`),
|
...addImportToModule(source, modulePath, `StoreModule.forRoot(${reducerName}, {initialState: ${initName}})`),
|
||||||
...addImportToModule(source, modulePath, `EffectsModule.forRoot([${effectsName}])`),
|
...addImportToModule(source, modulePath, `EffectsModule.forRoot([${effectsName}])`),
|
||||||
...addImportToModule(source, modulePath, `!environment.production ? StoreDevtoolsModule.instrument() : []`),
|
...addImportToModule(source, modulePath, `!environment.production ? StoreDevtoolsModule.instrument() : []`)
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
insert(host, modulePath, [
|
insert(host, modulePath, [
|
||||||
...common,
|
...common,
|
||||||
...addImportToModule(
|
...addImportToModule(
|
||||||
source, modulePath,
|
source,
|
||||||
`StoreModule.forFeature('${toPropertyName(name)}', ${reducerName}, {initialState: ${initName}})`),
|
modulePath,
|
||||||
|
`StoreModule.forFeature('${toPropertyName(name)}', ${reducerName}, {initialState: ${initName}})`
|
||||||
|
),
|
||||||
...addImportToModule(source, modulePath, `EffectsModule.forFeature([${effectsName}])`)
|
...addImportToModule(source, modulePath, `EffectsModule.forFeature([${effectsName}])`)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -112,9 +124,10 @@ export default function(options: Schema): Rule {
|
|||||||
if (options.onlyEmptyRoot) {
|
if (options.onlyEmptyRoot) {
|
||||||
return chain([addImportsToModule(name, options), options.skipPackageJson ? noop() : addNgRxToPackageJson()]);
|
return chain([addImportsToModule(name, options), options.skipPackageJson ? noop() : addNgRxToPackageJson()]);
|
||||||
} else {
|
} else {
|
||||||
const templateSource = apply(url('./files'), [template({...options, tmpl: '', ...names(name)}), move(moduleDir)]);
|
const templateSource = apply(url('./files'), [template({ ...options, tmpl: '', ...names(name) }), move(moduleDir)]);
|
||||||
return chain([
|
return chain([
|
||||||
branchAndMerge(chain([mergeWith(templateSource)])), addImportsToModule(name, options),
|
branchAndMerge(chain([mergeWith(templateSource)])),
|
||||||
|
addImportsToModule(name, options),
|
||||||
options.skipPackageJson ? noop() : addNgRxToPackageJson()
|
options.skipPackageJson ? noop() : addNgRxToPackageJson()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
import {RuleFailure} from 'tslint';
|
import { RuleFailure } from 'tslint';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Rule} from './nxEnforceModuleBoundariesRule';
|
import { Rule } from './nxEnforceModuleBoundariesRule';
|
||||||
|
|
||||||
describe('Enforce Module Boundaries', () => {
|
describe('Enforce Module Boundaries', () => {
|
||||||
it('should not error when everything is in order', () => {
|
it('should not error when everything is in order', () => {
|
||||||
const failures = runRule({npmScope: 'mycompany'}, `
|
const failures = runRule(
|
||||||
|
{ npmScope: 'mycompany' },
|
||||||
|
`
|
||||||
import '@mycompany/mylib';
|
import '@mycompany/mylib';
|
||||||
import '../blah';
|
import '../blah';
|
||||||
`);
|
`
|
||||||
|
);
|
||||||
|
|
||||||
expect(failures.length).toEqual(0);
|
expect(failures.length).toEqual(0);
|
||||||
});
|
});
|
||||||
@ -21,14 +24,14 @@ describe('Enforce Module Boundaries', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should error about deep imports into libraries', () => {
|
it('should error about deep imports into libraries', () => {
|
||||||
const failures = runRule({npmScope: 'mycompany'}, `import '@mycompany/mylib/blah';`);
|
const failures = runRule({ npmScope: 'mycompany' }, `import '@mycompany/mylib/blah';`);
|
||||||
|
|
||||||
expect(failures.length).toEqual(1);
|
expect(failures.length).toEqual(1);
|
||||||
expect(failures[0].getFailure()).toEqual('deep imports into libraries are forbidden');
|
expect(failures[0].getFailure()).toEqual('deep imports into libraries are forbidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should error on importing a lazy-loaded library', () => {
|
it('should error on importing a lazy-loaded library', () => {
|
||||||
const failures = runRule({npmScope: 'mycompany', lazyLoad: ['mylib']}, `import '@mycompany/mylib';`);
|
const failures = runRule({ npmScope: 'mycompany', lazyLoad: ['mylib'] }, `import '@mycompany/mylib';`);
|
||||||
|
|
||||||
expect(failures.length).toEqual(1);
|
expect(failures.length).toEqual(1);
|
||||||
expect(failures[0].getFailure()).toEqual('import of lazy-loaded libraries are forbidden');
|
expect(failures[0].getFailure()).toEqual('import of lazy-loaded libraries are forbidden');
|
||||||
@ -36,7 +39,11 @@ describe('Enforce Module Boundaries', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function runRule(ruleArguments: any, content: string): RuleFailure[] {
|
function runRule(ruleArguments: any, content: string): RuleFailure[] {
|
||||||
const options: any = {ruleArguments: [ruleArguments], ruleSeverity: 'error', ruleName: 'enforceModuleBoundaries'};
|
const options: any = {
|
||||||
|
ruleArguments: [ruleArguments],
|
||||||
|
ruleSeverity: 'error',
|
||||||
|
ruleName: 'enforceModuleBoundaries'
|
||||||
|
};
|
||||||
|
|
||||||
const sourceFile = ts.createSourceFile('proj/apps/myapp/src/main.ts', content, ts.ScriptTarget.Latest, true);
|
const sourceFile = ts.createSourceFile('proj/apps/myapp/src/main.ts', content, ts.ScriptTarget.Latest, true);
|
||||||
const rule = new Rule(options, 'proj');
|
const rule = new Rule(options, 'proj');
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as Lint from 'tslint';
|
import * as Lint from 'tslint';
|
||||||
import {IOptions} from 'tslint';
|
import { IOptions } from 'tslint';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
export class Rule extends Lint.Rules.AbstractRule {
|
export class Rule extends Lint.Rules.AbstractRule {
|
||||||
@ -29,10 +29,8 @@ class EnforceModuleBoundariesWalker extends Lint.RuleWalker {
|
|||||||
|
|
||||||
if (impParts[0] === npmScope && impParts.length > 2) {
|
if (impParts[0] === npmScope && impParts.length > 2) {
|
||||||
this.addFailureAt(node.getStart(), node.getWidth(), 'deep imports into libraries are forbidden');
|
this.addFailureAt(node.getStart(), node.getWidth(), 'deep imports into libraries are forbidden');
|
||||||
|
|
||||||
} else if (impParts[0] === npmScope && impParts.length === 2 && lazyLoad && lazyLoad.indexOf(impParts[1]) > -1) {
|
} else if (impParts[0] === npmScope && impParts.length === 2 && lazyLoad && lazyLoad.indexOf(impParts[1]) > -1) {
|
||||||
this.addFailureAt(node.getStart(), node.getWidth(), 'import of lazy-loaded libraries are forbidden');
|
this.addFailureAt(node.getStart(), node.getWidth(), 'import of lazy-loaded libraries are forbidden');
|
||||||
|
|
||||||
} else if (this.isRelative(imp) && this.isRelativeImportIntoAnotherProject(imp)) {
|
} else if (this.isRelative(imp) && this.isRelativeImportIntoAnotherProject(imp)) {
|
||||||
this.addFailureAt(node.getStart(), node.getWidth(), 'relative imports of libraries are forbidden');
|
this.addFailureAt(node.getStart(), node.getWidth(), 'relative imports of libraries are forbidden');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,34 @@
|
|||||||
import {apply, branchAndMerge, chain, mergeWith, move, noop, Rule, SchematicContext, template, Tree, url} from '@angular-devkit/schematics';
|
import {
|
||||||
|
apply,
|
||||||
|
branchAndMerge,
|
||||||
|
chain,
|
||||||
|
mergeWith,
|
||||||
|
move,
|
||||||
|
noop,
|
||||||
|
Rule,
|
||||||
|
SchematicContext,
|
||||||
|
template,
|
||||||
|
Tree,
|
||||||
|
url
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
|
||||||
import {names, toClassName, toFileName, toPropertyName} from '../utility/name-utils';
|
import { names, toClassName, toFileName, toPropertyName } from '../utility/name-utils';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {addDeclarationToModule, addEntryComponents, addImportToModule, addMethod, addParameterToConstructor, addProviderToModule, getBootstrapComponent, insert, removeFromNgModule} from '../utility/ast-utils';
|
import {
|
||||||
import {insertImport} from '@schematics/angular/utility/route-utils';
|
addDeclarationToModule,
|
||||||
import {Schema} from './schema';
|
addEntryComponents,
|
||||||
import {angularJsVersion} from '../utility/lib-versions';
|
addImportToModule,
|
||||||
|
addMethod,
|
||||||
|
addParameterToConstructor,
|
||||||
|
addProviderToModule,
|
||||||
|
getBootstrapComponent,
|
||||||
|
insert,
|
||||||
|
removeFromNgModule
|
||||||
|
} from '../utility/ast-utils';
|
||||||
|
import { insertImport } from '@schematics/angular/utility/route-utils';
|
||||||
|
import { Schema } from './schema';
|
||||||
|
import { angularJsVersion } from '../utility/lib-versions';
|
||||||
|
|
||||||
function addImportsToModule(moduleClassName: string, options: Schema): Rule {
|
function addImportsToModule(moduleClassName: string, options: Schema): Rule {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
@ -22,8 +43,11 @@ function addImportsToModule(moduleClassName: string, options: Schema): Rule {
|
|||||||
|
|
||||||
insert(host, modulePath, [
|
insert(host, modulePath, [
|
||||||
insertImport(
|
insertImport(
|
||||||
source, modulePath, `configure${toClassName(options.name)}, upgradedComponents`,
|
source,
|
||||||
`./${toFileName(options.name)}-setup`),
|
modulePath,
|
||||||
|
`configure${toClassName(options.name)}, upgradedComponents`,
|
||||||
|
`./${toFileName(options.name)}-setup`
|
||||||
|
),
|
||||||
insertImport(source, modulePath, 'UpgradeModule', '@angular/upgrade/static'),
|
insertImport(source, modulePath, 'UpgradeModule', '@angular/upgrade/static'),
|
||||||
...addImportToModule(source, modulePath, 'UpgradeModule'),
|
...addImportToModule(source, modulePath, 'UpgradeModule'),
|
||||||
...addDeclarationToModule(source, modulePath, '...upgradedComponents'),
|
...addDeclarationToModule(source, modulePath, '...upgradedComponents'),
|
||||||
@ -34,7 +58,6 @@ function addImportsToModule(moduleClassName: string, options: Schema): Rule {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function addNgDoBootstrapToModule(moduleClassName: string, options: Schema): Rule {
|
function addNgDoBootstrapToModule(moduleClassName: string, options: Schema): Rule {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
if (!host.exists(options.module)) {
|
if (!host.exists(options.module)) {
|
||||||
@ -46,8 +69,10 @@ function addNgDoBootstrapToModule(moduleClassName: string, options: Schema): Rul
|
|||||||
const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
|
const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
|
||||||
|
|
||||||
insert(host, modulePath, [
|
insert(host, modulePath, [
|
||||||
...addParameterToConstructor(
|
...addParameterToConstructor(source, modulePath, {
|
||||||
source, modulePath, {className: moduleClassName, param: 'private upgrade: UpgradeModule'}),
|
className: moduleClassName,
|
||||||
|
param: 'private upgrade: UpgradeModule'
|
||||||
|
}),
|
||||||
...addMethod(source, modulePath, {
|
...addMethod(source, modulePath, {
|
||||||
className: moduleClassName,
|
className: moduleClassName,
|
||||||
methodHeader: 'ngDoBootstrap(): void',
|
methodHeader: 'ngDoBootstrap(): void',
|
||||||
@ -74,8 +99,9 @@ function createFiles(angularJsImport: string, moduleClassName: string, moduleFil
|
|||||||
const moduleSource = ts.createSourceFile(modulePath, moduleSourceText, ts.ScriptTarget.Latest, true);
|
const moduleSource = ts.createSourceFile(modulePath, moduleSourceText, ts.ScriptTarget.Latest, true);
|
||||||
|
|
||||||
const bootstrapComponentClassName = getBootstrapComponent(moduleSource, moduleClassName);
|
const bootstrapComponentClassName = getBootstrapComponent(moduleSource, moduleClassName);
|
||||||
const bootstrapComponentFileName =
|
const bootstrapComponentFileName = `${toFileName(
|
||||||
`${toFileName(bootstrapComponentClassName.substring(0, bootstrapComponentClassName.length - 9))}.component`;
|
bootstrapComponentClassName.substring(0, bootstrapComponentClassName.length - 9)
|
||||||
|
)}.component`;
|
||||||
|
|
||||||
const moduleDir = path.dirname(options.module);
|
const moduleDir = path.dirname(options.module);
|
||||||
const templateSource = apply(url('./files'), [
|
const templateSource = apply(url('./files'), [
|
||||||
@ -97,7 +123,6 @@ function createFiles(angularJsImport: string, moduleClassName: string, moduleFil
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function addUpgradeToPackageJson() {
|
function addUpgradeToPackageJson() {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
if (!host.exists('package.json')) return host;
|
if (!host.exists('package.json')) return host;
|
||||||
@ -127,7 +152,8 @@ export default function(options: Schema): Rule {
|
|||||||
|
|
||||||
return chain([
|
return chain([
|
||||||
createFiles(angularJsImport, moduleClassName, moduleFileName, options),
|
createFiles(angularJsImport, moduleClassName, moduleFileName, options),
|
||||||
addImportsToModule(moduleClassName, options), addNgDoBootstrapToModule(moduleClassName, options),
|
addImportsToModule(moduleClassName, options),
|
||||||
|
addNgDoBootstrapToModule(moduleClassName, options),
|
||||||
options.skipPackageJson ? noop() : addUpgradeToPackageJson()
|
options.skipPackageJson ? noop() : addUpgradeToPackageJson()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,17 +5,20 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {Tree} from '@angular-devkit/schematics';
|
import { Tree } from '@angular-devkit/schematics';
|
||||||
import {getDecoratorMetadata, getSourceNodes, insertAfterLastOccurrence} from '@schematics/angular/utility/ast-utils';
|
import { getDecoratorMetadata, getSourceNodes, insertAfterLastOccurrence } from '@schematics/angular/utility/ast-utils';
|
||||||
import {Change, InsertChange, NoopChange, RemoveChange} from '@schematics/angular/utility/change';
|
import { Change, InsertChange, NoopChange, RemoveChange } from '@schematics/angular/utility/change';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
|
|
||||||
// This should be moved to @schematics/angular once it allows to pass custom expressions as providers
|
// This should be moved to @schematics/angular once it allows to pass custom expressions as providers
|
||||||
function _addSymbolToNgModuleMetadata(
|
function _addSymbolToNgModuleMetadata(
|
||||||
source: ts.SourceFile, ngModulePath: string, metadataField: string, expression: string): Change[] {
|
source: ts.SourceFile,
|
||||||
|
ngModulePath: string,
|
||||||
|
metadataField: string,
|
||||||
|
expression: string
|
||||||
|
): Change[] {
|
||||||
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
||||||
let node: any = nodes[0]; // tslint:disable-line:no-any
|
let node: any = nodes[0]; // tslint:disable-line:no-any
|
||||||
|
|
||||||
// Find the decorator declaration.
|
// Find the decorator declaration.
|
||||||
if (!node) {
|
if (!node) {
|
||||||
@ -23,23 +26,21 @@ function _addSymbolToNgModuleMetadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get all the children property assignment of object literals.
|
// Get all the children property assignment of object literals.
|
||||||
const matchingProperties: ts.ObjectLiteralElement[] =
|
const matchingProperties: ts.ObjectLiteralElement[] = (node as ts.ObjectLiteralExpression).properties
|
||||||
(node as ts.ObjectLiteralExpression)
|
.filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment)
|
||||||
.properties
|
// Filter out every fields that's not "metadataField". Also handles string literals
|
||||||
.filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment)
|
// (but not expressions).
|
||||||
// Filter out every fields that's not "metadataField". Also handles string literals
|
.filter((prop: ts.PropertyAssignment) => {
|
||||||
// (but not expressions).
|
const name = prop.name;
|
||||||
.filter((prop: ts.PropertyAssignment) => {
|
switch (name.kind) {
|
||||||
const name = prop.name;
|
case ts.SyntaxKind.Identifier:
|
||||||
switch (name.kind) {
|
return (name as ts.Identifier).getText(source) == metadataField;
|
||||||
case ts.SyntaxKind.Identifier:
|
case ts.SyntaxKind.StringLiteral:
|
||||||
return (name as ts.Identifier).getText(source) == metadataField;
|
return (name as ts.StringLiteral).text == metadataField;
|
||||||
case ts.SyntaxKind.StringLiteral:
|
}
|
||||||
return (name as ts.StringLiteral).text == metadataField;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get the last node of the array literal.
|
// Get the last node of the array literal.
|
||||||
if (!matchingProperties) {
|
if (!matchingProperties) {
|
||||||
@ -90,7 +91,7 @@ function _addSymbolToNgModuleMetadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(node)) {
|
if (Array.isArray(node)) {
|
||||||
const nodeArray = node as {} as Array<ts.Node>;
|
const nodeArray = (node as {}) as Array<ts.Node>;
|
||||||
const symbolsArray = nodeArray.map(node => node.getText());
|
const symbolsArray = nodeArray.map(node => node.getText());
|
||||||
if (symbolsArray.includes(expression)) {
|
if (symbolsArray.includes(expression)) {
|
||||||
return [];
|
return [];
|
||||||
@ -137,27 +138,37 @@ function _addSymbolToNgModuleMetadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function addParameterToConstructor(
|
export function addParameterToConstructor(
|
||||||
source: ts.SourceFile, modulePath: string, opts: {className: string, param: string}): Change[] {
|
source: ts.SourceFile,
|
||||||
|
modulePath: string,
|
||||||
|
opts: { className: string; param: string }
|
||||||
|
): Change[] {
|
||||||
const clazz = findClass(source, opts.className);
|
const clazz = findClass(source, opts.className);
|
||||||
const constructor = clazz.members.filter(m => m.kind === ts.SyntaxKind.Constructor)[0];
|
const constructor = clazz.members.filter(m => m.kind === ts.SyntaxKind.Constructor)[0];
|
||||||
if (constructor) {
|
if (constructor) {
|
||||||
throw new Error('Should be tested');
|
throw new Error('Should be tested');
|
||||||
} else {
|
} else {
|
||||||
const methodHeader = `constructor(${opts.param})`;
|
const methodHeader = `constructor(${opts.param})`;
|
||||||
return addMethod(source, modulePath, {className: opts.className, methodHeader, body: null});
|
return addMethod(source, modulePath, {
|
||||||
|
className: opts.className,
|
||||||
|
methodHeader,
|
||||||
|
body: null
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addMethod(
|
export function addMethod(
|
||||||
source: ts.SourceFile, modulePath: string,
|
source: ts.SourceFile,
|
||||||
opts: {className: string, methodHeader: string, body: string}): Change[] {
|
modulePath: string,
|
||||||
|
opts: { className: string; methodHeader: string; body: string }
|
||||||
|
): Change[] {
|
||||||
const clazz = findClass(source, opts.className);
|
const clazz = findClass(source, opts.className);
|
||||||
const body = opts.body ? `
|
const body = opts.body
|
||||||
|
? `
|
||||||
${opts.methodHeader} {
|
${opts.methodHeader} {
|
||||||
${offset(opts.body, 1, false)}
|
${offset(opts.body, 1, false)}
|
||||||
}
|
}
|
||||||
` :
|
`
|
||||||
`
|
: `
|
||||||
${opts.methodHeader} {}
|
${opts.methodHeader} {}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -167,7 +178,7 @@ ${opts.methodHeader} {}
|
|||||||
|
|
||||||
export function removeFromNgModule(source: ts.SourceFile, modulePath: string, property: string): Change[] {
|
export function removeFromNgModule(source: ts.SourceFile, modulePath: string, property: string): Change[] {
|
||||||
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
||||||
let node: any = nodes[0]; // tslint:disable-line:no-any
|
let node: any = nodes[0]; // tslint:disable-line:no-any
|
||||||
|
|
||||||
// Find the decorator declaration.
|
// Find the decorator declaration.
|
||||||
if (!node) {
|
if (!node) {
|
||||||
@ -177,7 +188,7 @@ export function removeFromNgModule(source: ts.SourceFile, modulePath: string, pr
|
|||||||
// Get all the children property assignment of object literals.
|
// Get all the children property assignment of object literals.
|
||||||
const matchingProperty = getMatchingProperty(source, property);
|
const matchingProperty = getMatchingProperty(source, property);
|
||||||
if (matchingProperty) {
|
if (matchingProperty) {
|
||||||
return [new RemoveChange(modulePath, matchingProperty.pos, matchingProperty.getFullText(source))]
|
return [new RemoveChange(modulePath, matchingProperty.pos, matchingProperty.getFullText(source))];
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -186,8 +197,9 @@ export function removeFromNgModule(source: ts.SourceFile, modulePath: string, pr
|
|||||||
function findClass(source: ts.SourceFile, className: string): ts.ClassDeclaration {
|
function findClass(source: ts.SourceFile, className: string): ts.ClassDeclaration {
|
||||||
const nodes = getSourceNodes(source);
|
const nodes = getSourceNodes(source);
|
||||||
|
|
||||||
const clazz =
|
const clazz = <any>nodes.filter(
|
||||||
<any>nodes.filter(n => n.kind === ts.SyntaxKind.ClassDeclaration && (<any>n).name.text === className)[0];
|
n => n.kind === ts.SyntaxKind.ClassDeclaration && (<any>n).name.text === className
|
||||||
|
)[0];
|
||||||
|
|
||||||
if (!clazz) {
|
if (!clazz) {
|
||||||
throw new Error(`Cannot find class '${className}'`);
|
throw new Error(`Cannot find class '${className}'`);
|
||||||
@ -197,27 +209,23 @@ function findClass(source: ts.SourceFile, className: string): ts.ClassDeclaratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function offset(text: string, numberOfTabs: number, wrap: boolean): string {
|
export function offset(text: string, numberOfTabs: number, wrap: boolean): string {
|
||||||
const lines = text.trim()
|
const lines = text
|
||||||
.split('\n')
|
.trim()
|
||||||
.map(line => {
|
.split('\n')
|
||||||
let tabs = '';
|
.map(line => {
|
||||||
for (let c = 0; c < numberOfTabs; ++c) {
|
let tabs = '';
|
||||||
tabs += ' ';
|
for (let c = 0; c < numberOfTabs; ++c) {
|
||||||
}
|
tabs += ' ';
|
||||||
return `${tabs}${line}`;
|
}
|
||||||
})
|
return `${tabs}${line}`;
|
||||||
.join('\n');
|
})
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
return wrap ? `\n${lines}\n` : lines;
|
return wrap ? `\n${lines}\n` : lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addImportToModule(source: ts.SourceFile, modulePath: string, symbolName: string): Change[] {
|
export function addImportToModule(source: ts.SourceFile, modulePath: string, symbolName: string): Change[] {
|
||||||
return _addSymbolToNgModuleMetadata(
|
return _addSymbolToNgModuleMetadata(source, modulePath, 'imports', symbolName);
|
||||||
source,
|
|
||||||
modulePath,
|
|
||||||
'imports',
|
|
||||||
symbolName,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBootstrapComponent(source: ts.SourceFile, moduleClassName: string): string {
|
export function getBootstrapComponent(source: ts.SourceFile, moduleClassName: string): string {
|
||||||
@ -238,13 +246,13 @@ export function getBootstrapComponent(source: ts.SourceFile, moduleClassName: st
|
|||||||
|
|
||||||
function getMatchingProperty(source: ts.SourceFile, property: string): ts.ObjectLiteralElement {
|
function getMatchingProperty(source: ts.SourceFile, property: string): ts.ObjectLiteralElement {
|
||||||
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
||||||
let node: any = nodes[0]; // tslint:disable-line:no-any
|
let node: any = nodes[0]; // tslint:disable-line:no-any
|
||||||
|
|
||||||
if (!node) return null;
|
if (!node) return null;
|
||||||
|
|
||||||
// Get all the children property assignment of object literals.
|
// Get all the children property assignment of object literals.
|
||||||
return (node as ts.ObjectLiteralExpression)
|
return (
|
||||||
.properties
|
(node as ts.ObjectLiteralExpression).properties
|
||||||
.filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment)
|
.filter(prop => prop.kind == ts.SyntaxKind.PropertyAssignment)
|
||||||
// Filter out every fields that's not "metadataField". Also handles string literals
|
// Filter out every fields that's not "metadataField". Also handles string literals
|
||||||
// (but not expressions).
|
// (but not expressions).
|
||||||
@ -257,7 +265,8 @@ function getMatchingProperty(source: ts.SourceFile, property: string): ts.Object
|
|||||||
return (name as ts.StringLiteral).text === property;
|
return (name as ts.StringLiteral).text === property;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
})[0];
|
})[0]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addProviderToModule(source: ts.SourceFile, modulePath: string, symbolName: string): Change[] {
|
export function addProviderToModule(source: ts.SourceFile, modulePath: string, symbolName: string): Change[] {
|
||||||
@ -272,7 +281,6 @@ export function addEntryComponents(source: ts.SourceFile, modulePath: string, sy
|
|||||||
return _addSymbolToNgModuleMetadata(source, modulePath, 'entryComponents', symbolName);
|
return _addSymbolToNgModuleMetadata(source, modulePath, 'entryComponents', symbolName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function insert(host: Tree, modulePath: string, changes: Change[]) {
|
export function insert(host: Tree, modulePath: string, changes: Change[]) {
|
||||||
const recorder = host.beginUpdate(modulePath);
|
const recorder = host.beginUpdate(modulePath);
|
||||||
for (const change of changes) {
|
for (const change of changes) {
|
||||||
|
|||||||
@ -1,23 +1,30 @@
|
|||||||
import {addApp} from './config-file-utils';
|
import { addApp } from './config-file-utils';
|
||||||
|
|
||||||
describe('configFileUtils', () => {
|
describe('configFileUtils', () => {
|
||||||
describe('sortApps', () => {
|
describe('sortApps', () => {
|
||||||
it('should handle undefined', () => {
|
it('should handle undefined', () => {
|
||||||
expect(addApp(undefined, {name: 'a'})).toEqual([{name: 'a'}]);
|
expect(addApp(undefined, { name: 'a' })).toEqual([{ name: 'a' }]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle an empty array', () => {
|
it('should handle an empty array', () => {
|
||||||
expect(addApp([], {name: 'a'})).toEqual([{name: 'a'}]);
|
expect(addApp([], { name: 'a' })).toEqual([{ name: 'a' }]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should sort apps by name', () => {
|
it('should sort apps by name', () => {
|
||||||
expect(addApp([{name: 'a'}, {name: 'b'}], {name: 'c'})).toEqual([{name: 'a'}, {name: 'b'}, {name: 'c'}]);
|
expect(addApp([{ name: 'a' }, { name: 'b' }], { name: 'c' })).toEqual([
|
||||||
|
{ name: 'a' },
|
||||||
|
{ name: 'b' },
|
||||||
|
{ name: 'c' }
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prioritize apps with "main" defined', () => {
|
it('should prioritize apps with "main" defined', () => {
|
||||||
expect(addApp([{name: 'c'}, {name: 'a'}, {name: 'a', main: 'a'}], {name: 'b', main: 'b'})).toEqual([
|
expect(
|
||||||
{name: 'a', main: 'a'}, {name: 'b', main: 'b'}, {name: 'a'}, {name: 'c'}
|
addApp([{ name: 'c' }, { name: 'a' }, { name: 'a', main: 'a' }], {
|
||||||
]);
|
name: 'b',
|
||||||
|
main: 'b'
|
||||||
|
})
|
||||||
|
).toEqual([{ name: 'a', main: 'a' }, { name: 'b', main: 'b' }, { name: 'a' }, { name: 'c' }]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export function addApp(apps: any[]|undefined, newApp: any): any[] {
|
export function addApp(apps: any[] | undefined, newApp: any): any[] {
|
||||||
if (!apps) {
|
if (!apps) {
|
||||||
apps = [];
|
apps = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ export const angularJsVersion = '1.6.6';
|
|||||||
export const ngrxVersion = '^4.0.0';
|
export const ngrxVersion = '^4.0.0';
|
||||||
export const nxVersion = 'nrwl/nx-build';
|
export const nxVersion = 'nrwl/nx-build';
|
||||||
export const schematicsVersion = 'nrwl/schematics-build';
|
export const schematicsVersion = 'nrwl/schematics-build';
|
||||||
|
export const prettierVersion = '1.7.4';
|
||||||
|
|
||||||
export const libVersions = {
|
export const libVersions = {
|
||||||
angularVersion,
|
angularVersion,
|
||||||
@ -11,5 +12,6 @@ export const libVersions = {
|
|||||||
angularJsVersion,
|
angularJsVersion,
|
||||||
ngrxVersion,
|
ngrxVersion,
|
||||||
nxVersion,
|
nxVersion,
|
||||||
schematicsVersion
|
schematicsVersion,
|
||||||
|
prettierVersion
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
export function names(name: string): any {
|
export function names(name: string): any {
|
||||||
return {name, className: toClassName(name), propertyName: toPropertyName(name), fileName: toFileName(name)};
|
return {
|
||||||
|
name,
|
||||||
|
className: toClassName(name),
|
||||||
|
propertyName: toPropertyName(name),
|
||||||
|
fileName: toFileName(name)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toClassName(str: string): string {
|
export function toClassName(str: string): string {
|
||||||
@ -7,12 +12,16 @@ export function toClassName(str: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function toPropertyName(s: string): string {
|
export function toPropertyName(s: string): string {
|
||||||
return s.replace(/(-|_|\.|\s)+(.)?/g, (_, __, chr) => chr ? chr.toUpperCase() : '')
|
return s
|
||||||
.replace(/^([A-Z])/, m => m.toLowerCase());
|
.replace(/(-|_|\.|\s)+(.)?/g, (_, __, chr) => (chr ? chr.toUpperCase() : ''))
|
||||||
|
.replace(/^([A-Z])/, m => m.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toFileName(s: string): string {
|
export function toFileName(s: string): string {
|
||||||
return s.replace(/([a-z\d])([A-Z])/g, '$1_$2').toLowerCase().replace(/[ _]/g, '-');
|
return s
|
||||||
|
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[ _]/g, '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
function toCapitalCase(s: string): string {
|
function toCapitalCase(s: string): string {
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
Language: JavaScript
|
|
||||||
BasedOnStyle: Google
|
|
||||||
ColumnLimit: 120
|
|
||||||
@ -1,11 +1,23 @@
|
|||||||
import {apply, branchAndMerge, chain, externalSchematic, mergeWith, move, Rule, template, Tree, url, schematic} from '@angular-devkit/schematics';
|
import {
|
||||||
import {Schema} from './schema';
|
apply,
|
||||||
|
branchAndMerge,
|
||||||
|
chain,
|
||||||
|
externalSchematic,
|
||||||
|
mergeWith,
|
||||||
|
move,
|
||||||
|
Rule,
|
||||||
|
template,
|
||||||
|
Tree,
|
||||||
|
url,
|
||||||
|
schematic
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
import { Schema } from './schema';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {angularCliVersion, ngrxVersion, nxVersion, schematicsVersion} from '../utility/lib-versions';
|
import { angularCliVersion, ngrxVersion, nxVersion, prettierVersion, schematicsVersion } from '../utility/lib-versions';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import {join} from 'path';
|
import { join } from 'path';
|
||||||
import {updateJsonFile} from '../utility/fileutils';
|
import { updateJsonFile } from '../utility/fileutils';
|
||||||
import {toFileName} from '@nrwl/schematics';
|
import { toFileName } from '@nrwl/schematics';
|
||||||
|
|
||||||
function updatePackageJson() {
|
function updatePackageJson() {
|
||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
@ -43,8 +55,10 @@ function updatePackageJson() {
|
|||||||
if (!packageJson.dependencies['@angular/cli']) {
|
if (!packageJson.dependencies['@angular/cli']) {
|
||||||
packageJson.dependencies['@angular/cli'] = angularCliVersion;
|
packageJson.dependencies['@angular/cli'] = angularCliVersion;
|
||||||
}
|
}
|
||||||
packageJson.scripts['format'] =
|
if (!packageJson.devDependencies['prettier']) {
|
||||||
`find apps/ -iname '*.ts' | xargs clang-format -i && find libs/ -iname '*.ts' | xargs clang-format -i`;
|
packageJson.devDependencies['prettier'] = prettierVersion;
|
||||||
|
}
|
||||||
|
packageJson.scripts['format'] = `prettier --single-quote --print-width 120 --write '{apps,libs}/**/*.ts'`;
|
||||||
host.overwrite('package.json', JSON.stringify(packageJson, null, 2));
|
host.overwrite('package.json', JSON.stringify(packageJson, null, 2));
|
||||||
return host;
|
return host;
|
||||||
};
|
};
|
||||||
@ -60,8 +74,11 @@ function updateAngularCLIJson(options: Schema) {
|
|||||||
throw new Error('Can only convert projects with one app');
|
throw new Error('Can only convert projects with one app');
|
||||||
}
|
}
|
||||||
|
|
||||||
angularCliJson.lint =
|
angularCliJson.lint = [
|
||||||
[{'project': './tsconfig.app.json'}, {'project': './tsconfig.spec.json'}, {'project': './tsconfig.e2e.json'}];
|
{ project: './tsconfig.app.json' },
|
||||||
|
{ project: './tsconfig.spec.json' },
|
||||||
|
{ project: './tsconfig.e2e.json' }
|
||||||
|
];
|
||||||
|
|
||||||
const app = angularCliJson.apps[0];
|
const app = angularCliJson.apps[0];
|
||||||
app.root = path.join('apps', options.name, app.root);
|
app.root = path.join('apps', options.name, app.root);
|
||||||
@ -69,7 +86,7 @@ function updateAngularCLIJson(options: Schema) {
|
|||||||
app.test = '../../../test.js';
|
app.test = '../../../test.js';
|
||||||
app.tsconfig = '../../../tsconfig.app.json';
|
app.tsconfig = '../../../tsconfig.app.json';
|
||||||
app.testTsconfig = '../../../tsconfig.spec.json';
|
app.testTsconfig = '../../../tsconfig.spec.json';
|
||||||
app.scripts = app.scripts.map((p) => path.join('../../', p));
|
app.scripts = app.scripts.map(p => path.join('../../', p));
|
||||||
if (!angularCliJson.defaults) {
|
if (!angularCliJson.defaults) {
|
||||||
angularCliJson.defaults = {};
|
angularCliJson.defaults = {};
|
||||||
}
|
}
|
||||||
@ -90,16 +107,16 @@ function updateTsConfigsJson(options: Schema) {
|
|||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
const npmScope = options && options.npmScope ? options.npmScope : options.name;
|
const npmScope = options && options.npmScope ? options.npmScope : options.name;
|
||||||
|
|
||||||
updateJsonFile('tsconfig.json', (json) => setUpCompilerOptions(json, npmScope));
|
updateJsonFile('tsconfig.json', json => setUpCompilerOptions(json, npmScope));
|
||||||
|
|
||||||
updateJsonFile('tsconfig.app.json', (json) => {
|
updateJsonFile('tsconfig.app.json', json => {
|
||||||
json['extends'] = './tsconfig.json';
|
json['extends'] = './tsconfig.json';
|
||||||
if (!json.exclude) json.exclude = [];
|
if (!json.exclude) json.exclude = [];
|
||||||
json.exclude = dedup(json.exclude.concat(['**/*.spec.ts', '**/*.e2e-spec.ts', 'node_modules', 'tmp']));
|
json.exclude = dedup(json.exclude.concat(['**/*.spec.ts', '**/*.e2e-spec.ts', 'node_modules', 'tmp']));
|
||||||
setUpCompilerOptions(json, npmScope);
|
setUpCompilerOptions(json, npmScope);
|
||||||
});
|
});
|
||||||
|
|
||||||
updateJsonFile('tsconfig.spec.json', (json) => {
|
updateJsonFile('tsconfig.spec.json', json => {
|
||||||
json['extends'] = './tsconfig.json';
|
json['extends'] = './tsconfig.json';
|
||||||
if (!json.exclude) json.exclude = [];
|
if (!json.exclude) json.exclude = [];
|
||||||
json.files = ['test.js'];
|
json.files = ['test.js'];
|
||||||
@ -107,7 +124,7 @@ function updateTsConfigsJson(options: Schema) {
|
|||||||
setUpCompilerOptions(json, npmScope);
|
setUpCompilerOptions(json, npmScope);
|
||||||
});
|
});
|
||||||
|
|
||||||
updateJsonFile('tsconfig.e2e.json', (json) => {
|
updateJsonFile('tsconfig.e2e.json', json => {
|
||||||
json['extends'] = './tsconfig.json';
|
json['extends'] = './tsconfig.json';
|
||||||
if (!json.exclude) json.exclude = [];
|
if (!json.exclude) json.exclude = [];
|
||||||
json.exclude = dedup(json.exclude.concat(['**/*.spec.ts', 'node_modules', 'tmp']));
|
json.exclude = dedup(json.exclude.concat(['**/*.spec.ts', 'node_modules', 'tmp']));
|
||||||
@ -122,11 +139,11 @@ function updateTsLintJson(options: Schema) {
|
|||||||
return (host: Tree) => {
|
return (host: Tree) => {
|
||||||
const npmScope = options && options.npmScope ? options.npmScope : options.name;
|
const npmScope = options && options.npmScope ? options.npmScope : options.name;
|
||||||
|
|
||||||
updateJsonFile('tslint.json', (json) => {
|
updateJsonFile('tslint.json', json => {
|
||||||
['no-trailing-whitespace', 'one-line', 'quotemark', 'typedef-whitespace', 'whitespace'].forEach(key => {
|
['no-trailing-whitespace', 'one-line', 'quotemark', 'typedef-whitespace', 'whitespace'].forEach(key => {
|
||||||
json[key] = undefined;
|
json[key] = undefined;
|
||||||
});
|
});
|
||||||
json['nx-enforce-module-boundaries'] = [true, {'npmScope': npmScope, 'lazyLoad': []}];
|
json['nx-enforce-module-boundaries'] = [true, { npmScope: npmScope, lazyLoad: [] }];
|
||||||
});
|
});
|
||||||
return host;
|
return host;
|
||||||
};
|
};
|
||||||
@ -138,8 +155,9 @@ function updateProtractorConf() {
|
|||||||
throw new Error('Cannot find protractor.conf.js');
|
throw new Error('Cannot find protractor.conf.js');
|
||||||
}
|
}
|
||||||
const protractorConf = host.read('protractor.conf.js')!.toString('utf-8');
|
const protractorConf = host.read('protractor.conf.js')!.toString('utf-8');
|
||||||
const updatedConf = protractorConf.replace(`./e2e/**/*.e2e-spec.ts`, `./apps/**/*.e2e-spec.ts`)
|
const updatedConf = protractorConf
|
||||||
.replace(`e2e/tsconfig.e2e.json`, `./tsconfig.e2e.json`);
|
.replace(`./e2e/**/*.e2e-spec.ts`, `./apps/**/*.e2e-spec.ts`)
|
||||||
|
.replace(`e2e/tsconfig.e2e.json`, `./tsconfig.e2e.json`);
|
||||||
|
|
||||||
host.overwrite('protractor.conf.js', updatedConf);
|
host.overwrite('protractor.conf.js', updatedConf);
|
||||||
|
|
||||||
@ -186,12 +204,14 @@ function dedup(array: any[]): any[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function(schema: Schema): Rule {
|
export default function(schema: Schema): Rule {
|
||||||
const options = {...schema, name: toFileName(schema.name)};
|
const options = { ...schema, name: toFileName(schema.name) };
|
||||||
return chain([
|
return chain([
|
||||||
moveFiles(options), branchAndMerge(chain([
|
moveFiles(options),
|
||||||
mergeWith(apply(url('./files'), [])),
|
branchAndMerge(chain([mergeWith(apply(url('./files'), []))])),
|
||||||
])),
|
updatePackageJson(),
|
||||||
updatePackageJson(), updateAngularCLIJson(options), updateTsConfigsJson(options), updateProtractorConf(),
|
updateAngularCLIJson(options),
|
||||||
|
updateTsConfigsJson(options),
|
||||||
|
updateProtractorConf(),
|
||||||
updateTsLintJson(options)
|
updateTsLintJson(options)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,3 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
find packages/ -iname "*.ts" | xargs -n1 clang-format -output-replacements-xml | grep -c "<replacement " >/dev/null
|
prettier --single-quote --print-width 120 --list-different '{packages,e2e}/**/*.ts'
|
||||||
if [ $? -ne 1 ]
|
|
||||||
then
|
|
||||||
echo "Please run yarn format"
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
find e2e/ -iname "*.ts" | xargs -n1 clang-format -output-replacements-xml | grep -c "<replacement " >/dev/null
|
|
||||||
if [ $? -ne 1 ]
|
|
||||||
then
|
|
||||||
echo "Please run yarn format"
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
find packages/ -iname "*.ts" | xargs clang-format -i
|
prettier --single-quote --print-width 120 --write '{packages,e2e}/**/*.ts'
|
||||||
find e2e/ -iname "*.ts" | xargs clang-format -i
|
|
||||||
|
|||||||
14
yarn.lock
14
yarn.lock
@ -968,14 +968,6 @@ circular-dependency-plugin@^3.0.0:
|
|||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-3.0.0.tgz#9b68692e35b0e3510998d0164b6ae5011bea5760"
|
resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-3.0.0.tgz#9b68692e35b0e3510998d0164b6ae5011bea5760"
|
||||||
|
|
||||||
clang-format@1.0.55:
|
|
||||||
version "1.0.55"
|
|
||||||
resolved "https://registry.yarnpkg.com/clang-format/-/clang-format-1.0.55.tgz#8031271329e27a779a5d08fc5dce24d7c52c14d5"
|
|
||||||
dependencies:
|
|
||||||
async "^1.5.2"
|
|
||||||
glob "^7.0.0"
|
|
||||||
resolve "^1.1.6"
|
|
||||||
|
|
||||||
clap@^1.0.9:
|
clap@^1.0.9:
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51"
|
resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51"
|
||||||
@ -4532,6 +4524,10 @@ preserve@^0.2.0:
|
|||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||||
|
|
||||||
|
prettier@1.7.4:
|
||||||
|
version "1.7.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.7.4.tgz#5e8624ae9363c80f95ec644584ecdf55d74f93fa"
|
||||||
|
|
||||||
pretty-error@^2.0.2:
|
pretty-error@^2.0.2:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"
|
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"
|
||||||
@ -4902,7 +4898,7 @@ resolve@1.1.7:
|
|||||||
version "1.1.7"
|
version "1.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
|
||||||
|
|
||||||
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2:
|
resolve@^1.1.7, resolve@^1.3.2:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86"
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user