diff --git a/packages/angular_devkit/core/src/workspace/workspace-schema.json b/packages/angular_devkit/core/src/workspace/workspace-schema.json index 223d4a8a11..71acda0c48 100644 --- a/packages/angular_devkit/core/src/workspace/workspace-schema.json +++ b/packages/angular_devkit/core/src/workspace/workspace-schema.json @@ -60,6 +60,10 @@ "type": "string", "description": "Root of the project sourcefiles." }, + "prefix": { + "type": "string", + "description": "The prefix to apply to generated selectors." + }, "cli": { "$ref": "#/definitions/tool", "default": {} @@ -91,4 +95,4 @@ "additionalProperties": true } } -} \ No newline at end of file +} diff --git a/packages/angular_devkit/core/src/workspace/workspace-schema.ts b/packages/angular_devkit/core/src/workspace/workspace-schema.ts index 3a5583c0e6..ba907905cc 100644 --- a/packages/angular_devkit/core/src/workspace/workspace-schema.ts +++ b/packages/angular_devkit/core/src/workspace/workspace-schema.ts @@ -68,6 +68,10 @@ export interface Project { * Root of the project sourcefiles. */ root: string; + /** + * The prefix to apply to generated selectors." + */ + prefix: string; /** * Tool options. */ diff --git a/packages/angular_devkit/core/src/workspace/workspace_spec.ts b/packages/angular_devkit/core/src/workspace/workspace_spec.ts index 33f54fe414..e22b3e4860 100644 --- a/packages/angular_devkit/core/src/workspace/workspace_spec.ts +++ b/packages/angular_devkit/core/src/workspace/workspace_spec.ts @@ -51,6 +51,7 @@ describe('Workspace', () => { app: { root: 'projects/app', projectType: 'application', + prefix: 'app', cli: {}, schematics: { '@schematics/angular': { diff --git a/packages/schematics/angular/application/index.ts b/packages/schematics/angular/application/index.ts index 547e650613..282e9ce47b 100644 --- a/packages/schematics/angular/application/index.ts +++ b/packages/schematics/angular/application/index.ts @@ -110,6 +110,7 @@ function addAppToWorkspaceFile(options: ApplicationOptions, workspace: Workspace const project: any = { root: projectRoot, projectType: 'application', + prefix: options.prefix || 'app', architect: { build: { builder: '@angular-devkit/build-angular:browser', diff --git a/packages/schematics/angular/application/index_spec.ts b/packages/schematics/angular/application/index_spec.ts index a804779992..018816559f 100644 --- a/packages/schematics/angular/application/index_spec.ts +++ b/packages/schematics/angular/application/index_spec.ts @@ -71,6 +71,22 @@ describe('Application Schematic', () => { expect(workspace.projects.foo).toBeDefined(); }); + it('should set the prefix to app if none is set', () => { + const options = { ...defaultOptions }; + + const tree = schematicRunner.runSchematic('application', options, workspaceTree); + const workspace = JSON.parse(tree.readContent('/angular.json')); + expect(workspace.projects.foo.prefix).toEqual('app'); + }); + + it('should set the prefix correctly', () => { + const options = { ...defaultOptions, prefix: 'pre' }; + + const tree = schematicRunner.runSchematic('application', options, workspaceTree); + const workspace = JSON.parse(tree.readContent('/angular.json')); + expect(workspace.projects.foo.prefix).toEqual('pre'); + }); + it('should handle the routing flag', () => { const options = { ...defaultOptions, routing: true }; diff --git a/packages/schematics/angular/component/index.ts b/packages/schematics/angular/component/index.ts index e95469751d..026f3a1379 100644 --- a/packages/schematics/angular/component/index.ts +++ b/packages/schematics/angular/component/index.ts @@ -92,10 +92,12 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule { } -function buildSelector(options: ComponentOptions) { +function buildSelector(options: ComponentOptions, projectPrefix: string) { let selector = strings.dasherize(options.name); if (options.prefix) { selector = `${options.prefix}-${selector}`; + } else if (projectPrefix) { + selector = `${projectPrefix}-${selector}`; } return selector; @@ -119,7 +121,7 @@ export default function(options: ComponentOptions): Rule { const parsedPath = parseName(options.path, options.name); options.name = parsedPath.name; options.path = parsedPath.path; - options.selector = options.selector || buildSelector(options); + options.selector = options.selector || buildSelector(options, project.prefix); validateName(options.name); validateHtmlSelector(options.selector); diff --git a/packages/schematics/angular/component/index_spec.ts b/packages/schematics/angular/component/index_spec.ts index b4cbb6792a..b145633db6 100644 --- a/packages/schematics/angular/component/index_spec.ts +++ b/packages/schematics/angular/component/index_spec.ts @@ -28,7 +28,6 @@ describe('Component Schematic', () => { spec: true, module: undefined, export: false, - prefix: 'app', }; @@ -197,12 +196,12 @@ describe('Component Schematic', () => { expect(content).toMatch(/selector: 'pre-foo'/); }); - it('should not use a prefix if none is passed', () => { + it('should use the default project prefix if none is passed', () => { const options = { ...defaultOptions, prefix: undefined }; const tree = schematicRunner.runSchematic('component', options, appTree); const content = tree.readContent('/projects/bar/src/app/foo/foo.component.ts'); - expect(content).toMatch(/selector: 'foo'/); + expect(content).toMatch(/selector: 'app-foo'/); }); it('should respect the inlineTemplate option', () => { diff --git a/packages/schematics/angular/directive/index.ts b/packages/schematics/angular/directive/index.ts index 21f19f579c..bcacb61ef4 100644 --- a/packages/schematics/angular/directive/index.ts +++ b/packages/schematics/angular/directive/index.ts @@ -90,10 +90,12 @@ function addDeclarationToNgModule(options: DirectiveOptions): Rule { } -function buildSelector(options: DirectiveOptions) { +function buildSelector(options: DirectiveOptions, projectPrefix: string) { let selector = options.name; if (options.prefix) { selector = `${options.prefix}-${selector}`; + } else if (projectPrefix) { + selector = `${projectPrefix}-${selector}`; } return strings.camelize(selector); @@ -116,7 +118,7 @@ export default function (options: DirectiveOptions): Rule { const parsedPath = parseName(options.path, options.name); options.name = parsedPath.name; options.path = parsedPath.path; - options.selector = options.selector || buildSelector(options); + options.selector = options.selector || buildSelector(options, project.prefix); validateHtmlSelector(options.selector); diff --git a/packages/schematics/angular/directive/index_spec.ts b/packages/schematics/angular/directive/index_spec.ts index 8d173fc8f8..9673e3cd2c 100644 --- a/packages/schematics/angular/directive/index_spec.ts +++ b/packages/schematics/angular/directive/index_spec.ts @@ -129,4 +129,20 @@ describe('Directive Schematic', () => { const content = appTree.readContent('/projects/bar/src/app/sub/test.directive.ts'); expect(content).toMatch(/selector: '\[appTest\]'/); }); + + it('should use the prefix', () => { + const options = { ...defaultOptions, prefix: 'pre' }; + const tree = schematicRunner.runSchematic('directive', options, appTree); + + const content = tree.readContent('/projects/bar/src/app/foo.directive.ts'); + expect(content).toMatch(/selector: '\[preFoo\]'/); + }); + + it('should use the default project prefix if none is passed', () => { + const options = { ...defaultOptions, prefix: undefined }; + const tree = schematicRunner.runSchematic('directive', options, appTree); + + const content = tree.readContent('/projects/bar/src/app/foo.directive.ts'); + expect(content).toMatch(/selector: '\[appFoo\]'/); + }); }); diff --git a/packages/schematics/angular/library/index.ts b/packages/schematics/angular/library/index.ts index 173bad6679..7712ec7a41 100644 --- a/packages/schematics/angular/library/index.ts +++ b/packages/schematics/angular/library/index.ts @@ -126,6 +126,7 @@ function addAppToWorkspaceFile(options: LibraryOptions, workspace: WorkspaceSche const project: any = { root: `${projectRoot}`, projectType: 'library', + prefix: options.prefix || 'lib', architect: { build: { builder: '@angular-devkit/build-ng-packagr:build', diff --git a/packages/schematics/angular/library/index_spec.ts b/packages/schematics/angular/library/index_spec.ts index e223a3e043..47a76f0c6c 100644 --- a/packages/schematics/angular/library/index_spec.ts +++ b/packages/schematics/angular/library/index_spec.ts @@ -84,6 +84,21 @@ describe('Library Schematic', () => { expect(workspace.projects.foo).toBeDefined(); }); + it('should set the prefix to lib if none is set', () => { + const tree = schematicRunner.runSchematic('library', defaultOptions, workspaceTree); + + const workspace = JSON.parse(tree.readContent('/angular.json')); + expect(workspace.projects.foo.prefix).toEqual('lib'); + }); + + it('should set the prefix correctly', () => { + const options = { ...defaultOptions, prefix: 'pre' }; + const tree = schematicRunner.runSchematic('application', options, workspaceTree); + + const workspace = JSON.parse(tree.readContent('/angular.json')); + expect(workspace.projects.foo.prefix).toEqual('pre'); + }); + it('should handle a pascalCasedName', () => { const options = {...defaultOptions, name: 'pascalCasedName'}; const tree = schematicRunner.runSchematic('library', options, workspaceTree); diff --git a/packages/schematics/angular/ng-new/index.ts b/packages/schematics/angular/ng-new/index.ts index 7e44a9682a..1862d086f2 100644 --- a/packages/schematics/angular/ng-new/index.ts +++ b/packages/schematics/angular/ng-new/index.ts @@ -46,6 +46,7 @@ export default function (options: NgNewOptions): Rule { name: options.name, inlineStyle: options.inlineStyle, inlineTemplate: options.inlineTemplate, + prefix: options.prefix, viewEncapsulation: options.viewEncapsulation, routing: options.routing, style: options.style, diff --git a/packages/schematics/angular/ng-new/index_spec.ts b/packages/schematics/angular/ng-new/index_spec.ts index 4c75eec0d1..fb25a4d41f 100644 --- a/packages/schematics/angular/ng-new/index_spec.ts +++ b/packages/schematics/angular/ng-new/index_spec.ts @@ -38,4 +38,12 @@ describe('Ng New Schematic', () => { expect(files.indexOf('/bar/src/main.ts')).toBeGreaterThanOrEqual(0); expect(files.indexOf('/bar/src/app/app.module.ts')).toBeGreaterThanOrEqual(0); }); + + it('should should set the prefix in angular.json and in app.component.ts', () => { + const options = { ...defaultOptions, prefix: 'pre' }; + + const tree = schematicRunner.runSchematic('ng-new', options); + const content = tree.readContent('/bar/angular.json'); + expect(content).toMatch(/"prefix": "pre"/); + }); }); diff --git a/tests/@angular_devkit/build_angular/hello-world-app/.angular.json b/tests/@angular_devkit/build_angular/hello-world-app/.angular.json index 7881cfd9e5..96df8f781e 100644 --- a/tests/@angular_devkit/build_angular/hello-world-app/.angular.json +++ b/tests/@angular_devkit/build_angular/hello-world-app/.angular.json @@ -9,6 +9,7 @@ "app": { "root": "src", "projectType": "application", + "prefix": "app", "schematics": {}, "architect": { "build": {