Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/design/analytics.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Note: There's a limit of 20 custom dimensions.
| 12 | `Flag: --skip-tests` | `boolean` |
| 13 | `Flag: --aot` | `boolean` |
| 14 | `Flag: --minimal` | `boolean` |
| 15 | `Flag: --standalone` | `boolean` |
| 16 | `Flag: --optimization` | `boolean` |
| 17 | `Flag: --routing` | `boolean` |
| 18 | `Flag: --skip-import` | `boolean` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('<%= classify(name) %><%= classify(type) %>', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ <%= classify(name) %><%= classify(type) %> ]
<%= standalone ? 'imports' : 'declarations' %>: [ <%= classify(name) %><%= classify(type) %> ]
})
.compileComponents();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Component, OnInit<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }%><% if(changeDetection !== 'Default') { %>, ChangeDetectionStrategy<% }%> } from '@angular/core';

@Component({<% if(!skipSelector) {%>
selector: '<%= selector %>',<%}%><% if(inlineTemplate) { %>
selector: '<%= selector %>',<%}%><% if(standalone) {%>
standalone: true,<%}%><% if(inlineTemplate) { %>
template: `
<p>
<%= dasherize(name) %> works!
Expand Down
2 changes: 1 addition & 1 deletion packages/schematics/angular/component/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile {

function addDeclarationToNgModule(options: ComponentOptions): Rule {
return (host: Tree) => {
if (options.skipImport || !options.module) {
if (options.skipImport || options.standalone || !options.module) {
return host;
}

Expand Down
18 changes: 18 additions & 0 deletions packages/schematics/angular/component/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,4 +420,22 @@ describe('Component Schematic', () => {
expect(content).toMatch(/template: `(\n(.|)*){3}\n\s*`,\n/);
expect(content).toMatch(/changeDetection: ChangeDetectionStrategy.OnPush/);
});

it('should create a standalone component', async () => {
const options = { ...defaultOptions, standalone: true };
const tree = await schematicRunner.runSchematicAsync('component', options, appTree).toPromise();
const moduleContent = tree.readContent('/projects/bar/src/app/app.module.ts');
const componentContent = tree.readContent('/projects/bar/src/app/foo/foo.component.ts');
expect(componentContent).toContain('standalone: true');
expect(componentContent).toContain('class FooComponent');
expect(moduleContent).not.toContain('FooComponent');
});

it('should declare standalone components in the `imports` of a test', async () => {
const options = { ...defaultOptions, standalone: true };
const tree = await schematicRunner.runSchematicAsync('component', options, appTree).toPromise();
const testContent = tree.readContent('/projects/bar/src/app/foo/foo.component.spec.ts');
expect(testContent).toContain('imports: [ FooComponent ]');
expect(testContent).not.toContain('declarations');
});
});
6 changes: 6 additions & 0 deletions packages/schematics/angular/component/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@
"alias": "t",
"x-user-analytics": 10
},
"standalone": {
"description": "Whether the generated component is standalone.",
"type": "boolean",
"default": false,
"x-user-analytics": 15
},
"viewEncapsulation": {
"description": "The view encapsulation strategy to use in the new component.",
"enum": ["Emulated", "None", "ShadowDom"],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Directive } from '@angular/core';

@Directive({
selector: '[<%= selector %>]'
selector: '[<%= selector %>]'<% if(standalone) {%>,
standalone: true<%}%>
})
export class <%= classify(name) %>Directive {

Expand Down
2 changes: 1 addition & 1 deletion packages/schematics/angular/directive/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { Schema as DirectiveOptions } from './schema';

function addDeclarationToNgModule(options: DirectiveOptions): Rule {
return (host: Tree) => {
if (options.skipImport || !options.module) {
if (options.skipImport || options.standalone || !options.module) {
return host;
}

Expand Down
10 changes: 10 additions & 0 deletions packages/schematics/angular/directive/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,14 @@ describe('Directive Schematic', () => {
expect(files).toContain('/projects/bar/src/app/foo.directive.ts');
expect(files).not.toContain('/projects/bar/src/app/foo.directive.spec.ts');
});

it('should create a standalone directive', async () => {
const options = { ...defaultOptions, standalone: true };
const tree = await schematicRunner.runSchematicAsync('directive', options, appTree).toPromise();
const moduleContent = tree.readContent('/projects/bar/src/app/app.module.ts');
const directiveContent = tree.readContent('/projects/bar/src/app/foo.directive.ts');
expect(directiveContent).toContain('standalone: true');
expect(directiveContent).toContain('class FooDirective');
expect(moduleContent).not.toContain('FooDirective');
});
});
6 changes: 6 additions & 0 deletions packages/schematics/angular/directive/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
"format": "html-selector",
"description": "The HTML selector to use for this directive."
},
"standalone": {
"description": "Whether the generated directive is standalone.",
"type": "boolean",
"default": false,
"x-user-analytics": 15
},
"flat": {
"type": "boolean",
"description": "When true (the default), creates the new files at the top level of the current project.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: '<%= camelize(name) %>'
name: '<%= camelize(name) %>'<% if(standalone) {%>,
standalone: true<%}%>
})
export class <%= classify(name) %>Pipe implements PipeTransform {

Expand Down
2 changes: 1 addition & 1 deletion packages/schematics/angular/pipe/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { Schema as PipeOptions } from './schema';

function addDeclarationToNgModule(options: PipeOptions): Rule {
return (host: Tree) => {
if (options.skipImport || !options.module) {
if (options.skipImport || options.standalone || !options.module) {
return host;
}

Expand Down
10 changes: 10 additions & 0 deletions packages/schematics/angular/pipe/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,14 @@ describe('Pipe Schematic', () => {
expect(files).not.toContain('/projects/bar/src/app/foo.pipe.spec.ts');
expect(files).toContain('/projects/bar/src/app/foo.pipe.ts');
});

it('should create a standalone pipe', async () => {
const options = { ...defaultOptions, standalone: true };
const tree = await schematicRunner.runSchematicAsync('pipe', options, appTree).toPromise();
const moduleContent = tree.readContent('/projects/bar/src/app/app.module.ts');
const pipeContent = tree.readContent('/projects/bar/src/app/foo.pipe.ts');
expect(pipeContent).toContain('standalone: true');
expect(pipeContent).toContain('class FooPipe');
expect(moduleContent).not.toContain('FooPipe');
});
});
6 changes: 6 additions & 0 deletions packages/schematics/angular/pipe/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@
"description": "Do not import this pipe into the owning NgModule.",
"x-user-analytics": 18
},
"standalone": {
"description": "Whether the generated pipe is standalone.",
"type": "boolean",
"default": false,
"x-user-analytics": 15
},
"module": {
"type": "string",
"description": "The declaring NgModule.",
Expand Down
4 changes: 2 additions & 2 deletions packages/schematics/angular/utility/find-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface ModuleOptions {
skipImport?: boolean;
moduleExt?: string;
routingModuleExt?: string;
standalone?: boolean;
}

export const MODULE_EXT = '.module.ts';
Expand All @@ -26,8 +27,7 @@ export const ROUTING_MODULE_EXT = '-routing.module.ts';
* Find the module referred by a set of options passed to the schematics.
*/
export function findModuleFromOptions(host: Tree, options: ModuleOptions): Path | undefined {
// eslint-disable-next-line no-prototype-builtins
if (options.hasOwnProperty('skipImport') && options.skipImport) {
if (options.standalone || options.skipImport) {
return undefined;
}

Expand Down