feat(angular): add backwards compat support for the ngrx generator (#14348)
This commit is contained in:
parent
c94ac41f56
commit
295547b3a9
@ -32,12 +32,12 @@
|
|||||||
},
|
},
|
||||||
"parent": {
|
"parent": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The path to the `NgModule` or the `Routes` definition file (for Standalone API usage) where the feature state will be registered. The host directory will create/use the new state directory.",
|
"description": "The path to the `NgModule` or the `Routes` definition file (for Standalone API usage) where the feature state will be registered. _Note: The Standalone API usage is only supported in Angular versions >= 14.1.0_.",
|
||||||
"x-prompt": "What is the path to the module or Routes definition where this NgRx state should be registered?"
|
"x-prompt": "What is the path to the module or Routes definition where this NgRx state should be registered?"
|
||||||
},
|
},
|
||||||
"route": {
|
"route": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The route that the Standalone NgRx Providers should be added to.",
|
"description": "The route that the Standalone NgRx Providers should be added to. _Note: This is only supported in Angular versions >= 14.1.0_.",
|
||||||
"default": "''"
|
"default": "''"
|
||||||
},
|
},
|
||||||
"directory": {
|
"directory": {
|
||||||
|
|||||||
@ -40,7 +40,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular-devkit/schematics": "~15.1.0",
|
"@angular-devkit/schematics": "~15.1.0",
|
||||||
"@nguniversal/builders": "~15.0.0",
|
|
||||||
"@nrwl/cypress": "file:../cypress",
|
"@nrwl/cypress": "file:../cypress",
|
||||||
"@nrwl/devkit": "file:../devkit",
|
"@nrwl/devkit": "file:../devkit",
|
||||||
"@nrwl/jest": "file:../jest",
|
"@nrwl/jest": "file:../jest",
|
||||||
@ -61,6 +60,15 @@
|
|||||||
"webpack": "^5.75.0",
|
"webpack": "^5.75.0",
|
||||||
"webpack-merge": "5.7.3"
|
"webpack-merge": "5.7.3"
|
||||||
},
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@nguniversal/builders": "~15.0.0",
|
||||||
|
"rxjs": "^6.5.3 || ^7.5.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@nguniversal/builders": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -604,3 +604,117 @@ import { UsersEffects } from './+state/users.effects';
|
|||||||
import { UsersFacade } from './+state/users.facade';
|
import { UsersFacade } from './+state/users.facade';
|
||||||
export const appRoutes: Routes = [{ path: '', component: NxWelcomeComponent , providers: [UsersFacade, provideState(fromUsers.USERS_FEATURE_KEY, fromUsers.usersReducer), provideEffects(UsersEffects)]}];"
|
export const appRoutes: Routes = [{ path: '', component: NxWelcomeComponent , providers: [UsersFacade, provideState(fromUsers.USERS_FEATURE_KEY, fromUsers.usersReducer), provideEffects(UsersEffects)]}];"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`ngrx angular v14 support should generate the ngrx effects using "inject" for versions >= 14.1.0 1`] = `
|
||||||
|
"import { Injectable, inject } from '@angular/core';
|
||||||
|
import { createEffect, Actions, ofType } from '@ngrx/effects';
|
||||||
|
|
||||||
|
import * as UsersActions from './users.actions';
|
||||||
|
import * as UsersFeature from './users.reducer';
|
||||||
|
|
||||||
|
import {switchMap, catchError, of} from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UsersEffects {
|
||||||
|
private actions$ = inject(Actions);
|
||||||
|
|
||||||
|
init$ = createEffect(() => this.actions$.pipe(
|
||||||
|
ofType(UsersActions.initUsers),
|
||||||
|
switchMap(() => of(UsersActions.loadUsersSuccess({ users: [] }))),
|
||||||
|
catchError((error) => {
|
||||||
|
console.error('Error', error);
|
||||||
|
return of(UsersActions.loadUsersFailure({ error }));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`ngrx angular v14 support should generate the ngrx effects with no usage of "inject" 1`] = `
|
||||||
|
"import { Injectable } from '@angular/core';
|
||||||
|
import { createEffect, Actions, ofType } from '@ngrx/effects';
|
||||||
|
|
||||||
|
import * as UsersActions from './users.actions';
|
||||||
|
import * as UsersFeature from './users.reducer';
|
||||||
|
|
||||||
|
import {switchMap, catchError, of} from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UsersEffects {
|
||||||
|
init$ = createEffect(() => this.actions$.pipe(
|
||||||
|
ofType(UsersActions.initUsers),
|
||||||
|
switchMap(() => of(UsersActions.loadUsersSuccess({ users: [] }))),
|
||||||
|
catchError((error) => {
|
||||||
|
console.error('Error', error);
|
||||||
|
return of(UsersActions.loadUsersFailure({ error }));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
constructor(private readonly actions$: Actions) {}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`ngrx angular v14 support should generate the ngrx facade using "inject" for versions >= 14.1.0 1`] = `
|
||||||
|
"import { Injectable, inject } from '@angular/core';
|
||||||
|
import { select, Store, Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
import * as UsersActions from './users.actions';
|
||||||
|
import * as UsersFeature from './users.reducer';
|
||||||
|
import * as UsersSelectors from './users.selectors';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UsersFacade {
|
||||||
|
private readonly store = inject(Store);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine pieces of state using createSelector,
|
||||||
|
* and expose them as observables through the facade.
|
||||||
|
*/
|
||||||
|
loaded$ = this.store.pipe(select(UsersSelectors.selectUsersLoaded));
|
||||||
|
allUsers$ = this.store.pipe(select(UsersSelectors.selectAllUsers));
|
||||||
|
selectedUsers$ = this.store.pipe(select(UsersSelectors.selectEntity));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the initialization action to perform one
|
||||||
|
* or more tasks in your Effects.
|
||||||
|
*/
|
||||||
|
init() {
|
||||||
|
this.store.dispatch(UsersActions.initUsers());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`ngrx angular v14 support should generate the ngrx facade with no usage of "inject" 1`] = `
|
||||||
|
"import { Injectable } from '@angular/core';
|
||||||
|
import { select, Store, Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
import * as UsersActions from './users.actions';
|
||||||
|
import * as UsersFeature from './users.reducer';
|
||||||
|
import * as UsersSelectors from './users.selectors';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UsersFacade {
|
||||||
|
/**
|
||||||
|
* Combine pieces of state using createSelector,
|
||||||
|
* and expose them as observables through the facade.
|
||||||
|
*/
|
||||||
|
loaded$ = this.store.pipe(select(UsersSelectors.selectUsersLoaded));
|
||||||
|
allUsers$ = this.store.pipe(select(UsersSelectors.selectAllUsers));
|
||||||
|
selectedUsers$ = this.store.pipe(select(UsersSelectors.selectEntity));
|
||||||
|
|
||||||
|
constructor(private readonly store: Store) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the initialization action to perform one
|
||||||
|
* or more tasks in your Effects.
|
||||||
|
*/
|
||||||
|
init() {
|
||||||
|
this.store.dispatch(UsersActions.initUsers());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { createEffect, Actions, ofType } from '@ngrx/effects';
|
||||||
|
|
||||||
|
import * as <%= className %>Actions from './<%= fileName %>.actions';
|
||||||
|
import * as <%= className %>Feature from './<%= fileName %>.reducer';
|
||||||
|
|
||||||
|
import {switchMap, catchError, of} from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class <%= className %>Effects {
|
||||||
|
init$ = createEffect(() => this.actions$.pipe(
|
||||||
|
ofType(<%= className %>Actions.init<%= className %>),
|
||||||
|
switchMap(() => of(<%= className %>Actions.load<%= className %>Success({ <%= propertyName %>: [] }))),
|
||||||
|
catchError((error) => {
|
||||||
|
console.error('Error', error);
|
||||||
|
return of(<%= className %>Actions.load<%= className %>Failure({ error }));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
constructor(private readonly actions$: Actions) {}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { select, Store, Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
import * as <%= className %>Actions from './<%= fileName %>.actions';
|
||||||
|
import * as <%= className %>Feature from './<%= fileName %>.reducer';
|
||||||
|
import * as <%= className %>Selectors from './<%= fileName %>.selectors';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class <%= className %>Facade {
|
||||||
|
/**
|
||||||
|
* Combine pieces of state using createSelector,
|
||||||
|
* and expose them as observables through the facade.
|
||||||
|
*/
|
||||||
|
loaded$ = this.store.pipe(select(<%= className %>Selectors.select<%= className %>Loaded));
|
||||||
|
all<%= className %>$ = this.store.pipe(select(<%= className %>Selectors.selectAll<%= className %>));
|
||||||
|
selected<%= className %>$ = this.store.pipe(select(<%= className %>Selectors.selectEntity));
|
||||||
|
|
||||||
|
constructor(private readonly store: Store) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the initialization action to perform one
|
||||||
|
* or more tasks in your Effects.
|
||||||
|
*/
|
||||||
|
init() {
|
||||||
|
this.store.dispatch(<%= className %>Actions.init<%= className %>());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,11 +1,10 @@
|
|||||||
import type { GeneratorCallback, Tree } from '@nrwl/devkit';
|
import type { GeneratorCallback, Tree } from '@nrwl/devkit';
|
||||||
import { addDependenciesToPackageJson, readJson } from '@nrwl/devkit';
|
import { addDependenciesToPackageJson, readJson } from '@nrwl/devkit';
|
||||||
import { gte } from 'semver';
|
|
||||||
import {
|
|
||||||
ngrxVersion,
|
|
||||||
rxjsVersion as defaultRxjsVersion,
|
|
||||||
} from '../../../utils/versions';
|
|
||||||
import { checkAndCleanWithSemver } from '@nrwl/workspace/src/utilities/version-utils';
|
import { checkAndCleanWithSemver } from '@nrwl/workspace/src/utilities/version-utils';
|
||||||
|
import { gte } from 'semver';
|
||||||
|
import { getPkgVersionForAngularMajorVersion } from '../../../utils/version-utils';
|
||||||
|
import { rxjsVersion as defaultRxjsVersion } from '../../../utils/versions';
|
||||||
|
import { getInstalledAngularMajorVersion } from '../../utils/angular-version-utils';
|
||||||
|
|
||||||
export function addNgRxToPackageJson(tree: Tree): GeneratorCallback {
|
export function addNgRxToPackageJson(tree: Tree): GeneratorCallback {
|
||||||
let rxjsVersion: string;
|
let rxjsVersion: string;
|
||||||
@ -18,6 +17,13 @@ export function addNgRxToPackageJson(tree: Tree): GeneratorCallback {
|
|||||||
rxjsVersion = checkAndCleanWithSemver('rxjs', defaultRxjsVersion);
|
rxjsVersion = checkAndCleanWithSemver('rxjs', defaultRxjsVersion);
|
||||||
}
|
}
|
||||||
const jasmineMarblesVersion = gte(rxjsVersion, '7.0.0') ? '~0.9.1' : '~0.8.3';
|
const jasmineMarblesVersion = gte(rxjsVersion, '7.0.0') ? '~0.9.1' : '~0.8.3';
|
||||||
|
|
||||||
|
const angularMajorVersion = getInstalledAngularMajorVersion(tree);
|
||||||
|
const ngrxVersion = getPkgVersionForAngularMajorVersion(
|
||||||
|
'ngrxVersion',
|
||||||
|
angularMajorVersion
|
||||||
|
);
|
||||||
|
|
||||||
return addDependenciesToPackageJson(
|
return addDependenciesToPackageJson(
|
||||||
tree,
|
tree,
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import type { Tree } from '@nrwl/devkit';
|
import type { Tree } from '@nrwl/devkit';
|
||||||
import { generateFiles, joinPathFragments, names } from '@nrwl/devkit';
|
import { generateFiles, joinPathFragments, names } from '@nrwl/devkit';
|
||||||
|
import { lt } from 'semver';
|
||||||
|
import { getInstalledAngularVersion } from '../../utils/angular-version-utils';
|
||||||
import { NormalizedNgRxGeneratorOptions } from './normalize-options';
|
import { NormalizedNgRxGeneratorOptions } from './normalize-options';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,7 +16,7 @@ export function generateNgrxFilesFromTemplates(
|
|||||||
|
|
||||||
generateFiles(
|
generateFiles(
|
||||||
tree,
|
tree,
|
||||||
joinPathFragments(__dirname, '..', 'files'),
|
joinPathFragments(__dirname, '..', 'files', 'latest'),
|
||||||
options.parentDirectory,
|
options.parentDirectory,
|
||||||
{
|
{
|
||||||
...options,
|
...options,
|
||||||
@ -23,6 +25,20 @@ export function generateNgrxFilesFromTemplates(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const angularVersion = getInstalledAngularVersion(tree);
|
||||||
|
if (lt(angularVersion, '14.1.0')) {
|
||||||
|
generateFiles(
|
||||||
|
tree,
|
||||||
|
joinPathFragments(__dirname, '..', 'files', 'no-inject'),
|
||||||
|
options.parentDirectory,
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
...projectNames,
|
||||||
|
tmpl: '',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.facade) {
|
if (!options.facade) {
|
||||||
tree.delete(
|
tree.delete(
|
||||||
joinPathFragments(
|
joinPathFragments(
|
||||||
|
|||||||
@ -3,3 +3,4 @@ export { addImportsToModule } from './add-imports-to-module';
|
|||||||
export { addNgRxToPackageJson } from './add-ngrx-to-package-json';
|
export { addNgRxToPackageJson } from './add-ngrx-to-package-json';
|
||||||
export { generateNgrxFilesFromTemplates } from './generate-files';
|
export { generateNgrxFilesFromTemplates } from './generate-files';
|
||||||
export { normalizeOptions } from './normalize-options';
|
export { normalizeOptions } from './normalize-options';
|
||||||
|
export { validateOptions } from './validate-options';
|
||||||
|
|||||||
41
packages/angular/src/generators/ngrx/lib/validate-options.ts
Normal file
41
packages/angular/src/generators/ngrx/lib/validate-options.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import type { Tree } from '@nrwl/devkit';
|
||||||
|
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||||
|
import { lt } from 'semver';
|
||||||
|
import { getInstalledAngularVersion } from '../../utils/angular-version-utils';
|
||||||
|
import type { NgRxGeneratorOptions } from '../schema';
|
||||||
|
|
||||||
|
export function validateOptions(
|
||||||
|
tree: Tree,
|
||||||
|
options: NgRxGeneratorOptions
|
||||||
|
): void {
|
||||||
|
if (!options.module && !options.parent) {
|
||||||
|
throw new Error('Please provide a value for "--parent"!');
|
||||||
|
}
|
||||||
|
if (options.module && !tree.exists(options.module)) {
|
||||||
|
throw new Error(`Module does not exist: ${options.module}.`);
|
||||||
|
}
|
||||||
|
if (options.parent && !tree.exists(options.parent)) {
|
||||||
|
throw new Error(`Parent does not exist: ${options.parent}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const angularVersion = getInstalledAngularVersion(tree);
|
||||||
|
const parentPath = options.parent ?? options.module;
|
||||||
|
if (parentPath && lt(angularVersion, '14.1.0')) {
|
||||||
|
const parentContent = tree.read(parentPath, 'utf-8');
|
||||||
|
const ast = tsquery.ast(parentContent);
|
||||||
|
|
||||||
|
const NG_MODULE_DECORATOR_SELECTOR =
|
||||||
|
'ClassDeclaration > Decorator > CallExpression:has(Identifier[name=NgModule])';
|
||||||
|
const nodes = tsquery(ast, NG_MODULE_DECORATOR_SELECTOR, {
|
||||||
|
visitAllChildren: true,
|
||||||
|
});
|
||||||
|
if (nodes.length === 0) {
|
||||||
|
throw new Error(
|
||||||
|
`The provided parent path "${parentPath}" does not contain an "NgModule". ` +
|
||||||
|
'Please make sure to provide a path to an "NgModule" where the state will be registered. ' +
|
||||||
|
'If you are trying to use a "Routes" definition file (for Standalone API usage), ' +
|
||||||
|
'please note this is not supported in Angular versions lower than 14.1.0.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ import {
|
|||||||
getAppConfig,
|
getAppConfig,
|
||||||
getLibConfig,
|
getLibConfig,
|
||||||
} from '../../utils/nx-devkit/testing';
|
} from '../../utils/nx-devkit/testing';
|
||||||
import { ngrxVersion } from '../../utils/versions';
|
import { ngrxVersion, versions } from '../../utils/versions';
|
||||||
import { ngrxGenerator } from './ngrx';
|
import { ngrxGenerator } from './ngrx';
|
||||||
import applicationGenerator from '../application/application';
|
import applicationGenerator from '../application/application';
|
||||||
import type { NgRxGeneratorOptions } from './schema';
|
import type { NgRxGeneratorOptions } from './schema';
|
||||||
@ -588,4 +588,115 @@ describe('ngrx', () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('angular v14 support', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
|
await applicationGenerator(tree, { name: 'myapp' });
|
||||||
|
devkit.updateJson(tree, 'package.json', (json) => ({
|
||||||
|
...json,
|
||||||
|
dependencies: {
|
||||||
|
...json.dependencies,
|
||||||
|
'@angular/core': '14.0.0',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should install the ngrx 14 packages', async () => {
|
||||||
|
await ngrxGenerator(tree, defaultOptions);
|
||||||
|
|
||||||
|
const packageJson = devkit.readJson(tree, 'package.json');
|
||||||
|
expect(packageJson.dependencies['@ngrx/store']).toEqual(
|
||||||
|
versions.angularV14.ngrxVersion
|
||||||
|
);
|
||||||
|
expect(packageJson.dependencies['@ngrx/effects']).toEqual(
|
||||||
|
versions.angularV14.ngrxVersion
|
||||||
|
);
|
||||||
|
expect(packageJson.dependencies['@ngrx/entity']).toEqual(
|
||||||
|
versions.angularV14.ngrxVersion
|
||||||
|
);
|
||||||
|
expect(packageJson.dependencies['@ngrx/router-store']).toEqual(
|
||||||
|
versions.angularV14.ngrxVersion
|
||||||
|
);
|
||||||
|
expect(packageJson.dependencies['@ngrx/component-store']).toEqual(
|
||||||
|
versions.angularV14.ngrxVersion
|
||||||
|
);
|
||||||
|
expect(packageJson.devDependencies['@ngrx/schematics']).toEqual(
|
||||||
|
versions.angularV14.ngrxVersion
|
||||||
|
);
|
||||||
|
expect(packageJson.devDependencies['@ngrx/store-devtools']).toEqual(
|
||||||
|
versions.angularV14.ngrxVersion
|
||||||
|
);
|
||||||
|
expect(packageJson.devDependencies['jasmine-marbles']).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate the ngrx effects with no usage of "inject"', async () => {
|
||||||
|
await ngrxGenerator(tree, defaultOptions);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tree.read('apps/myapp/src/app/+state/users.effects.ts', 'utf-8')
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate the ngrx effects using "inject" for versions >= 14.1.0', async () => {
|
||||||
|
devkit.updateJson(tree, 'package.json', (json) => ({
|
||||||
|
...json,
|
||||||
|
dependencies: {
|
||||||
|
...json.dependencies,
|
||||||
|
'@angular/core': '14.1.0',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
await ngrxGenerator(tree, defaultOptions);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tree.read('apps/myapp/src/app/+state/users.effects.ts', 'utf-8')
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate the ngrx facade with no usage of "inject"', async () => {
|
||||||
|
await ngrxGenerator(tree, { ...defaultOptions, facade: true });
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tree.read('apps/myapp/src/app/+state/users.facade.ts', 'utf-8')
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should generate the ngrx facade using "inject" for versions >= 14.1.0', async () => {
|
||||||
|
devkit.updateJson(tree, 'package.json', (json) => ({
|
||||||
|
...json,
|
||||||
|
dependencies: {
|
||||||
|
...json.dependencies,
|
||||||
|
'@angular/core': '14.1.0',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
await ngrxGenerator(tree, { ...defaultOptions, facade: true });
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tree.read('apps/myapp/src/app/+state/users.facade.ts', 'utf-8')
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw when the provided parent does not have an NgModule', async () => {
|
||||||
|
const parentPath = 'apps/myapp/src/app/app.routes.ts';
|
||||||
|
tree.write(
|
||||||
|
parentPath,
|
||||||
|
`import { Routes } from '@angular/router';
|
||||||
|
import { NxWelcomeComponent } from './nx-welcome.component';
|
||||||
|
export const appRoutes: Routes = [{ path: '', component: NxWelcomeComponent }];`
|
||||||
|
);
|
||||||
|
|
||||||
|
// ACT & ASSERT
|
||||||
|
await expect(
|
||||||
|
ngrxGenerator(tree, {
|
||||||
|
...defaultStandaloneOptions,
|
||||||
|
parent: parentPath,
|
||||||
|
})
|
||||||
|
).rejects.toThrowError(
|
||||||
|
`The provided parent path "${parentPath}" does not contain an "NgModule".`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
addNgRxToPackageJson,
|
addNgRxToPackageJson,
|
||||||
generateNgrxFilesFromTemplates,
|
generateNgrxFilesFromTemplates,
|
||||||
normalizeOptions,
|
normalizeOptions,
|
||||||
|
validateOptions,
|
||||||
} from './lib';
|
} from './lib';
|
||||||
import type { NgRxGeneratorOptions } from './schema';
|
import type { NgRxGeneratorOptions } from './schema';
|
||||||
|
|
||||||
@ -13,18 +14,7 @@ export async function ngrxGenerator(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
schema: NgRxGeneratorOptions
|
schema: NgRxGeneratorOptions
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
if (!schema.module && !schema.parent) {
|
validateOptions(tree, schema);
|
||||||
throw new Error('Please provide a value for `--parent`!');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.module && !tree.exists(schema.module)) {
|
|
||||||
throw new Error(`Module does not exist: ${schema.module}.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.parent && !tree.exists(schema.parent)) {
|
|
||||||
throw new Error(`Parent does not exist: ${schema.parent}.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const options = normalizeOptions(schema);
|
const options = normalizeOptions(schema);
|
||||||
|
|
||||||
if (!options.minimal || !options.root) {
|
if (!options.minimal || !options.root) {
|
||||||
|
|||||||
@ -32,12 +32,12 @@
|
|||||||
},
|
},
|
||||||
"parent": {
|
"parent": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The path to the `NgModule` or the `Routes` definition file (for Standalone API usage) where the feature state will be registered. The host directory will create/use the new state directory.",
|
"description": "The path to the `NgModule` or the `Routes` definition file (for Standalone API usage) where the feature state will be registered. _Note: The Standalone API usage is only supported in Angular versions >= 14.1.0_.",
|
||||||
"x-prompt": "What is the path to the module or Routes definition where this NgRx state should be registered?"
|
"x-prompt": "What is the path to the module or Routes definition where this NgRx state should be registered?"
|
||||||
},
|
},
|
||||||
"route": {
|
"route": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The route that the Standalone NgRx Providers should be added to.",
|
"description": "The route that the Standalone NgRx Providers should be added to. _Note: This is only supported in Angular versions >= 14.1.0_.",
|
||||||
"default": "''"
|
"default": "''"
|
||||||
},
|
},
|
||||||
"directory": {
|
"directory": {
|
||||||
|
|||||||
13
packages/angular/src/utils/version-utils.ts
Normal file
13
packages/angular/src/utils/version-utils.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { coerce, major } from 'semver';
|
||||||
|
import { angularVersion, versions as versionsMap } from './versions';
|
||||||
|
import * as versions from './versions';
|
||||||
|
|
||||||
|
export function getPkgVersionForAngularMajorVersion(
|
||||||
|
pkgVersionName: Exclude<keyof typeof versions, 'versions'>,
|
||||||
|
angularMajorVersion: number
|
||||||
|
): string {
|
||||||
|
return angularMajorVersion < major(coerce(angularVersion))
|
||||||
|
? versionsMap[`angularV${angularMajorVersion}`]?.[pkgVersionName] ??
|
||||||
|
versions[pkgVersionName]
|
||||||
|
: versions[pkgVersionName];
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user