diff --git a/src/directive.ts b/src/directive.ts index a6fe05c..a79e84f 100644 --- a/src/directive.ts +++ b/src/directive.ts @@ -1,6 +1,6 @@ import { Declaration, defineMetadata, getAttributeName, getMetadata, isAttributeSelector, kebabToCamel, - metadataKeys + metadataKeys, tryGetDirectiveSelector } from './utils'; import { IHostListeners } from './hostListener'; import { IViewChildren } from './viewChild'; @@ -26,9 +26,10 @@ export function Directive({selector, ...options}: DirectiveOptionsDecorated) { options.require = require; if (!options.bindToController) options.bindToController = true; } - options.restrict = options.restrict || 'A'; - const selectorName = isAttributeSelector(selector) ? getAttributeName(selector) : selector; + const selectorTyped = tryGetDirectiveSelector(selector); + const selectorName = selectorTyped.selector || selector; + options.restrict = options.restrict || selectorTyped.restrict || 'A'; defineMetadata(metadataKeys.name, kebabToCamel(selectorName), ctrl); defineMetadata(metadataKeys.declaration, Declaration.Directive, ctrl); defineMetadata(metadataKeys.options, options, ctrl); diff --git a/src/utils.ts b/src/utils.ts index 5de362c..8ad9a99 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,6 +2,15 @@ import 'reflect-metadata'; export enum Declaration { Component = 'Component', Directive = 'Directive', Pipe = 'Pipe' } +export type DirectiveRestriction = 'A' | 'E' | 'C'; + +/** @internal */ +export const knownDirectiveTypes: Record = { + A: /^\[([a-z][a-zA-Z\-_]*?)\]$/, + E: /^([a-z\-]*)$/, + C: /^\.([a-z][a-zA-Z\-_]*?)$/ +}; + /** @internal */ export const metadataKeys = { declaration: 'custom:declaration', @@ -31,6 +40,15 @@ export function isAttributeSelector(selector: string) { return /^[\[].*[\]]$/g.test(selector); } +/** @internal */ +export function tryGetDirectiveSelector(selector: string): Partial<{ selector: string, restrict: DirectiveRestriction }> { + for (const restrictBy of Object.keys(knownDirectiveTypes)) { + const match = selector.match(knownDirectiveTypes[restrictBy]); + if (match && match[1]) return { selector: match[1], restrict: restrictBy as DirectiveRestriction }; + } + return {}; +} + /** @internal */ export function getMetadata(metadataKey: any, target: any): any { return Reflect.getMetadata(metadataKey, target); diff --git a/test/ng-module.spec.ts b/test/ng-module.spec.ts index adb2bbd..b4b9372 100644 --- a/test/ng-module.spec.ts +++ b/test/ng-module.spec.ts @@ -116,9 +116,10 @@ describe('NgModule', () => { directive('camel-case-name'), directive('[camelCaseName]'), directive('[camel-case-name]'), + directive('.camel-case-name'), ]); const invokeQueue = angular.module(moduleName)['_invokeQueue']; - expect(invokeQueue.length).toEqual(4); + expect(invokeQueue.length).toEqual(5); invokeQueue.forEach((value: any) => { expect(value[0]).toEqual('$compileProvider'); expect(value[1]).toEqual('directive');