cleanup(angular): replace wrapAngularDevkitSchematics for component (#15791)

This commit is contained in:
Colum Ferry 2023-03-22 10:22:19 +00:00 committed by GitHub
parent 7cb3a3f333
commit 4dbe6a5d5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 215 additions and 104 deletions

View File

@ -28,6 +28,11 @@
"$default": { "$source": "argv", "index": 0 }, "$default": { "$source": "argv", "index": 0 },
"x-prompt": "What name would you like to use for the component?" "x-prompt": "What name would you like to use for the component?"
}, },
"prefix": {
"type": "string",
"description": "The prefix to apply to the generated component selector.",
"alias": "p"
},
"displayBlock": { "displayBlock": {
"description": "Specifies if the style will contain `:host { display: block; }`.", "description": "Specifies if the style will contain `:host { display: block; }`.",
"type": "boolean", "type": "boolean",

View File

@ -4,13 +4,11 @@ exports[`component Generator --flat should create the component correctly and ex
"import { Component } from '@angular/core'; "import { Component } from '@angular/core';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;
@ -18,13 +16,11 @@ exports[`component Generator --flat should create the component correctly and no
"import { Component } from '@angular/core'; "import { Component } from '@angular/core';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;
@ -32,13 +28,11 @@ exports[`component Generator --path should create the component correctly and ex
"import { Component } from '@angular/core'; "import { Component } from '@angular/core';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;
@ -46,13 +40,11 @@ exports[`component Generator secondary entry points should create the component
"import { Component } from '@angular/core'; "import { Component } from '@angular/core';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;
@ -65,13 +57,11 @@ exports[`component Generator should create the component correctly and export it
"import { Component } from '@angular/core'; "import { Component } from '@angular/core';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;
@ -85,15 +75,13 @@ exports[`component Generator should create the component correctly and export it
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
standalone: true, standalone: true,
imports: [CommonModule], imports: [CommonModule],
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;
@ -101,13 +89,11 @@ exports[`component Generator should create the component correctly and not expor
"import { Component } from '@angular/core'; "import { Component } from '@angular/core';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;
@ -116,15 +102,13 @@ exports[`component Generator should create the component correctly and not expor
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
standalone: true, standalone: true,
imports: [CommonModule], imports: [CommonModule],
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;
@ -132,13 +116,11 @@ exports[`component Generator should create the component correctly and not expor
"import { Component } from '@angular/core'; "import { Component } from '@angular/core';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;
@ -146,12 +128,10 @@ exports[`component Generator should create the component correctly but not expor
"import { Component } from '@angular/core'; "import { Component } from '@angular/core';
@Component({ @Component({
selector: 'example', selector: 'proj-example',
templateUrl: './example.component.html', templateUrl: './example.component.html',
styleUrls: ['./example.component.css'] styleUrls: ['./example.component.css']
}) })
export class ExampleComponent { export class ExampleComponent {}
}
" "
`; `;

View File

@ -1,11 +1,20 @@
import type { Tree } from '@nrwl/devkit'; import type { Tree } from '@nrwl/devkit';
import { formatFiles, stripIndents } from '@nrwl/devkit'; import {
formatFiles,
generateFiles,
joinPathFragments,
names,
readNxJson,
stripIndents,
} from '@nrwl/devkit';
import { lt } from 'semver'; import { lt } from 'semver';
import { checkPathUnderProjectRoot } from '../utils/path'; import { checkPathUnderProjectRoot } from '../utils/path';
import { getInstalledAngularVersionInfo } from '../utils/version-utils'; import { getInstalledAngularVersionInfo } from '../utils/version-utils';
import { exportComponentInEntryPoint } from './lib/component'; import { exportComponentInEntryPoint } from './lib/component';
import { normalizeOptions } from './lib/normalize-options'; import { normalizeOptions } from './lib/normalize-options';
import type { Schema } from './schema'; import type { Schema } from './schema';
import { addToNgModule } from '../utils';
import { findModuleFromOptions } from './lib/module';
export async function componentGenerator(tree: Tree, rawOptions: Schema) { export async function componentGenerator(tree: Tree, rawOptions: Schema) {
const installedAngularVersionInfo = getInstalledAngularVersionInfo(tree); const installedAngularVersionInfo = getInstalledAngularVersionInfo(tree);
@ -19,20 +28,105 @@ export async function componentGenerator(tree: Tree, rawOptions: Schema) {
} }
const options = await normalizeOptions(tree, rawOptions); const options = await normalizeOptions(tree, rawOptions);
const { projectSourceRoot, ...schematicOptions } = options;
checkPathUnderProjectRoot(tree, options.project, options.path); checkPathUnderProjectRoot(tree, options.project, options.path);
const { wrapAngularDevkitSchematic } = require('@nrwl/devkit/ngcli-adapter'); const pathToGenerate = options.flat
const angularComponentSchematic = wrapAngularDevkitSchematic( ? joinPathFragments(__dirname, './files/__fileName__')
'@schematics/angular', : joinPathFragments(__dirname, './files');
'component'
); const componentNames = names(options.name);
await angularComponentSchematic(tree, schematicOptions); const typeNames = names(options.type);
const selector =
options.selector ||
buildSelector(tree, componentNames.fileName, options.prefix);
generateFiles(tree, pathToGenerate, options.path, {
fileName: componentNames.fileName,
className: componentNames.className,
type: typeNames.fileName,
typeClassName: typeNames.className,
style: options.style,
inlineStyle: options.inlineStyle,
inlineTemplate: options.inlineTemplate,
standalone: options.standalone,
skipSelector: options.skipSelector,
changeDetection: options.changeDetection,
viewEncapsulation: options.viewEncapsulation,
displayBlock: options.displayBlock,
selector,
tpl: '',
});
if (options.skipTests) {
const pathToSpecFile = joinPathFragments(
options.path,
`${!options.flat ? `${componentNames.fileName}/` : ``}${
componentNames.fileName
}.${typeNames.fileName}.spec.ts`
);
tree.delete(pathToSpecFile);
}
if (options.inlineTemplate) {
const pathToTemplateFile = joinPathFragments(
options.path,
`${!options.flat ? `${componentNames.fileName}/` : ``}${
componentNames.fileName
}.${typeNames.fileName}.html`
);
tree.delete(pathToTemplateFile);
}
if (options.inlineStyle) {
const pathToStyleFile = joinPathFragments(
options.path,
`${!options.flat ? `${componentNames.fileName}/` : ``}${
componentNames.fileName
}.${typeNames.fileName}.${options.style}`
);
tree.delete(pathToStyleFile);
}
if (!options.skipImport && !options.standalone) {
const modulePath = findModuleFromOptions(
tree,
options,
options.projectRoot
);
addToNgModule(
tree,
options.path,
modulePath,
componentNames.fileName,
`${componentNames.className}${typeNames.className}`,
options.flat
? `${componentNames.fileName}.${typeNames.fileName}`
: joinPathFragments(
componentNames.fileName,
`${componentNames.fileName}.${typeNames.fileName}`
),
'declarations',
options.flat,
options.export
);
}
exportComponentInEntryPoint(tree, options); exportComponentInEntryPoint(tree, options);
await formatFiles(tree); await formatFiles(tree);
} }
function buildSelector(tree: Tree, name: string, prefix: string) {
const selectorPrefix = names(
prefix ?? readNxJson(tree).npmScope ?? 'app'
).fileName;
return names(`${selectorPrefix}-${name}`).fileName;
}
export default componentGenerator; export default componentGenerator;

View File

@ -0,0 +1,6 @@
<% if(displayBlock){ if(style != 'sass') { %>:host {
display: block;
}
<% } else { %>\:host
display: block;
<% }} %>

View File

@ -0,0 +1 @@
<p><%= fileName %> works!</p>

View File

@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { <%= className %><%= typeClassName %> } from './<%= fileName %><%= type ? '.' + type: '' %>';
describe('<%= className %><%= typeClassName %>', () => {
let component: <%= className %><%= typeClassName %>;
let fixture: ComponentFixture<<%= className %><%= typeClassName %>>;
beforeEach(async () => {
await TestBed.configureTestingModule({
<%= standalone ? 'imports' : 'declarations' %>: [ <%= className %><%= typeClassName %> ]
})
.compileComponents();
fixture = TestBed.createComponent(<%= className %><%= typeClassName %>);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,21 @@
import { <% if(changeDetection !== 'Default') { %>ChangeDetectionStrategy, <% }%>Component<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }%> } from '@angular/core';<% if(standalone) {%>
import { CommonModule } from '@angular/common';<% } %>
@Component({<% if(!skipSelector) {%>
selector: '<%= selector %>',<%}%><% if(standalone) {%>
standalone: true,
imports: [CommonModule],<%}%><% if(inlineTemplate) { %>
template: `<p><%= fileName %> works!</p>`<% } else { %>
templateUrl: './<%= fileName %><%= type ? '.' + type : '' %>.html'<% } if(inlineStyle) { %>,
styles: [<% if(displayBlock){ %>
`
:host {
display: block;
}
`<% } %>
]<% } else if (style !== 'none') { %>,
styleUrls: ['./<%= fileName %><%= type ? '.' + type : '' %>.<%= style %>']<% } %><% if(!!viewEncapsulation) { %>,
encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection !== 'Default') { %>,
changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %>
})
export class <%= className %><%= typeClassName %> {}

View File

@ -11,7 +11,7 @@ export function exportComponentInEntryPoint(
tree: Tree, tree: Tree,
schema: NormalizedSchema schema: NormalizedSchema
): void { ): void {
if (!schema.export || (schema.skipImport && !schema.standalone)) { if (!schema.export || schema.skipImport) {
return; return;
} }

View File

@ -11,16 +11,27 @@ export async function normalizeOptions(
options.project options.project
); );
const projectSourceRoot = sourceRoot ?? joinPathFragments(root, 'src'); const projectSourceRoot = sourceRoot ?? joinPathFragments(root, 'src');
const parsedName = options.name.split('/');
const name = parsedName.pop();
const namedPath = parsedName.join('/');
const path = const path =
options.path ?? options.path ??
joinPathFragments( joinPathFragments(
projectSourceRoot, projectSourceRoot,
projectType === 'application' ? 'app' : 'lib' projectType === 'application' ? 'app' : 'lib',
namedPath
); );
return { return {
...options, ...options,
name,
type: options.type ?? 'component',
changeDetection: options.changeDetection ?? 'Default',
style: options.style ?? 'css',
path, path,
projectSourceRoot, projectSourceRoot,
projectRoot: root,
}; };
} }

View File

@ -17,9 +17,11 @@ export interface Schema {
module?: string; module?: string;
skipSelector?: boolean; skipSelector?: boolean;
export?: boolean; export?: boolean;
prefix?: string;
} }
export interface NormalizedSchema extends Schema { export interface NormalizedSchema extends Schema {
path: string; path: string;
projectSourceRoot: string; projectSourceRoot: string;
projectRoot: string;
} }

View File

@ -30,6 +30,11 @@
}, },
"x-prompt": "What name would you like to use for the component?" "x-prompt": "What name would you like to use for the component?"
}, },
"prefix": {
"type": "string",
"description": "The prefix to apply to the generated component selector.",
"alias": "p"
},
"displayBlock": { "displayBlock": {
"description": "Specifies if the style will contain `:host { display: block; }`.", "description": "Specifies if the style will contain `:host { display: block; }`.",
"type": "boolean", "type": "boolean",

View File

@ -13,15 +13,12 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html', templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css'] styleUrls: ['./my-lib.component.css']
}) })
export class MyLibComponent { export class MyLibComponent {}
}
" "
`; `;
exports[`lib --angular-14 should generate a library with a standalone component as entry point with angular 14.1.0 3`] = ` exports[`lib --angular-14 should generate a library with a standalone component as entry point with angular 14.1.0 3`] = `
"import { ComponentFixture, TestBed } from '@angular/core/testing'; "import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyLibComponent } from './my-lib.component'; import { MyLibComponent } from './my-lib.component';
describe('MyLibComponent', () => { describe('MyLibComponent', () => {
@ -59,15 +56,12 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html', templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css'] styleUrls: ['./my-lib.component.css']
}) })
export class MyLibComponent { export class MyLibComponent {}
}
" "
`; `;
exports[`lib --standalone should generate a library with a standalone component and have it flat 3`] = ` exports[`lib --standalone should generate a library with a standalone component and have it flat 3`] = `
"import { ComponentFixture, TestBed } from '@angular/core/testing'; "import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyLibComponent } from './my-lib.component'; import { MyLibComponent } from './my-lib.component';
describe('MyLibComponent', () => { describe('MyLibComponent', () => {
@ -109,15 +103,12 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html', templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css'] styleUrls: ['./my-lib.component.css']
}) })
export class MyLibComponent { export class MyLibComponent {}
}
" "
`; `;
exports[`lib --standalone should generate a library with a standalone component and have it flat with routing setup 3`] = ` exports[`lib --standalone should generate a library with a standalone component and have it flat with routing setup 3`] = `
"import { ComponentFixture, TestBed } from '@angular/core/testing'; "import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyLibComponent } from './my-lib.component'; import { MyLibComponent } from './my-lib.component';
describe('MyLibComponent', () => { describe('MyLibComponent', () => {
@ -165,15 +156,12 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html', templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css'] styleUrls: ['./my-lib.component.css']
}) })
export class MyLibComponent { export class MyLibComponent {}
}
" "
`; `;
exports[`lib --standalone should generate a library with a standalone component as entry point 3`] = ` exports[`lib --standalone should generate a library with a standalone component as entry point 3`] = `
"import { ComponentFixture, TestBed } from '@angular/core/testing'; "import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyLibComponent } from './my-lib.component'; import { MyLibComponent } from './my-lib.component';
describe('MyLibComponent', () => { describe('MyLibComponent', () => {
@ -208,19 +196,13 @@ import { CommonModule } from '@angular/common';
selector: 'proj-my-lib', selector: 'proj-my-lib',
standalone: true, standalone: true,
imports: [CommonModule], imports: [CommonModule],
template: \` template: \`<p>my-lib works!</p>\`,
<p>
my-lib works!
</p>
\`,
styles: [ styles: [
], ],
encapsulation: ViewEncapsulation.ShadowDom, encapsulation: ViewEncapsulation.ShadowDom,
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class MyLibComponent { export class MyLibComponent {}
}
" "
`; `;
@ -234,17 +216,11 @@ import { CommonModule } from '@angular/common';
selector: 'proj-my-lib', selector: 'proj-my-lib',
standalone: true, standalone: true,
imports: [CommonModule], imports: [CommonModule],
template: \` template: \`<p>my-lib works!</p>\`,
<p>
my-lib works!
</p>
\`,
styles: [ styles: [
] ]
}) })
export class MyLibComponent { export class MyLibComponent {}
}
" "
`; `;
@ -258,23 +234,16 @@ import { CommonModule } from '@angular/common';
selector: 'proj-my-lib', selector: 'proj-my-lib',
standalone: true, standalone: true,
imports: [CommonModule], imports: [CommonModule],
template: \` template: \`<p>my-lib works!</p>\`,
<p>
my-lib works!
</p>
\`,
styles: [ styles: [
] ]
}) })
export class MyLibComponent { export class MyLibComponent {}
}
" "
`; `;
exports[`lib --standalone should generate a library with a standalone component as entry point following SFC pattern 3`] = ` exports[`lib --standalone should generate a library with a standalone component as entry point following SFC pattern 3`] = `
"import { ComponentFixture, TestBed } from '@angular/core/testing'; "import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyLibComponent } from './my-lib.component'; import { MyLibComponent } from './my-lib.component';
describe('MyLibComponent', () => { describe('MyLibComponent', () => {
@ -326,15 +295,12 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html', templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css'] styleUrls: ['./my-lib.component.css']
}) })
export class MyLibComponent { export class MyLibComponent {}
}
" "
`; `;
exports[`lib --standalone should generate a library with a standalone component as entry point with routing setup 4`] = ` exports[`lib --standalone should generate a library with a standalone component as entry point with routing setup 4`] = `
"import { ComponentFixture, TestBed } from '@angular/core/testing'; "import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyLibComponent } from './my-lib.component'; import { MyLibComponent } from './my-lib.component';
describe('MyLibComponent', () => { describe('MyLibComponent', () => {
@ -444,15 +410,12 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-dir-my-lib.component.html', templateUrl: './my-dir-my-lib.component.html',
styleUrls: ['./my-dir-my-lib.component.css'] styleUrls: ['./my-dir-my-lib.component.css']
}) })
export class MyDirMyLibComponent { export class MyDirMyLibComponent {}
}
" "
`; `;
exports[`lib --standalone should generate a library with a standalone component in a directory 3`] = ` exports[`lib --standalone should generate a library with a standalone component in a directory 3`] = `
"import { ComponentFixture, TestBed } from '@angular/core/testing'; "import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyDirMyLibComponent } from './my-dir-my-lib.component'; import { MyDirMyLibComponent } from './my-dir-my-lib.component';
describe('MyDirMyLibComponent', () => { describe('MyDirMyLibComponent', () => {
@ -490,15 +453,12 @@ import { CommonModule } from '@angular/common';
templateUrl: './my-lib.component.html', templateUrl: './my-lib.component.html',
styleUrls: ['./my-lib.component.css'] styleUrls: ['./my-lib.component.css']
}) })
export class MyLibComponent { export class MyLibComponent {}
}
" "
`; `;
exports[`lib --standalone should generate a library with a standalone component in a directory with a simple name 3`] = ` exports[`lib --standalone should generate a library with a standalone component in a directory with a simple name 3`] = `
"import { ComponentFixture, TestBed } from '@angular/core/testing'; "import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyLibComponent } from './my-lib.component'; import { MyLibComponent } from './my-lib.component';
describe('MyLibComponent', () => { describe('MyLibComponent', () => {

View File

@ -13,7 +13,7 @@ let tsModule: typeof import('typescript');
export function findModule(tree: Tree, path: string, module?: string) { export function findModule(tree: Tree, path: string, module?: string) {
let modulePath = ''; let modulePath = '';
let pathToSearch = path; let pathToSearch = path;
while (pathToSearch !== '/') { while (pathToSearch !== '.' && pathToSearch !== '/') {
if (module) { if (module) {
const pathToModule = joinPathFragments(pathToSearch, module); const pathToModule = joinPathFragments(pathToSearch, module);
if (tree.exists(pathToModule)) { if (tree.exists(pathToModule)) {
@ -36,6 +36,10 @@ export function findModule(tree: Tree, path: string, module?: string) {
pathToSearch = dirname(pathToSearch); pathToSearch = dirname(pathToSearch);
} }
if (modulePath === '') {
throw new Error('Could not find a declaring module file.');
}
const moduleContents = tree.read(modulePath, 'utf-8'); const moduleContents = tree.read(modulePath, 'utf-8');
if (!moduleContents.includes('@NgModule')) { if (!moduleContents.includes('@NgModule')) {
throw new Error( throw new Error(