diff --git a/README.md b/README.md index 0a9cf1b..f8f980d 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ Members can be matched to positional slots using several criteria, including nam - `readonly`: `true|false` to restrict the match to members with typescript `readonly` keyword. - `async`: `true|false` to restrict the match to async members. - `sort`: `"alphabetical"|"none"`. Used to require a specific sorting within the slot for matched members. Defaults to `"none"`. -- `groupByDecorator`: a string used to group properties with the same decorator name (e.g. `observable` for `@observable`). Can be used together with `sort`. **Note**: Decorators are a Stage 2 proposal and require a custom parser like [babel-eslint](https://github.com/babel/babel-eslint). +- `groupByDecorator`: a string used to group properties with the same decorator name (e.g. `observable` for `@observable`). Can be used together with `sort`. If the string starts and ends with `/` it will be interpreted as a regular expression. E.g., `"/_.+/"` will match members that have a decorator that starts with an underscore. **Note**: Decorators are a Stage 2 proposal and require a custom parser like [babel-eslint](https://github.com/babel/babel-eslint). A few examples: diff --git a/src/rules/sort-class-members.js b/src/rules/sort-class-members.js index 97aec0c..15c727d 100644 --- a/src/rules/sort-class-members.js +++ b/src/rules/sort-class-members.js @@ -349,7 +349,7 @@ function expandSlot(input, groups) { return []; } - const testName = slot.name && getNameComparer(slot.name); + const testName = slot.name && getStringComparer(slot.name); if (testName) { slot.testName = testName; } @@ -372,24 +372,24 @@ function matchAccessorPairs(members) { }); } -function getNameComparer(name) { - if (name[0] === '/') { - let namePattern = name.substr(1, name.length - 2); +function getStringComparer(str) { + if (str[0] === '/') { + let strPattern = str.substr(1, str.length - 2); - if (namePattern[0] !== '^') { - namePattern = `^${namePattern}`; + if (strPattern[0] !== '^') { + strPattern = `^${strPattern}`; } - if (namePattern[namePattern.length - 1] !== '$') { - namePattern += '$'; + if (strPattern[strPattern.length - 1] !== '$') { + strPattern += '$'; } - const re = new RegExp(namePattern); + const re = new RegExp(strPattern); - return (n) => re.test(n); + return (s) => re.test(s); } - return (n) => n === name; + return (s) => s === str; } function flatten(collection) { @@ -436,7 +436,10 @@ const comparers = [ { property: 'groupByDecorator', value: 10, - test: (m, s) => m.decorators.includes(s.groupByDecorator), + test: (m, s) => { + const comparer = getStringComparer(s.groupByDecorator); + return m.decorators.some((decorator) => comparer(decorator)); + }, }, { property: 'accessorPair', diff --git a/test/rules/sort-class-members.spec.js b/test/rules/sort-class-members.spec.js index db18c2b..3177415 100644 --- a/test/rules/sort-class-members.spec.js +++ b/test/rules/sort-class-members.spec.js @@ -142,6 +142,15 @@ const decoratorOptions = [ }, ]; +const decoratorRegexpOptions = [ + { + order: ['before', '[decorator-starts-with-ab]', 'after', '[everything-else]'], + groups: { + 'decorator-starts-with-ab': [{ groupByDecorator: '/ab.+/' }], + }, + }, +]; + const decoratorOptionsAlphabetical = [ { order: ['[observables]', '[properties]'], @@ -322,6 +331,13 @@ ruleTester.run('sort-class-members', rule, { code: 'class A { @observable bar = 2; @observable foo = 1; @Inject() @observable fuga = 5; baz = 3; constructor(){}; @Inject() hoge = 4; }', options: decoratorOptions, }, + + // regexp decorators + { code: 'class A { before(){} @abc() x = 4; after(){} }', options: decoratorRegexpOptions }, + { + code: 'class A { before(){} @something @abc() x = 4; after(){} xyz(){} }', + options: decoratorRegexpOptions, + }, ]), // regexp names