├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── default.json ├── docs ├── ban-prefix.md ├── component-member-order.md ├── components-per-file.md ├── decorated-member-style.md ├── lifecycle-order.md └── require-prefix.md ├── package-lock.json ├── package.json ├── scripts ├── commit.js ├── docs │ ├── README.js │ ├── index.js │ └── render.js ├── prepare.js ├── shared │ ├── eval-text.js │ ├── run.js │ └── spawn.js ├── verify.js └── version.js ├── src ├── banPrefixRule.ts ├── code-examples │ ├── decoratedMemberStyle.examples.ts │ └── lifecycleSort.example.ts ├── componentMemberOrderRule.ts ├── componentsPerFileRule.ts ├── decoratedMemberStyleRule.ts ├── index.ts ├── lifecycleOrderRule.ts ├── requirePrefixRule.ts └── shared │ ├── constants.ts │ └── utils.ts ├── test └── rules │ ├── ban-prefix │ └── default │ │ ├── ban-prefix.lint │ │ └── tslint.json │ ├── component-member-order │ ├── alphabetical │ │ ├── simple.lint │ │ └── tslint.json │ ├── combined-order-watch │ │ ├── simple.lint │ │ └── tslint.json │ ├── combined │ │ ├── component-member-order.lint │ │ └── tslint.json │ ├── group │ │ ├── simple.lint │ │ └── tslint.json │ ├── order │ │ ├── simple.lint │ │ └── tslint.json │ ├── stencil-style │ │ ├── invalid.lint │ │ ├── tslint.json │ │ └── valid.lint │ └── watch │ │ ├── simple.lint │ │ └── tslint.json │ ├── components-per-file │ ├── one │ │ ├── components-per-file.ts.lint │ │ └── tslint.json │ ├── three │ │ ├── components-per-file.ts.lint │ │ └── tslint.json │ └── two │ │ ├── components-per-file.ts.lint │ │ └── tslint.json │ ├── decorated-member-style │ ├── methods-multiline │ │ ├── decorated-member-style.lint │ │ └── tslint.json │ ├── methods-singleline │ │ ├── decorated-member-style.lint │ │ └── tslint.json │ ├── properties-multiline │ │ ├── decorated-member-style.lint │ │ └── tslint.json │ └── properties-singleline │ │ ├── decorated-member-style.lint │ │ └── tslint.json │ ├── lifecycle-order │ ├── alphabetical │ │ ├── lifecycle-sort.lint │ │ └── tslint.json │ ├── call-order │ │ ├── lifecycle-sort.lint │ │ └── tslint.json │ └── default │ │ ├── lifecycle-sort.lint │ │ └── tslint.json │ └── require-prefix │ ├── multiple │ ├── require-prefix.lint │ └── tslint.json │ └── single │ ├── require-prefix.lint │ └── tslint.json ├── tsconfig.json └── tslint-stencil.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /rules 4 | .idea/ 5 | yarn.lock -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | thumbs.db 3 | *.log 4 | scripts/ 5 | src/ 6 | test/ 7 | docs/ 8 | .editorconfig 9 | .gitignore 10 | .travis.yml 11 | tsconfig.json 12 | tsint.json 13 | !/rules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-Present Nate Moore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tslint-stencil 2 | 3 | Adds stylistic [tslint](https://github.com/palantir/tslint) rules for [Stencil](https://github.com/ionic-team/stencil) projects 4 | 5 | ## Getting started 6 | 7 | Add the following line to your `tslint.json` file to enable the default ruleset (which follows the [Stencil Style Guide](https://stenciljs.com/docs/style-guide)) 8 | 9 | ```json 10 | { 11 | "extends": ["tslint-stencil/default"] 12 | } 13 | ``` 14 | 15 | Alternatively, you can extend the bare package and enable each [rule](#rules) on a individual basis 16 | 17 | ```json 18 | { 19 | "extends": ["tslint-stencil"], 20 | "rules": { 21 | "host-data-precedes-render": true 22 | } 23 | } 24 | ``` 25 | 26 | ## Rules 27 | 28 | ### [`ban-prefix`](docs/ban-prefix.md) 29 | 30 | Ensures that a Component's `tag` does not use any of the given prefixes. 31 | 32 | ### [`component-member-order`](docs/component-member-order.md) 33 | 34 | Ensures that Component members are ordered consistently 35 | 36 | ### [`components-per-file`](docs/components-per-file.md) 37 | 38 | Allows a maximum number of Components to be placed in a single file 39 | 40 | ### [`decorated-member-style`](docs/decorated-member-style.md) 41 | 42 | Requires decorated class members to follow a consistent style (singleline or multiline) 43 | 44 | ### [`lifecycle-order`](docs/lifecycle-order.md) 45 | 46 | Ensures that Component lifecycle methods are ordered consistently 47 | 48 | ### [`require-prefix`](docs/require-prefix.md) 49 | 50 | Ensures that a Component's `tag` begins with the given prefix(es). 51 | 52 | ## Contributing 53 | 54 | Rules in the `src/` directory must be **camelCased** and end in **Rule**. 55 | More information on developing custom tslint rules can be found on the [tslint site](https://palantir.github.io/tslint/develop/custom-rules/) 56 | 57 | Before adding your custom rule, be sure to write a test for it. Then, you should be able to verify that it works by running: 58 | 59 | ``` 60 | npm run verify 61 | ``` 62 | -------------------------------------------------------------------------------- /default.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tslint-stencil.json", 3 | "rules": { 4 | "ban-prefix": [true, "stencil", "st", "stnl"], 5 | "component-member-order": [ 6 | true, 7 | { 8 | "order": [ 9 | "own-prop", 10 | "element", 11 | "state", 12 | "watched-state", 13 | "internal-prop", 14 | "prop", 15 | "watched-prop", 16 | "event", 17 | "lifecycle", 18 | "listen", 19 | "method", 20 | "own-method", 21 | "stencil-method" 22 | ], 23 | "watch-follows-prop": true, 24 | "alphabetical": true 25 | } 26 | ], 27 | "components-per-file": [true, 1], 28 | "decorated-member-style": [ 29 | true, 30 | { 31 | "properties": "singleline", 32 | "methods": "multiline" 33 | } 34 | ], 35 | "lifecycle-order": [true, "call-order"] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /docs/ban-prefix.md: -------------------------------------------------------------------------------- 1 | # `ban-prefix` 2 | 3 | Ensures that a Component's `tag` does not use any of the given prefixes. 4 | 5 | ## Config 6 | 7 | An array of `"string"`s which no Component `tag` will be allowed to use as a prefix. 8 | 9 | ### Config examples 10 | 11 | ```ts 12 | { "ban-prefix": [true, "stencil"] } 13 | ``` 14 | 15 | ```ts 16 | { "ban-prefix": [true, "stencil", "st", "stnl"] } 17 | ``` 18 | 19 | ## Schema 20 | 21 | ```ts 22 | { 23 | "type": "array", 24 | "items": { 25 | "type": "string" 26 | }, 27 | "minLength": 1 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/component-member-order.md: -------------------------------------------------------------------------------- 1 | # `component-member-order` 2 | 3 | Ensures that Component members are ordered consistently 4 | 5 | ## Config 6 | 7 | One argument, which is an object, must be provided. It should contain an `"order"` property. The `"order"` property should be an array consisting of the following strings: 8 | 9 | - `element`, which refers to `@Element()` decorated properties 10 | - `event`, which refers to `@Event()` decorated properties 11 | - `internal-prop`, which refers to `@Prop()` decorated properties using `context` or `connect` 12 | - `lifecycle`, which refers to Stencil lifecycle methods (such as `componentWillLoad`) 13 | - `listen`, which refers to `@Listen()` decorated methods 14 | - `method`, which refers to `@Method()` decorated methods 15 | - `own-method`, which refers to undecorated methods 16 | - `own-prop`, which refers to undecorated properties 17 | - `prop`, which refers to `@Prop()` decorated properties 18 | - `state`, which refers to `@State()` decorated properties 19 | - `stencil-method`, which refers to Stencil \`render()\` method 20 | - `watch`, which refers to `@Watch()` decorated methods 21 | - `watched-prop`, which refers to `@Prop()` decorated properties that have a `@Watch()` method 22 | - `watched-state`, which refers to `@State()` decorated properties that have a `@Watch()` method 23 | 24 | ### Config examples 25 | 26 | ```ts 27 | { 28 | "component-member-order": [ 29 | true, 30 | { 31 | "order": [ 32 | "own-prop", 33 | "element", 34 | "state", 35 | "watched-state", 36 | "internal-prop", 37 | "prop", 38 | "watched-prop", 39 | "event", 40 | "lifecycle", 41 | "listen", 42 | "method", 43 | "own-method", 44 | "stencil-method" 45 | ], 46 | "alphabetical": true 47 | } 48 | ] 49 | } 50 | ``` 51 | 52 | ```ts 53 | { 54 | "component-member-order": [ 55 | true, 56 | { 57 | "order": false, 58 | "watch-follows-prop": true 59 | } 60 | ] 61 | } 62 | ``` 63 | 64 | ## Schema 65 | 66 | ```ts 67 | { 68 | "type": "object", 69 | "properties": { 70 | "order": { 71 | "type": "array", 72 | "items": { 73 | "type": "string", 74 | "enum": [ 75 | "element", 76 | "event", 77 | "internal-prop", 78 | "lifecycle", 79 | "listen", 80 | "method", 81 | "own-method", 82 | "own-prop", 83 | "prop", 84 | "state", 85 | "stencil-method", 86 | "watch", 87 | "watched-state", 88 | "watched-prop" 89 | ] 90 | }, 91 | "minLength": 2, 92 | "maxLength": 12 93 | }, 94 | "watch-follows-prop": { 95 | "type": "boolean" 96 | }, 97 | "alphabetical": { 98 | "type": "boolean" 99 | } 100 | }, 101 | "additionalProperties": false 102 | } 103 | ``` 104 | -------------------------------------------------------------------------------- /docs/components-per-file.md: -------------------------------------------------------------------------------- 1 | # `components-per-file` 2 | 3 | Allows a maximum number of Components to be placed in a single file 4 | 5 | ## Config 6 | 7 | This rule requires a single argument – a `"number"` representing the maximum number of @Component() decorated classes allowed in a single file. 8 | 9 | ### Config examples 10 | 11 | ```ts 12 | { "components-per-file": [true, 1] } 13 | ``` 14 | 15 | ## Schema 16 | 17 | ```ts 18 | { 19 | "type": "array", 20 | "items": { 21 | "type": "number" 22 | }, 23 | "minLength": 1, 24 | "maxLength": 1 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/decorated-member-style.md: -------------------------------------------------------------------------------- 1 | # `decorated-member-style` 2 | 3 | Requires decorated class members to follow a consistent style (singleline or multiline) 4 | 5 | **`🛠 Has Fixer`** 6 | 7 | ## Config 8 | 9 | One argument which is an object with the keys `"properties"` and `"methods"`. Both can be set to a string, which must be one of the following values: 10 | 11 | - `"singleline"` 12 | - `"multiline"` 13 | - `"ignore"` 14 | 15 | If either key is excluded, the default behavior (`"ignore"`) will be applied. 16 | 17 | A member is considered “multiline” if its declaration is on a line after the last decorator. If decorators are composed (multiple decorators for a single declaration), "multiline" requires each decorator to be on its own line. 18 | 19 | ### Config examples 20 | 21 | ```ts 22 | { 23 | "decorated-member-style": [ 24 | true, 25 | { 26 | "methods": "multiline" 27 | } 28 | ] 29 | } 30 | ``` 31 | 32 | ```ts 33 | { 34 | "decorated-member-style": [ 35 | true, 36 | { 37 | "properties": "singleline", 38 | "methods": "multiline" 39 | } 40 | ] 41 | } 42 | ``` 43 | 44 | ## Schema 45 | 46 | ```ts 47 | { 48 | "type": "object", 49 | "properties": { 50 | "properties": { 51 | "type": "string", 52 | "enum": [ 53 | "singleline", 54 | "multiline", 55 | "ignore" 56 | ] 57 | }, 58 | "methods": { 59 | "type": "string", 60 | "enum": [ 61 | "singleline", 62 | "multiline", 63 | "ignore" 64 | ] 65 | } 66 | } 67 | } 68 | ``` 69 | 70 | ## Code Examples 71 | 72 | - Require all decorated component properties to be singleline. 73 | **⚙️ Config** 74 | ```ts 75 | "rules": { "decorated-member-style": [true, { "properties": "singleline" }] } 76 | ``` 77 | **✅ Pass** 78 | ```ts 79 | @Prop() propName: string; 80 | ``` 81 | **🚫 Fail** 82 | ```ts 83 | @Prop() 84 | propName: string; 85 | ``` 86 | - Require all decorated component properties to be multiline. 87 | **⚙️ Config** 88 | ```ts 89 | "rules": { "decorated-member-style": [true, { "properties": "multiline" }] } 90 | ``` 91 | **✅ Pass** 92 | ```ts 93 | @Prop() 94 | propName: string; 95 | ``` 96 | **🚫 Fail** 97 | ```ts 98 | @Prop() propName: string; 99 | ``` 100 | - Require all decorated component methods to be inlined. 101 | **⚙️ Config** 102 | ```ts 103 | "rules": { "decorated-member-style": [true, { "methods": "singleline" }] } 104 | ``` 105 | **✅ Pass** 106 | ```ts 107 | @Listen('click') handleClick() {} 108 | ``` 109 | **🚫 Fail** 110 | ```ts 111 | @Listen('click') 112 | handleClick() {} 113 | ``` 114 | - Require all decorated component methods to be multiline. 115 | **⚙️ Config** 116 | ```ts 117 | "rules": { "decorated-member-style": [true, { "methods": "multiline" }] } 118 | ``` 119 | **✅ Pass** 120 | ```ts 121 | @Listen('click') 122 | handleClick() {} 123 | 124 | @Listen('click') 125 | @Listen('tap') 126 | handleClickOrTap() {} 127 | ``` 128 | **🚫 Fail** 129 | ```ts 130 | @Listen('click') handleClick() {} 131 | ``` 132 | -------------------------------------------------------------------------------- /docs/lifecycle-order.md: -------------------------------------------------------------------------------- 1 | # `lifecycle-order` 2 | 3 | Ensures that Component lifecycle methods are ordered consistently 4 | 5 | ## Rationale 6 | 7 | A consistent ordering for Component lifecycle methods can make Components easier to read, navigate, and edit. 8 | 9 | Ordering lifecycle methods by their natural call order (`call-order`) makes the functionality of each self-documenting. 10 | 11 | ## Config 12 | 13 | This rule optionally accepts a single argument, which is a string. It should be one of the following values: 14 | 15 | - `call-order` 16 | - `alphabetical` 17 | 18 | If no argument is provided, this rule will enforce the default functionality (which matches that of `call-order`.) 19 | 20 | ### Config examples 21 | 22 | ```ts 23 | { "lifecycle-sort": [true, "call-order"] } 24 | ``` 25 | 26 | ```ts 27 | { "lifecycle-sort": [true, "alphabetical"] } 28 | ``` 29 | 30 | ## Schema 31 | 32 | ```ts 33 | { 34 | "type": "array", 35 | "items": { 36 | "type": "string", 37 | "enum": [ 38 | "alphabetical", 39 | "call-order" 40 | ] 41 | }, 42 | "minLength": 0, 43 | "maxLength": 2 44 | } 45 | ``` 46 | 47 | ## Code Examples 48 | 49 | - Order lifecycle methods by their natural call order (`call-order` or `default`) 50 | 51 | **⚙️ Config** 52 | 53 | ```ts 54 | "rules": { "lifecycle-sort": [true, "call-order"] } 55 | ``` 56 | 57 | **✅ Pass** 58 | 59 | ```ts 60 | componentWillLoad() { } 61 | componentDidLoad() { } 62 | componentWillUpdate() { } 63 | componentDidUpdate() { } 64 | componentDidUnload() { } 65 | ``` 66 | 67 | - Order lifecycle methods alphabetically (`alphabetical`) 68 | **⚙️ Config** 69 | ```ts 70 | "rules": { "lifecycle-sort": [true, "alphabetical"] } 71 | ``` 72 | **✅ Pass** 73 | ```ts 74 | componentDidLoad() { } 75 | componentDidUnload() { } 76 | componentDidUpdate() { } 77 | componentWillLoad() { } 78 | componentWillUpdate() { } 79 | ``` 80 | -------------------------------------------------------------------------------- /docs/require-prefix.md: -------------------------------------------------------------------------------- 1 | # `require-prefix` 2 | 3 | Ensures that a Component's `tag` begins with the given prefix(es). 4 | 5 | ## Config 6 | 7 | An array of `"string"` which a Component `tag` must use as a prefix. 8 | 9 | ### Config examples 10 | 11 | ```ts 12 | { "ban-prefix": [true, "ion"] } 13 | ``` 14 | 15 | ```ts 16 | { "ban-prefix": [true, "ion", "ionic"] } 17 | ``` 18 | 19 | ## Schema 20 | 21 | ```ts 22 | { 23 | "type": "array", 24 | "items": { 25 | "type": "string" 26 | }, 27 | "minLength": 1 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint-stencil", 3 | "version": "1.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/runtime": { 8 | "version": "7.0.0", 9 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", 10 | "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", 11 | "dev": true, 12 | "requires": { 13 | "regenerator-runtime": "^0.12.0" 14 | } 15 | }, 16 | "@samverschueren/stream-to-observable": { 17 | "version": "0.3.0", 18 | "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", 19 | "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", 20 | "dev": true, 21 | "requires": { 22 | "any-observable": "^0.3.0" 23 | } 24 | }, 25 | "@types/node": { 26 | "version": "10.9.2", 27 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.9.2.tgz", 28 | "integrity": "sha512-pwZnkVyCGJ3LsQ0/3flQK5lCFao4esIzwUVzzk5NvL9vnkEyDhNf4fhHzUMHvyr56gNZywWTS2MR0euabMSz4A==", 29 | "dev": true 30 | }, 31 | "ansi-escapes": { 32 | "version": "3.2.0", 33 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", 34 | "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", 35 | "dev": true 36 | }, 37 | "ansi-regex": { 38 | "version": "2.1.1", 39 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 40 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 41 | "dev": true 42 | }, 43 | "ansi-styles": { 44 | "version": "2.2.1", 45 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 46 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 47 | "dev": true 48 | }, 49 | "any-observable": { 50 | "version": "0.3.0", 51 | "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", 52 | "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", 53 | "dev": true 54 | }, 55 | "argparse": { 56 | "version": "1.0.10", 57 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 58 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 59 | "dev": true, 60 | "requires": { 61 | "sprintf-js": "~1.0.2" 62 | } 63 | }, 64 | "arr-diff": { 65 | "version": "4.0.0", 66 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", 67 | "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", 68 | "dev": true 69 | }, 70 | "arr-flatten": { 71 | "version": "1.1.0", 72 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", 73 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", 74 | "dev": true 75 | }, 76 | "arr-union": { 77 | "version": "3.1.0", 78 | "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", 79 | "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", 80 | "dev": true 81 | }, 82 | "array-union": { 83 | "version": "1.0.2", 84 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", 85 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", 86 | "dev": true, 87 | "requires": { 88 | "array-uniq": "^1.0.1" 89 | } 90 | }, 91 | "array-uniq": { 92 | "version": "1.0.3", 93 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 94 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", 95 | "dev": true 96 | }, 97 | "array-unique": { 98 | "version": "0.3.2", 99 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", 100 | "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", 101 | "dev": true 102 | }, 103 | "arrify": { 104 | "version": "1.0.1", 105 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", 106 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", 107 | "dev": true 108 | }, 109 | "assign-symbols": { 110 | "version": "1.0.0", 111 | "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", 112 | "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", 113 | "dev": true 114 | }, 115 | "atob": { 116 | "version": "2.1.2", 117 | "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", 118 | "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", 119 | "dev": true 120 | }, 121 | "babel-code-frame": { 122 | "version": "6.26.0", 123 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 124 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 125 | "dev": true, 126 | "requires": { 127 | "chalk": "^1.1.3", 128 | "esutils": "^2.0.2", 129 | "js-tokens": "^3.0.2" 130 | }, 131 | "dependencies": { 132 | "chalk": { 133 | "version": "1.1.3", 134 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 135 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 136 | "dev": true, 137 | "requires": { 138 | "ansi-styles": "^2.2.1", 139 | "escape-string-regexp": "^1.0.2", 140 | "has-ansi": "^2.0.0", 141 | "strip-ansi": "^3.0.0", 142 | "supports-color": "^2.0.0" 143 | } 144 | } 145 | } 146 | }, 147 | "balanced-match": { 148 | "version": "1.0.0", 149 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 150 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 151 | "dev": true 152 | }, 153 | "base": { 154 | "version": "0.11.2", 155 | "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", 156 | "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", 157 | "dev": true, 158 | "requires": { 159 | "cache-base": "^1.0.1", 160 | "class-utils": "^0.3.5", 161 | "component-emitter": "^1.2.1", 162 | "define-property": "^1.0.0", 163 | "isobject": "^3.0.1", 164 | "mixin-deep": "^1.2.0", 165 | "pascalcase": "^0.1.1" 166 | }, 167 | "dependencies": { 168 | "define-property": { 169 | "version": "1.0.0", 170 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 171 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 172 | "dev": true, 173 | "requires": { 174 | "is-descriptor": "^1.0.0" 175 | } 176 | }, 177 | "is-accessor-descriptor": { 178 | "version": "1.0.0", 179 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 180 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 181 | "dev": true, 182 | "requires": { 183 | "kind-of": "^6.0.0" 184 | } 185 | }, 186 | "is-data-descriptor": { 187 | "version": "1.0.0", 188 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 189 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 190 | "dev": true, 191 | "requires": { 192 | "kind-of": "^6.0.0" 193 | } 194 | }, 195 | "is-descriptor": { 196 | "version": "1.0.2", 197 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 198 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 199 | "dev": true, 200 | "requires": { 201 | "is-accessor-descriptor": "^1.0.0", 202 | "is-data-descriptor": "^1.0.0", 203 | "kind-of": "^6.0.2" 204 | } 205 | } 206 | } 207 | }, 208 | "brace-expansion": { 209 | "version": "1.1.11", 210 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 211 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 212 | "dev": true, 213 | "requires": { 214 | "balanced-match": "^1.0.0", 215 | "concat-map": "0.0.1" 216 | } 217 | }, 218 | "braces": { 219 | "version": "2.3.2", 220 | "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", 221 | "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", 222 | "dev": true, 223 | "requires": { 224 | "arr-flatten": "^1.1.0", 225 | "array-unique": "^0.3.2", 226 | "extend-shallow": "^2.0.1", 227 | "fill-range": "^4.0.0", 228 | "isobject": "^3.0.1", 229 | "repeat-element": "^1.1.2", 230 | "snapdragon": "^0.8.1", 231 | "snapdragon-node": "^2.0.1", 232 | "split-string": "^3.0.2", 233 | "to-regex": "^3.0.1" 234 | }, 235 | "dependencies": { 236 | "extend-shallow": { 237 | "version": "2.0.1", 238 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 239 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 240 | "dev": true, 241 | "requires": { 242 | "is-extendable": "^0.1.0" 243 | } 244 | } 245 | } 246 | }, 247 | "builtin-modules": { 248 | "version": "1.1.1", 249 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 250 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 251 | "dev": true 252 | }, 253 | "cache-base": { 254 | "version": "1.0.1", 255 | "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", 256 | "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", 257 | "dev": true, 258 | "requires": { 259 | "collection-visit": "^1.0.0", 260 | "component-emitter": "^1.2.1", 261 | "get-value": "^2.0.6", 262 | "has-value": "^1.0.0", 263 | "isobject": "^3.0.1", 264 | "set-value": "^2.0.0", 265 | "to-object-path": "^0.3.0", 266 | "union-value": "^1.0.0", 267 | "unset-value": "^1.0.0" 268 | } 269 | }, 270 | "caller-callsite": { 271 | "version": "2.0.0", 272 | "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", 273 | "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", 274 | "dev": true, 275 | "requires": { 276 | "callsites": "^2.0.0" 277 | } 278 | }, 279 | "caller-path": { 280 | "version": "2.0.0", 281 | "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", 282 | "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", 283 | "dev": true, 284 | "requires": { 285 | "caller-callsite": "^2.0.0" 286 | } 287 | }, 288 | "callsites": { 289 | "version": "2.0.0", 290 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", 291 | "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", 292 | "dev": true 293 | }, 294 | "chalk": { 295 | "version": "2.4.1", 296 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 297 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 298 | "dev": true, 299 | "requires": { 300 | "ansi-styles": "^3.2.1", 301 | "escape-string-regexp": "^1.0.5", 302 | "supports-color": "^5.3.0" 303 | }, 304 | "dependencies": { 305 | "ansi-styles": { 306 | "version": "3.2.1", 307 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 308 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 309 | "dev": true, 310 | "requires": { 311 | "color-convert": "^1.9.0" 312 | } 313 | }, 314 | "supports-color": { 315 | "version": "5.5.0", 316 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 317 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 318 | "dev": true, 319 | "requires": { 320 | "has-flag": "^3.0.0" 321 | } 322 | } 323 | } 324 | }, 325 | "ci-info": { 326 | "version": "2.0.0", 327 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", 328 | "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", 329 | "dev": true 330 | }, 331 | "class-utils": { 332 | "version": "0.3.6", 333 | "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", 334 | "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", 335 | "dev": true, 336 | "requires": { 337 | "arr-union": "^3.1.0", 338 | "define-property": "^0.2.5", 339 | "isobject": "^3.0.0", 340 | "static-extend": "^0.1.1" 341 | }, 342 | "dependencies": { 343 | "define-property": { 344 | "version": "0.2.5", 345 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 346 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 347 | "dev": true, 348 | "requires": { 349 | "is-descriptor": "^0.1.0" 350 | } 351 | } 352 | } 353 | }, 354 | "cli-cursor": { 355 | "version": "2.1.0", 356 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 357 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 358 | "dev": true, 359 | "requires": { 360 | "restore-cursor": "^2.0.0" 361 | } 362 | }, 363 | "cli-spinner": { 364 | "version": "0.2.8", 365 | "resolved": "https://registry.npmjs.org/cli-spinner/-/cli-spinner-0.2.8.tgz", 366 | "integrity": "sha512-Z4l0jljucEUsW/5GNaVYOpGgVmnB/Sq4l2vG9k7RbJYRZ97hVncP+BqRMemTZNBHZ4aYUPJPU/wl6zt/ZSqzPQ==", 367 | "dev": true 368 | }, 369 | "cli-truncate": { 370 | "version": "0.2.1", 371 | "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", 372 | "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", 373 | "dev": true, 374 | "requires": { 375 | "slice-ansi": "0.0.4", 376 | "string-width": "^1.0.1" 377 | } 378 | }, 379 | "code-point-at": { 380 | "version": "1.1.0", 381 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 382 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 383 | "dev": true 384 | }, 385 | "collection-visit": { 386 | "version": "1.0.0", 387 | "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", 388 | "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", 389 | "dev": true, 390 | "requires": { 391 | "map-visit": "^1.0.0", 392 | "object-visit": "^1.0.0" 393 | } 394 | }, 395 | "color-convert": { 396 | "version": "1.9.2", 397 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", 398 | "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", 399 | "dev": true, 400 | "requires": { 401 | "color-name": "1.1.1" 402 | } 403 | }, 404 | "color-name": { 405 | "version": "1.1.1", 406 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", 407 | "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", 408 | "dev": true 409 | }, 410 | "colorette": { 411 | "version": "1.0.1", 412 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.0.1.tgz", 413 | "integrity": "sha512-40MnlppkzHhFjRhtXunbpqKUT+eJn0gyVGi8aQlNSG8T2CCy31NdD7yktcS0aizH1VP2OhhQCyGMeTp0a/fvaw==", 414 | "dev": true 415 | }, 416 | "commander": { 417 | "version": "2.17.1", 418 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", 419 | "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", 420 | "dev": true 421 | }, 422 | "component-emitter": { 423 | "version": "1.3.0", 424 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 425 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", 426 | "dev": true 427 | }, 428 | "concat-map": { 429 | "version": "0.0.1", 430 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 431 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 432 | "dev": true 433 | }, 434 | "copy-descriptor": { 435 | "version": "0.1.1", 436 | "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", 437 | "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", 438 | "dev": true 439 | }, 440 | "cosmiconfig": { 441 | "version": "5.2.0", 442 | "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.0.tgz", 443 | "integrity": "sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==", 444 | "dev": true, 445 | "requires": { 446 | "import-fresh": "^2.0.0", 447 | "is-directory": "^0.3.1", 448 | "js-yaml": "^3.13.0", 449 | "parse-json": "^4.0.0" 450 | }, 451 | "dependencies": { 452 | "js-yaml": { 453 | "version": "3.13.1", 454 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 455 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 456 | "dev": true, 457 | "requires": { 458 | "argparse": "^1.0.7", 459 | "esprima": "^4.0.0" 460 | } 461 | } 462 | } 463 | }, 464 | "cross-spawn": { 465 | "version": "6.0.5", 466 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 467 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 468 | "dev": true, 469 | "requires": { 470 | "nice-try": "^1.0.4", 471 | "path-key": "^2.0.1", 472 | "semver": "^5.5.0", 473 | "shebang-command": "^1.2.0", 474 | "which": "^1.2.9" 475 | } 476 | }, 477 | "date-fns": { 478 | "version": "1.30.1", 479 | "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", 480 | "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", 481 | "dev": true 482 | }, 483 | "debug": { 484 | "version": "3.2.6", 485 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 486 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 487 | "dev": true, 488 | "requires": { 489 | "ms": "^2.1.1" 490 | } 491 | }, 492 | "decode-uri-component": { 493 | "version": "0.2.0", 494 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", 495 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", 496 | "dev": true 497 | }, 498 | "dedent": { 499 | "version": "0.7.0", 500 | "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", 501 | "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", 502 | "dev": true 503 | }, 504 | "define-property": { 505 | "version": "2.0.2", 506 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", 507 | "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", 508 | "dev": true, 509 | "requires": { 510 | "is-descriptor": "^1.0.2", 511 | "isobject": "^3.0.1" 512 | }, 513 | "dependencies": { 514 | "is-accessor-descriptor": { 515 | "version": "1.0.0", 516 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 517 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 518 | "dev": true, 519 | "requires": { 520 | "kind-of": "^6.0.0" 521 | } 522 | }, 523 | "is-data-descriptor": { 524 | "version": "1.0.0", 525 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 526 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 527 | "dev": true, 528 | "requires": { 529 | "kind-of": "^6.0.0" 530 | } 531 | }, 532 | "is-descriptor": { 533 | "version": "1.0.2", 534 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 535 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 536 | "dev": true, 537 | "requires": { 538 | "is-accessor-descriptor": "^1.0.0", 539 | "is-data-descriptor": "^1.0.0", 540 | "kind-of": "^6.0.2" 541 | } 542 | } 543 | } 544 | }, 545 | "del": { 546 | "version": "3.0.0", 547 | "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", 548 | "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", 549 | "dev": true, 550 | "requires": { 551 | "globby": "^6.1.0", 552 | "is-path-cwd": "^1.0.0", 553 | "is-path-in-cwd": "^1.0.0", 554 | "p-map": "^1.1.1", 555 | "pify": "^3.0.0", 556 | "rimraf": "^2.2.8" 557 | } 558 | }, 559 | "diff": { 560 | "version": "3.5.0", 561 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 562 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 563 | "dev": true 564 | }, 565 | "elegant-spinner": { 566 | "version": "1.0.1", 567 | "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", 568 | "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", 569 | "dev": true 570 | }, 571 | "end-of-stream": { 572 | "version": "1.4.1", 573 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", 574 | "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", 575 | "dev": true, 576 | "requires": { 577 | "once": "^1.4.0" 578 | } 579 | }, 580 | "error-ex": { 581 | "version": "1.3.2", 582 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 583 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 584 | "dev": true, 585 | "requires": { 586 | "is-arrayish": "^0.2.1" 587 | } 588 | }, 589 | "escape-string-regexp": { 590 | "version": "1.0.5", 591 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 592 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 593 | "dev": true 594 | }, 595 | "esprima": { 596 | "version": "4.0.1", 597 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 598 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 599 | "dev": true 600 | }, 601 | "esutils": { 602 | "version": "2.0.2", 603 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 604 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 605 | "dev": true 606 | }, 607 | "execa": { 608 | "version": "1.0.0", 609 | "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", 610 | "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", 611 | "dev": true, 612 | "requires": { 613 | "cross-spawn": "^6.0.0", 614 | "get-stream": "^4.0.0", 615 | "is-stream": "^1.1.0", 616 | "npm-run-path": "^2.0.0", 617 | "p-finally": "^1.0.0", 618 | "signal-exit": "^3.0.0", 619 | "strip-eof": "^1.0.0" 620 | } 621 | }, 622 | "expand-brackets": { 623 | "version": "2.1.4", 624 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", 625 | "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", 626 | "dev": true, 627 | "requires": { 628 | "debug": "^2.3.3", 629 | "define-property": "^0.2.5", 630 | "extend-shallow": "^2.0.1", 631 | "posix-character-classes": "^0.1.0", 632 | "regex-not": "^1.0.0", 633 | "snapdragon": "^0.8.1", 634 | "to-regex": "^3.0.1" 635 | }, 636 | "dependencies": { 637 | "debug": { 638 | "version": "2.6.9", 639 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 640 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 641 | "dev": true, 642 | "requires": { 643 | "ms": "2.0.0" 644 | } 645 | }, 646 | "define-property": { 647 | "version": "0.2.5", 648 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 649 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 650 | "dev": true, 651 | "requires": { 652 | "is-descriptor": "^0.1.0" 653 | } 654 | }, 655 | "extend-shallow": { 656 | "version": "2.0.1", 657 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 658 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 659 | "dev": true, 660 | "requires": { 661 | "is-extendable": "^0.1.0" 662 | } 663 | }, 664 | "ms": { 665 | "version": "2.0.0", 666 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 667 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 668 | "dev": true 669 | } 670 | } 671 | }, 672 | "extend-shallow": { 673 | "version": "3.0.2", 674 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", 675 | "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", 676 | "dev": true, 677 | "requires": { 678 | "assign-symbols": "^1.0.0", 679 | "is-extendable": "^1.0.1" 680 | }, 681 | "dependencies": { 682 | "is-extendable": { 683 | "version": "1.0.1", 684 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 685 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 686 | "dev": true, 687 | "requires": { 688 | "is-plain-object": "^2.0.4" 689 | } 690 | } 691 | } 692 | }, 693 | "extglob": { 694 | "version": "2.0.4", 695 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", 696 | "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", 697 | "dev": true, 698 | "requires": { 699 | "array-unique": "^0.3.2", 700 | "define-property": "^1.0.0", 701 | "expand-brackets": "^2.1.4", 702 | "extend-shallow": "^2.0.1", 703 | "fragment-cache": "^0.2.1", 704 | "regex-not": "^1.0.0", 705 | "snapdragon": "^0.8.1", 706 | "to-regex": "^3.0.1" 707 | }, 708 | "dependencies": { 709 | "define-property": { 710 | "version": "1.0.0", 711 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 712 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 713 | "dev": true, 714 | "requires": { 715 | "is-descriptor": "^1.0.0" 716 | } 717 | }, 718 | "extend-shallow": { 719 | "version": "2.0.1", 720 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 721 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 722 | "dev": true, 723 | "requires": { 724 | "is-extendable": "^0.1.0" 725 | } 726 | }, 727 | "is-accessor-descriptor": { 728 | "version": "1.0.0", 729 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 730 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 731 | "dev": true, 732 | "requires": { 733 | "kind-of": "^6.0.0" 734 | } 735 | }, 736 | "is-data-descriptor": { 737 | "version": "1.0.0", 738 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 739 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 740 | "dev": true, 741 | "requires": { 742 | "kind-of": "^6.0.0" 743 | } 744 | }, 745 | "is-descriptor": { 746 | "version": "1.0.2", 747 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 748 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 749 | "dev": true, 750 | "requires": { 751 | "is-accessor-descriptor": "^1.0.0", 752 | "is-data-descriptor": "^1.0.0", 753 | "kind-of": "^6.0.2" 754 | } 755 | } 756 | } 757 | }, 758 | "figures": { 759 | "version": "1.7.0", 760 | "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", 761 | "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", 762 | "dev": true, 763 | "requires": { 764 | "escape-string-regexp": "^1.0.5", 765 | "object-assign": "^4.1.0" 766 | } 767 | }, 768 | "fill-range": { 769 | "version": "4.0.0", 770 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", 771 | "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", 772 | "dev": true, 773 | "requires": { 774 | "extend-shallow": "^2.0.1", 775 | "is-number": "^3.0.0", 776 | "repeat-string": "^1.6.1", 777 | "to-regex-range": "^2.1.0" 778 | }, 779 | "dependencies": { 780 | "extend-shallow": { 781 | "version": "2.0.1", 782 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 783 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 784 | "dev": true, 785 | "requires": { 786 | "is-extendable": "^0.1.0" 787 | } 788 | } 789 | } 790 | }, 791 | "find-parent-dir": { 792 | "version": "0.3.0", 793 | "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", 794 | "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", 795 | "dev": true 796 | }, 797 | "find-up": { 798 | "version": "3.0.0", 799 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 800 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 801 | "dev": true, 802 | "requires": { 803 | "locate-path": "^3.0.0" 804 | } 805 | }, 806 | "fn-name": { 807 | "version": "2.0.1", 808 | "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", 809 | "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", 810 | "dev": true 811 | }, 812 | "for-in": { 813 | "version": "1.0.2", 814 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", 815 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", 816 | "dev": true 817 | }, 818 | "fragment-cache": { 819 | "version": "0.2.1", 820 | "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", 821 | "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", 822 | "dev": true, 823 | "requires": { 824 | "map-cache": "^0.2.2" 825 | } 826 | }, 827 | "fs.realpath": { 828 | "version": "1.0.0", 829 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 830 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 831 | "dev": true 832 | }, 833 | "g-status": { 834 | "version": "2.0.2", 835 | "resolved": "https://registry.npmjs.org/g-status/-/g-status-2.0.2.tgz", 836 | "integrity": "sha512-kQoE9qH+T1AHKgSSD0Hkv98bobE90ILQcXAF4wvGgsr7uFqNvwmh8j+Lq3l0RVt3E3HjSbv2B9biEGcEtpHLCA==", 837 | "dev": true, 838 | "requires": { 839 | "arrify": "^1.0.1", 840 | "matcher": "^1.0.0", 841 | "simple-git": "^1.85.0" 842 | } 843 | }, 844 | "get-own-enumerable-property-symbols": { 845 | "version": "3.0.0", 846 | "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", 847 | "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==", 848 | "dev": true 849 | }, 850 | "get-stdin": { 851 | "version": "6.0.0", 852 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", 853 | "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", 854 | "dev": true 855 | }, 856 | "get-stream": { 857 | "version": "4.1.0", 858 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", 859 | "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", 860 | "dev": true, 861 | "requires": { 862 | "pump": "^3.0.0" 863 | } 864 | }, 865 | "get-value": { 866 | "version": "2.0.6", 867 | "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", 868 | "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", 869 | "dev": true 870 | }, 871 | "glob": { 872 | "version": "7.1.3", 873 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 874 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 875 | "dev": true, 876 | "requires": { 877 | "fs.realpath": "^1.0.0", 878 | "inflight": "^1.0.4", 879 | "inherits": "2", 880 | "minimatch": "^3.0.4", 881 | "once": "^1.3.0", 882 | "path-is-absolute": "^1.0.0" 883 | } 884 | }, 885 | "globby": { 886 | "version": "6.1.0", 887 | "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", 888 | "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", 889 | "dev": true, 890 | "requires": { 891 | "array-union": "^1.0.1", 892 | "glob": "^7.0.3", 893 | "object-assign": "^4.0.1", 894 | "pify": "^2.0.0", 895 | "pinkie-promise": "^2.0.0" 896 | }, 897 | "dependencies": { 898 | "pify": { 899 | "version": "2.3.0", 900 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 901 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 902 | "dev": true 903 | } 904 | } 905 | }, 906 | "has-ansi": { 907 | "version": "2.0.0", 908 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 909 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 910 | "dev": true, 911 | "requires": { 912 | "ansi-regex": "^2.0.0" 913 | } 914 | }, 915 | "has-flag": { 916 | "version": "3.0.0", 917 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 918 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 919 | "dev": true 920 | }, 921 | "has-value": { 922 | "version": "1.0.0", 923 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", 924 | "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", 925 | "dev": true, 926 | "requires": { 927 | "get-value": "^2.0.6", 928 | "has-values": "^1.0.0", 929 | "isobject": "^3.0.0" 930 | } 931 | }, 932 | "has-values": { 933 | "version": "1.0.0", 934 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", 935 | "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", 936 | "dev": true, 937 | "requires": { 938 | "is-number": "^3.0.0", 939 | "kind-of": "^4.0.0" 940 | }, 941 | "dependencies": { 942 | "kind-of": { 943 | "version": "4.0.0", 944 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", 945 | "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", 946 | "dev": true, 947 | "requires": { 948 | "is-buffer": "^1.1.5" 949 | } 950 | } 951 | } 952 | }, 953 | "hosted-git-info": { 954 | "version": "2.7.1", 955 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", 956 | "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", 957 | "dev": true 958 | }, 959 | "husky": { 960 | "version": "1.3.1", 961 | "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz", 962 | "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==", 963 | "dev": true, 964 | "requires": { 965 | "cosmiconfig": "^5.0.7", 966 | "execa": "^1.0.0", 967 | "find-up": "^3.0.0", 968 | "get-stdin": "^6.0.0", 969 | "is-ci": "^2.0.0", 970 | "pkg-dir": "^3.0.0", 971 | "please-upgrade-node": "^3.1.1", 972 | "read-pkg": "^4.0.1", 973 | "run-node": "^1.0.0", 974 | "slash": "^2.0.0" 975 | } 976 | }, 977 | "import-fresh": { 978 | "version": "2.0.0", 979 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", 980 | "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", 981 | "dev": true, 982 | "requires": { 983 | "caller-path": "^2.0.0", 984 | "resolve-from": "^3.0.0" 985 | } 986 | }, 987 | "indent-string": { 988 | "version": "3.2.0", 989 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", 990 | "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", 991 | "dev": true 992 | }, 993 | "inflight": { 994 | "version": "1.0.6", 995 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 996 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 997 | "dev": true, 998 | "requires": { 999 | "once": "^1.3.0", 1000 | "wrappy": "1" 1001 | } 1002 | }, 1003 | "inherits": { 1004 | "version": "2.0.3", 1005 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1006 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 1007 | "dev": true 1008 | }, 1009 | "is-accessor-descriptor": { 1010 | "version": "0.1.6", 1011 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 1012 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 1013 | "dev": true, 1014 | "requires": { 1015 | "kind-of": "^3.0.2" 1016 | }, 1017 | "dependencies": { 1018 | "kind-of": { 1019 | "version": "3.2.2", 1020 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1021 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1022 | "dev": true, 1023 | "requires": { 1024 | "is-buffer": "^1.1.5" 1025 | } 1026 | } 1027 | } 1028 | }, 1029 | "is-arrayish": { 1030 | "version": "0.2.1", 1031 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 1032 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 1033 | "dev": true 1034 | }, 1035 | "is-buffer": { 1036 | "version": "1.1.6", 1037 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 1038 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", 1039 | "dev": true 1040 | }, 1041 | "is-ci": { 1042 | "version": "2.0.0", 1043 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", 1044 | "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", 1045 | "dev": true, 1046 | "requires": { 1047 | "ci-info": "^2.0.0" 1048 | } 1049 | }, 1050 | "is-data-descriptor": { 1051 | "version": "0.1.4", 1052 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 1053 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 1054 | "dev": true, 1055 | "requires": { 1056 | "kind-of": "^3.0.2" 1057 | }, 1058 | "dependencies": { 1059 | "kind-of": { 1060 | "version": "3.2.2", 1061 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1062 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1063 | "dev": true, 1064 | "requires": { 1065 | "is-buffer": "^1.1.5" 1066 | } 1067 | } 1068 | } 1069 | }, 1070 | "is-descriptor": { 1071 | "version": "0.1.6", 1072 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 1073 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 1074 | "dev": true, 1075 | "requires": { 1076 | "is-accessor-descriptor": "^0.1.6", 1077 | "is-data-descriptor": "^0.1.4", 1078 | "kind-of": "^5.0.0" 1079 | }, 1080 | "dependencies": { 1081 | "kind-of": { 1082 | "version": "5.1.0", 1083 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 1084 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", 1085 | "dev": true 1086 | } 1087 | } 1088 | }, 1089 | "is-directory": { 1090 | "version": "0.3.1", 1091 | "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", 1092 | "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", 1093 | "dev": true 1094 | }, 1095 | "is-extendable": { 1096 | "version": "0.1.1", 1097 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 1098 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", 1099 | "dev": true 1100 | }, 1101 | "is-extglob": { 1102 | "version": "2.1.1", 1103 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1104 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 1105 | "dev": true 1106 | }, 1107 | "is-fullwidth-code-point": { 1108 | "version": "1.0.0", 1109 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 1110 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 1111 | "dev": true, 1112 | "requires": { 1113 | "number-is-nan": "^1.0.0" 1114 | } 1115 | }, 1116 | "is-glob": { 1117 | "version": "4.0.1", 1118 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 1119 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 1120 | "dev": true, 1121 | "requires": { 1122 | "is-extglob": "^2.1.1" 1123 | } 1124 | }, 1125 | "is-number": { 1126 | "version": "3.0.0", 1127 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", 1128 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", 1129 | "dev": true, 1130 | "requires": { 1131 | "kind-of": "^3.0.2" 1132 | }, 1133 | "dependencies": { 1134 | "kind-of": { 1135 | "version": "3.2.2", 1136 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1137 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1138 | "dev": true, 1139 | "requires": { 1140 | "is-buffer": "^1.1.5" 1141 | } 1142 | } 1143 | } 1144 | }, 1145 | "is-obj": { 1146 | "version": "1.0.1", 1147 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", 1148 | "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", 1149 | "dev": true 1150 | }, 1151 | "is-observable": { 1152 | "version": "1.1.0", 1153 | "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", 1154 | "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", 1155 | "dev": true, 1156 | "requires": { 1157 | "symbol-observable": "^1.1.0" 1158 | } 1159 | }, 1160 | "is-path-cwd": { 1161 | "version": "1.0.0", 1162 | "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", 1163 | "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", 1164 | "dev": true 1165 | }, 1166 | "is-path-in-cwd": { 1167 | "version": "1.0.1", 1168 | "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", 1169 | "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", 1170 | "dev": true, 1171 | "requires": { 1172 | "is-path-inside": "^1.0.0" 1173 | } 1174 | }, 1175 | "is-path-inside": { 1176 | "version": "1.0.1", 1177 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", 1178 | "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", 1179 | "dev": true, 1180 | "requires": { 1181 | "path-is-inside": "^1.0.1" 1182 | } 1183 | }, 1184 | "is-plain-object": { 1185 | "version": "2.0.4", 1186 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 1187 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 1188 | "dev": true, 1189 | "requires": { 1190 | "isobject": "^3.0.1" 1191 | } 1192 | }, 1193 | "is-promise": { 1194 | "version": "2.1.0", 1195 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 1196 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", 1197 | "dev": true 1198 | }, 1199 | "is-regexp": { 1200 | "version": "1.0.0", 1201 | "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", 1202 | "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", 1203 | "dev": true 1204 | }, 1205 | "is-stream": { 1206 | "version": "1.1.0", 1207 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 1208 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", 1209 | "dev": true 1210 | }, 1211 | "is-windows": { 1212 | "version": "1.0.2", 1213 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", 1214 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", 1215 | "dev": true 1216 | }, 1217 | "isarray": { 1218 | "version": "1.0.0", 1219 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1220 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 1221 | "dev": true 1222 | }, 1223 | "isexe": { 1224 | "version": "2.0.0", 1225 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1226 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1227 | "dev": true 1228 | }, 1229 | "isobject": { 1230 | "version": "3.0.1", 1231 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 1232 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", 1233 | "dev": true 1234 | }, 1235 | "js-tokens": { 1236 | "version": "3.0.2", 1237 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 1238 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 1239 | "dev": true 1240 | }, 1241 | "js-yaml": { 1242 | "version": "3.13.1", 1243 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 1244 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 1245 | "dev": true, 1246 | "requires": { 1247 | "argparse": "^1.0.7", 1248 | "esprima": "^4.0.0" 1249 | } 1250 | }, 1251 | "json-parse-better-errors": { 1252 | "version": "1.0.2", 1253 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", 1254 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", 1255 | "dev": true 1256 | }, 1257 | "kind-of": { 1258 | "version": "6.0.2", 1259 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", 1260 | "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", 1261 | "dev": true 1262 | }, 1263 | "kleur": { 1264 | "version": "2.0.2", 1265 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz", 1266 | "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==", 1267 | "dev": true 1268 | }, 1269 | "lint-staged": { 1270 | "version": "8.1.5", 1271 | "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.5.tgz", 1272 | "integrity": "sha512-e5ZavfnSLcBJE1BTzRTqw6ly8OkqVyO3GL2M6teSmTBYQ/2BuueD5GIt2RPsP31u/vjKdexUyDCxSyK75q4BDA==", 1273 | "dev": true, 1274 | "requires": { 1275 | "chalk": "^2.3.1", 1276 | "commander": "^2.14.1", 1277 | "cosmiconfig": "^5.0.2", 1278 | "debug": "^3.1.0", 1279 | "dedent": "^0.7.0", 1280 | "del": "^3.0.0", 1281 | "execa": "^1.0.0", 1282 | "find-parent-dir": "^0.3.0", 1283 | "g-status": "^2.0.2", 1284 | "is-glob": "^4.0.0", 1285 | "is-windows": "^1.0.2", 1286 | "listr": "^0.14.2", 1287 | "listr-update-renderer": "^0.5.0", 1288 | "lodash": "^4.17.11", 1289 | "log-symbols": "^2.2.0", 1290 | "micromatch": "^3.1.8", 1291 | "npm-which": "^3.0.1", 1292 | "p-map": "^1.1.1", 1293 | "path-is-inside": "^1.0.2", 1294 | "pify": "^3.0.0", 1295 | "please-upgrade-node": "^3.0.2", 1296 | "staged-git-files": "1.1.2", 1297 | "string-argv": "^0.0.2", 1298 | "stringify-object": "^3.2.2", 1299 | "yup": "^0.26.10" 1300 | } 1301 | }, 1302 | "listr": { 1303 | "version": "0.14.3", 1304 | "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", 1305 | "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", 1306 | "dev": true, 1307 | "requires": { 1308 | "@samverschueren/stream-to-observable": "^0.3.0", 1309 | "is-observable": "^1.1.0", 1310 | "is-promise": "^2.1.0", 1311 | "is-stream": "^1.1.0", 1312 | "listr-silent-renderer": "^1.1.1", 1313 | "listr-update-renderer": "^0.5.0", 1314 | "listr-verbose-renderer": "^0.5.0", 1315 | "p-map": "^2.0.0", 1316 | "rxjs": "^6.3.3" 1317 | }, 1318 | "dependencies": { 1319 | "p-map": { 1320 | "version": "2.1.0", 1321 | "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", 1322 | "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", 1323 | "dev": true 1324 | } 1325 | } 1326 | }, 1327 | "listr-silent-renderer": { 1328 | "version": "1.1.1", 1329 | "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", 1330 | "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", 1331 | "dev": true 1332 | }, 1333 | "listr-update-renderer": { 1334 | "version": "0.5.0", 1335 | "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", 1336 | "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", 1337 | "dev": true, 1338 | "requires": { 1339 | "chalk": "^1.1.3", 1340 | "cli-truncate": "^0.2.1", 1341 | "elegant-spinner": "^1.0.1", 1342 | "figures": "^1.7.0", 1343 | "indent-string": "^3.0.0", 1344 | "log-symbols": "^1.0.2", 1345 | "log-update": "^2.3.0", 1346 | "strip-ansi": "^3.0.1" 1347 | }, 1348 | "dependencies": { 1349 | "chalk": { 1350 | "version": "1.1.3", 1351 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 1352 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 1353 | "dev": true, 1354 | "requires": { 1355 | "ansi-styles": "^2.2.1", 1356 | "escape-string-regexp": "^1.0.2", 1357 | "has-ansi": "^2.0.0", 1358 | "strip-ansi": "^3.0.0", 1359 | "supports-color": "^2.0.0" 1360 | } 1361 | }, 1362 | "log-symbols": { 1363 | "version": "1.0.2", 1364 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", 1365 | "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", 1366 | "dev": true, 1367 | "requires": { 1368 | "chalk": "^1.0.0" 1369 | } 1370 | } 1371 | } 1372 | }, 1373 | "listr-verbose-renderer": { 1374 | "version": "0.5.0", 1375 | "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", 1376 | "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", 1377 | "dev": true, 1378 | "requires": { 1379 | "chalk": "^2.4.1", 1380 | "cli-cursor": "^2.1.0", 1381 | "date-fns": "^1.27.2", 1382 | "figures": "^2.0.0" 1383 | }, 1384 | "dependencies": { 1385 | "figures": { 1386 | "version": "2.0.0", 1387 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", 1388 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", 1389 | "dev": true, 1390 | "requires": { 1391 | "escape-string-regexp": "^1.0.5" 1392 | } 1393 | } 1394 | } 1395 | }, 1396 | "locate-path": { 1397 | "version": "3.0.0", 1398 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 1399 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 1400 | "dev": true, 1401 | "requires": { 1402 | "p-locate": "^3.0.0", 1403 | "path-exists": "^3.0.0" 1404 | } 1405 | }, 1406 | "lodash": { 1407 | "version": "4.17.11", 1408 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 1409 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", 1410 | "dev": true 1411 | }, 1412 | "log-symbols": { 1413 | "version": "2.2.0", 1414 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", 1415 | "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", 1416 | "dev": true, 1417 | "requires": { 1418 | "chalk": "^2.0.1" 1419 | } 1420 | }, 1421 | "log-update": { 1422 | "version": "2.3.0", 1423 | "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", 1424 | "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", 1425 | "dev": true, 1426 | "requires": { 1427 | "ansi-escapes": "^3.0.0", 1428 | "cli-cursor": "^2.0.0", 1429 | "wrap-ansi": "^3.0.1" 1430 | } 1431 | }, 1432 | "map-cache": { 1433 | "version": "0.2.2", 1434 | "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", 1435 | "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", 1436 | "dev": true 1437 | }, 1438 | "map-visit": { 1439 | "version": "1.0.0", 1440 | "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", 1441 | "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", 1442 | "dev": true, 1443 | "requires": { 1444 | "object-visit": "^1.0.0" 1445 | } 1446 | }, 1447 | "matcher": { 1448 | "version": "1.1.1", 1449 | "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", 1450 | "integrity": "sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==", 1451 | "dev": true, 1452 | "requires": { 1453 | "escape-string-regexp": "^1.0.4" 1454 | } 1455 | }, 1456 | "micromatch": { 1457 | "version": "3.1.10", 1458 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", 1459 | "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", 1460 | "dev": true, 1461 | "requires": { 1462 | "arr-diff": "^4.0.0", 1463 | "array-unique": "^0.3.2", 1464 | "braces": "^2.3.1", 1465 | "define-property": "^2.0.2", 1466 | "extend-shallow": "^3.0.2", 1467 | "extglob": "^2.0.4", 1468 | "fragment-cache": "^0.2.1", 1469 | "kind-of": "^6.0.2", 1470 | "nanomatch": "^1.2.9", 1471 | "object.pick": "^1.3.0", 1472 | "regex-not": "^1.0.0", 1473 | "snapdragon": "^0.8.1", 1474 | "to-regex": "^3.0.2" 1475 | } 1476 | }, 1477 | "mimic-fn": { 1478 | "version": "1.2.0", 1479 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 1480 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", 1481 | "dev": true 1482 | }, 1483 | "minimatch": { 1484 | "version": "3.0.4", 1485 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1486 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1487 | "dev": true, 1488 | "requires": { 1489 | "brace-expansion": "^1.1.7" 1490 | } 1491 | }, 1492 | "mixin-deep": { 1493 | "version": "1.3.1", 1494 | "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", 1495 | "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", 1496 | "dev": true, 1497 | "requires": { 1498 | "for-in": "^1.0.2", 1499 | "is-extendable": "^1.0.1" 1500 | }, 1501 | "dependencies": { 1502 | "is-extendable": { 1503 | "version": "1.0.1", 1504 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 1505 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 1506 | "dev": true, 1507 | "requires": { 1508 | "is-plain-object": "^2.0.4" 1509 | } 1510 | } 1511 | } 1512 | }, 1513 | "ms": { 1514 | "version": "2.1.1", 1515 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 1516 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 1517 | "dev": true 1518 | }, 1519 | "nanomatch": { 1520 | "version": "1.2.13", 1521 | "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", 1522 | "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", 1523 | "dev": true, 1524 | "requires": { 1525 | "arr-diff": "^4.0.0", 1526 | "array-unique": "^0.3.2", 1527 | "define-property": "^2.0.2", 1528 | "extend-shallow": "^3.0.2", 1529 | "fragment-cache": "^0.2.1", 1530 | "is-windows": "^1.0.2", 1531 | "kind-of": "^6.0.2", 1532 | "object.pick": "^1.3.0", 1533 | "regex-not": "^1.0.0", 1534 | "snapdragon": "^0.8.1", 1535 | "to-regex": "^3.0.1" 1536 | } 1537 | }, 1538 | "nice-try": { 1539 | "version": "1.0.5", 1540 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 1541 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 1542 | "dev": true 1543 | }, 1544 | "normalize-package-data": { 1545 | "version": "2.5.0", 1546 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", 1547 | "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", 1548 | "dev": true, 1549 | "requires": { 1550 | "hosted-git-info": "^2.1.4", 1551 | "resolve": "^1.10.0", 1552 | "semver": "2 || 3 || 4 || 5", 1553 | "validate-npm-package-license": "^3.0.1" 1554 | }, 1555 | "dependencies": { 1556 | "resolve": { 1557 | "version": "1.10.0", 1558 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", 1559 | "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", 1560 | "dev": true, 1561 | "requires": { 1562 | "path-parse": "^1.0.6" 1563 | } 1564 | } 1565 | } 1566 | }, 1567 | "npm-path": { 1568 | "version": "2.0.4", 1569 | "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", 1570 | "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", 1571 | "dev": true, 1572 | "requires": { 1573 | "which": "^1.2.10" 1574 | } 1575 | }, 1576 | "npm-run-path": { 1577 | "version": "2.0.2", 1578 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", 1579 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", 1580 | "dev": true, 1581 | "requires": { 1582 | "path-key": "^2.0.0" 1583 | } 1584 | }, 1585 | "npm-which": { 1586 | "version": "3.0.1", 1587 | "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", 1588 | "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", 1589 | "dev": true, 1590 | "requires": { 1591 | "commander": "^2.9.0", 1592 | "npm-path": "^2.0.2", 1593 | "which": "^1.2.10" 1594 | } 1595 | }, 1596 | "number-is-nan": { 1597 | "version": "1.0.1", 1598 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1599 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 1600 | "dev": true 1601 | }, 1602 | "object-assign": { 1603 | "version": "4.1.1", 1604 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1605 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1606 | "dev": true 1607 | }, 1608 | "object-copy": { 1609 | "version": "0.1.0", 1610 | "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", 1611 | "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", 1612 | "dev": true, 1613 | "requires": { 1614 | "copy-descriptor": "^0.1.0", 1615 | "define-property": "^0.2.5", 1616 | "kind-of": "^3.0.3" 1617 | }, 1618 | "dependencies": { 1619 | "define-property": { 1620 | "version": "0.2.5", 1621 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 1622 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 1623 | "dev": true, 1624 | "requires": { 1625 | "is-descriptor": "^0.1.0" 1626 | } 1627 | }, 1628 | "kind-of": { 1629 | "version": "3.2.2", 1630 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1631 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1632 | "dev": true, 1633 | "requires": { 1634 | "is-buffer": "^1.1.5" 1635 | } 1636 | } 1637 | } 1638 | }, 1639 | "object-visit": { 1640 | "version": "1.0.1", 1641 | "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", 1642 | "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", 1643 | "dev": true, 1644 | "requires": { 1645 | "isobject": "^3.0.0" 1646 | } 1647 | }, 1648 | "object.pick": { 1649 | "version": "1.3.0", 1650 | "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", 1651 | "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", 1652 | "dev": true, 1653 | "requires": { 1654 | "isobject": "^3.0.1" 1655 | } 1656 | }, 1657 | "once": { 1658 | "version": "1.4.0", 1659 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1660 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1661 | "dev": true, 1662 | "requires": { 1663 | "wrappy": "1" 1664 | } 1665 | }, 1666 | "onetime": { 1667 | "version": "2.0.1", 1668 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 1669 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 1670 | "dev": true, 1671 | "requires": { 1672 | "mimic-fn": "^1.0.0" 1673 | } 1674 | }, 1675 | "p-finally": { 1676 | "version": "1.0.0", 1677 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 1678 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", 1679 | "dev": true 1680 | }, 1681 | "p-limit": { 1682 | "version": "2.2.0", 1683 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", 1684 | "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", 1685 | "dev": true, 1686 | "requires": { 1687 | "p-try": "^2.0.0" 1688 | } 1689 | }, 1690 | "p-locate": { 1691 | "version": "3.0.0", 1692 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 1693 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 1694 | "dev": true, 1695 | "requires": { 1696 | "p-limit": "^2.0.0" 1697 | } 1698 | }, 1699 | "p-map": { 1700 | "version": "1.2.0", 1701 | "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", 1702 | "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", 1703 | "dev": true 1704 | }, 1705 | "p-try": { 1706 | "version": "2.2.0", 1707 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 1708 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 1709 | "dev": true 1710 | }, 1711 | "parse-json": { 1712 | "version": "4.0.0", 1713 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", 1714 | "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", 1715 | "dev": true, 1716 | "requires": { 1717 | "error-ex": "^1.3.1", 1718 | "json-parse-better-errors": "^1.0.1" 1719 | } 1720 | }, 1721 | "pascalcase": { 1722 | "version": "0.1.1", 1723 | "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", 1724 | "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", 1725 | "dev": true 1726 | }, 1727 | "path-exists": { 1728 | "version": "3.0.0", 1729 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1730 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 1731 | "dev": true 1732 | }, 1733 | "path-is-absolute": { 1734 | "version": "1.0.1", 1735 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1736 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1737 | "dev": true 1738 | }, 1739 | "path-is-inside": { 1740 | "version": "1.0.2", 1741 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 1742 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 1743 | "dev": true 1744 | }, 1745 | "path-key": { 1746 | "version": "2.0.1", 1747 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 1748 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 1749 | "dev": true 1750 | }, 1751 | "path-parse": { 1752 | "version": "1.0.6", 1753 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1754 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 1755 | "dev": true 1756 | }, 1757 | "pify": { 1758 | "version": "3.0.0", 1759 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 1760 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", 1761 | "dev": true 1762 | }, 1763 | "pinkie": { 1764 | "version": "2.0.4", 1765 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 1766 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 1767 | "dev": true 1768 | }, 1769 | "pinkie-promise": { 1770 | "version": "2.0.1", 1771 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 1772 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 1773 | "dev": true, 1774 | "requires": { 1775 | "pinkie": "^2.0.0" 1776 | } 1777 | }, 1778 | "pkg-dir": { 1779 | "version": "3.0.0", 1780 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", 1781 | "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", 1782 | "dev": true, 1783 | "requires": { 1784 | "find-up": "^3.0.0" 1785 | } 1786 | }, 1787 | "please-upgrade-node": { 1788 | "version": "3.1.1", 1789 | "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", 1790 | "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", 1791 | "dev": true, 1792 | "requires": { 1793 | "semver-compare": "^1.0.0" 1794 | } 1795 | }, 1796 | "posix-character-classes": { 1797 | "version": "0.1.1", 1798 | "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", 1799 | "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", 1800 | "dev": true 1801 | }, 1802 | "prettier": { 1803 | "version": "1.17.0", 1804 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.17.0.tgz", 1805 | "integrity": "sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw==", 1806 | "dev": true 1807 | }, 1808 | "prompts": { 1809 | "version": "1.1.0", 1810 | "resolved": "https://registry.npmjs.org/prompts/-/prompts-1.1.0.tgz", 1811 | "integrity": "sha512-VbHgVvxagRhlvKA/y3UXdYZnvD9A5CMmBmqnxqW/UY6vLSnG7QaB7w+gZeZ5m0ZXUCY66fBCS1Qp9fn8BsZhNw==", 1812 | "dev": true, 1813 | "requires": { 1814 | "kleur": "^2.0.1", 1815 | "sisteransi": "^1.0.0" 1816 | } 1817 | }, 1818 | "property-expr": { 1819 | "version": "1.5.1", 1820 | "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", 1821 | "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", 1822 | "dev": true 1823 | }, 1824 | "pump": { 1825 | "version": "3.0.0", 1826 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 1827 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 1828 | "dev": true, 1829 | "requires": { 1830 | "end-of-stream": "^1.1.0", 1831 | "once": "^1.3.1" 1832 | } 1833 | }, 1834 | "read-pkg": { 1835 | "version": "4.0.1", 1836 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", 1837 | "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", 1838 | "dev": true, 1839 | "requires": { 1840 | "normalize-package-data": "^2.3.2", 1841 | "parse-json": "^4.0.0", 1842 | "pify": "^3.0.0" 1843 | } 1844 | }, 1845 | "regenerator-runtime": { 1846 | "version": "0.12.1", 1847 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", 1848 | "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", 1849 | "dev": true 1850 | }, 1851 | "regex-not": { 1852 | "version": "1.0.2", 1853 | "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", 1854 | "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", 1855 | "dev": true, 1856 | "requires": { 1857 | "extend-shallow": "^3.0.2", 1858 | "safe-regex": "^1.1.0" 1859 | } 1860 | }, 1861 | "repeat-element": { 1862 | "version": "1.1.3", 1863 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", 1864 | "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", 1865 | "dev": true 1866 | }, 1867 | "repeat-string": { 1868 | "version": "1.6.1", 1869 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 1870 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", 1871 | "dev": true 1872 | }, 1873 | "resolve": { 1874 | "version": "1.8.1", 1875 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", 1876 | "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", 1877 | "dev": true, 1878 | "requires": { 1879 | "path-parse": "^1.0.5" 1880 | } 1881 | }, 1882 | "resolve-from": { 1883 | "version": "3.0.0", 1884 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", 1885 | "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", 1886 | "dev": true 1887 | }, 1888 | "resolve-url": { 1889 | "version": "0.2.1", 1890 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", 1891 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", 1892 | "dev": true 1893 | }, 1894 | "restore-cursor": { 1895 | "version": "2.0.0", 1896 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 1897 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 1898 | "dev": true, 1899 | "requires": { 1900 | "onetime": "^2.0.0", 1901 | "signal-exit": "^3.0.2" 1902 | } 1903 | }, 1904 | "ret": { 1905 | "version": "0.1.15", 1906 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", 1907 | "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", 1908 | "dev": true 1909 | }, 1910 | "rimraf": { 1911 | "version": "2.6.3", 1912 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 1913 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 1914 | "dev": true, 1915 | "requires": { 1916 | "glob": "^7.1.3" 1917 | } 1918 | }, 1919 | "run-node": { 1920 | "version": "1.0.0", 1921 | "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", 1922 | "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", 1923 | "dev": true 1924 | }, 1925 | "rxjs": { 1926 | "version": "6.4.0", 1927 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", 1928 | "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", 1929 | "dev": true, 1930 | "requires": { 1931 | "tslib": "^1.9.0" 1932 | } 1933 | }, 1934 | "safe-regex": { 1935 | "version": "1.1.0", 1936 | "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", 1937 | "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", 1938 | "dev": true, 1939 | "requires": { 1940 | "ret": "~0.1.10" 1941 | } 1942 | }, 1943 | "semver": { 1944 | "version": "5.5.1", 1945 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", 1946 | "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", 1947 | "dev": true 1948 | }, 1949 | "semver-compare": { 1950 | "version": "1.0.0", 1951 | "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", 1952 | "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", 1953 | "dev": true 1954 | }, 1955 | "set-value": { 1956 | "version": "2.0.0", 1957 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", 1958 | "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", 1959 | "dev": true, 1960 | "requires": { 1961 | "extend-shallow": "^2.0.1", 1962 | "is-extendable": "^0.1.1", 1963 | "is-plain-object": "^2.0.3", 1964 | "split-string": "^3.0.1" 1965 | }, 1966 | "dependencies": { 1967 | "extend-shallow": { 1968 | "version": "2.0.1", 1969 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 1970 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 1971 | "dev": true, 1972 | "requires": { 1973 | "is-extendable": "^0.1.0" 1974 | } 1975 | } 1976 | } 1977 | }, 1978 | "shebang-command": { 1979 | "version": "1.2.0", 1980 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1981 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1982 | "dev": true, 1983 | "requires": { 1984 | "shebang-regex": "^1.0.0" 1985 | } 1986 | }, 1987 | "shebang-regex": { 1988 | "version": "1.0.0", 1989 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1990 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1991 | "dev": true 1992 | }, 1993 | "signal-exit": { 1994 | "version": "3.0.2", 1995 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1996 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1997 | "dev": true 1998 | }, 1999 | "simple-git": { 2000 | "version": "1.110.0", 2001 | "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.110.0.tgz", 2002 | "integrity": "sha512-UYY0rQkknk0P5eb+KW+03F4TevZ9ou0H+LoGaj7iiVgpnZH4wdj/HTViy/1tNNkmIPcmtxuBqXWiYt2YwlRKOQ==", 2003 | "dev": true, 2004 | "requires": { 2005 | "debug": "^4.0.1" 2006 | }, 2007 | "dependencies": { 2008 | "debug": { 2009 | "version": "4.1.1", 2010 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 2011 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 2012 | "dev": true, 2013 | "requires": { 2014 | "ms": "^2.1.1" 2015 | } 2016 | } 2017 | } 2018 | }, 2019 | "sisteransi": { 2020 | "version": "1.0.0", 2021 | "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.0.tgz", 2022 | "integrity": "sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ==", 2023 | "dev": true 2024 | }, 2025 | "slash": { 2026 | "version": "2.0.0", 2027 | "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", 2028 | "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", 2029 | "dev": true 2030 | }, 2031 | "slice-ansi": { 2032 | "version": "0.0.4", 2033 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", 2034 | "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", 2035 | "dev": true 2036 | }, 2037 | "snapdragon": { 2038 | "version": "0.8.2", 2039 | "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", 2040 | "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", 2041 | "dev": true, 2042 | "requires": { 2043 | "base": "^0.11.1", 2044 | "debug": "^2.2.0", 2045 | "define-property": "^0.2.5", 2046 | "extend-shallow": "^2.0.1", 2047 | "map-cache": "^0.2.2", 2048 | "source-map": "^0.5.6", 2049 | "source-map-resolve": "^0.5.0", 2050 | "use": "^3.1.0" 2051 | }, 2052 | "dependencies": { 2053 | "debug": { 2054 | "version": "2.6.9", 2055 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 2056 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 2057 | "dev": true, 2058 | "requires": { 2059 | "ms": "2.0.0" 2060 | } 2061 | }, 2062 | "define-property": { 2063 | "version": "0.2.5", 2064 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 2065 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 2066 | "dev": true, 2067 | "requires": { 2068 | "is-descriptor": "^0.1.0" 2069 | } 2070 | }, 2071 | "extend-shallow": { 2072 | "version": "2.0.1", 2073 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 2074 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 2075 | "dev": true, 2076 | "requires": { 2077 | "is-extendable": "^0.1.0" 2078 | } 2079 | }, 2080 | "ms": { 2081 | "version": "2.0.0", 2082 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 2083 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 2084 | "dev": true 2085 | } 2086 | } 2087 | }, 2088 | "snapdragon-node": { 2089 | "version": "2.1.1", 2090 | "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", 2091 | "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", 2092 | "dev": true, 2093 | "requires": { 2094 | "define-property": "^1.0.0", 2095 | "isobject": "^3.0.0", 2096 | "snapdragon-util": "^3.0.1" 2097 | }, 2098 | "dependencies": { 2099 | "define-property": { 2100 | "version": "1.0.0", 2101 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 2102 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 2103 | "dev": true, 2104 | "requires": { 2105 | "is-descriptor": "^1.0.0" 2106 | } 2107 | }, 2108 | "is-accessor-descriptor": { 2109 | "version": "1.0.0", 2110 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 2111 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 2112 | "dev": true, 2113 | "requires": { 2114 | "kind-of": "^6.0.0" 2115 | } 2116 | }, 2117 | "is-data-descriptor": { 2118 | "version": "1.0.0", 2119 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 2120 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 2121 | "dev": true, 2122 | "requires": { 2123 | "kind-of": "^6.0.0" 2124 | } 2125 | }, 2126 | "is-descriptor": { 2127 | "version": "1.0.2", 2128 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 2129 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 2130 | "dev": true, 2131 | "requires": { 2132 | "is-accessor-descriptor": "^1.0.0", 2133 | "is-data-descriptor": "^1.0.0", 2134 | "kind-of": "^6.0.2" 2135 | } 2136 | } 2137 | } 2138 | }, 2139 | "snapdragon-util": { 2140 | "version": "3.0.1", 2141 | "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", 2142 | "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", 2143 | "dev": true, 2144 | "requires": { 2145 | "kind-of": "^3.2.0" 2146 | }, 2147 | "dependencies": { 2148 | "kind-of": { 2149 | "version": "3.2.2", 2150 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 2151 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 2152 | "dev": true, 2153 | "requires": { 2154 | "is-buffer": "^1.1.5" 2155 | } 2156 | } 2157 | } 2158 | }, 2159 | "source-map": { 2160 | "version": "0.5.7", 2161 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 2162 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 2163 | "dev": true 2164 | }, 2165 | "source-map-resolve": { 2166 | "version": "0.5.2", 2167 | "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", 2168 | "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", 2169 | "dev": true, 2170 | "requires": { 2171 | "atob": "^2.1.1", 2172 | "decode-uri-component": "^0.2.0", 2173 | "resolve-url": "^0.2.1", 2174 | "source-map-url": "^0.4.0", 2175 | "urix": "^0.1.0" 2176 | } 2177 | }, 2178 | "source-map-url": { 2179 | "version": "0.4.0", 2180 | "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", 2181 | "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", 2182 | "dev": true 2183 | }, 2184 | "spdx-correct": { 2185 | "version": "3.1.0", 2186 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", 2187 | "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", 2188 | "dev": true, 2189 | "requires": { 2190 | "spdx-expression-parse": "^3.0.0", 2191 | "spdx-license-ids": "^3.0.0" 2192 | } 2193 | }, 2194 | "spdx-exceptions": { 2195 | "version": "2.2.0", 2196 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", 2197 | "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", 2198 | "dev": true 2199 | }, 2200 | "spdx-expression-parse": { 2201 | "version": "3.0.0", 2202 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", 2203 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", 2204 | "dev": true, 2205 | "requires": { 2206 | "spdx-exceptions": "^2.1.0", 2207 | "spdx-license-ids": "^3.0.0" 2208 | } 2209 | }, 2210 | "spdx-license-ids": { 2211 | "version": "3.0.4", 2212 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", 2213 | "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", 2214 | "dev": true 2215 | }, 2216 | "split-string": { 2217 | "version": "3.1.0", 2218 | "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", 2219 | "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", 2220 | "dev": true, 2221 | "requires": { 2222 | "extend-shallow": "^3.0.0" 2223 | } 2224 | }, 2225 | "sprintf-js": { 2226 | "version": "1.0.3", 2227 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 2228 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 2229 | "dev": true 2230 | }, 2231 | "staged-git-files": { 2232 | "version": "1.1.2", 2233 | "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz", 2234 | "integrity": "sha512-0Eyrk6uXW6tg9PYkhi/V/J4zHp33aNyi2hOCmhFLqLTIhbgqWn5jlSzI+IU0VqrZq6+DbHcabQl/WP6P3BG0QA==", 2235 | "dev": true 2236 | }, 2237 | "static-extend": { 2238 | "version": "0.1.2", 2239 | "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", 2240 | "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", 2241 | "dev": true, 2242 | "requires": { 2243 | "define-property": "^0.2.5", 2244 | "object-copy": "^0.1.0" 2245 | }, 2246 | "dependencies": { 2247 | "define-property": { 2248 | "version": "0.2.5", 2249 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 2250 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 2251 | "dev": true, 2252 | "requires": { 2253 | "is-descriptor": "^0.1.0" 2254 | } 2255 | } 2256 | } 2257 | }, 2258 | "string-argv": { 2259 | "version": "0.0.2", 2260 | "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", 2261 | "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", 2262 | "dev": true 2263 | }, 2264 | "string-width": { 2265 | "version": "1.0.2", 2266 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 2267 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 2268 | "dev": true, 2269 | "requires": { 2270 | "code-point-at": "^1.0.0", 2271 | "is-fullwidth-code-point": "^1.0.0", 2272 | "strip-ansi": "^3.0.0" 2273 | } 2274 | }, 2275 | "stringify-object": { 2276 | "version": "3.3.0", 2277 | "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", 2278 | "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", 2279 | "dev": true, 2280 | "requires": { 2281 | "get-own-enumerable-property-symbols": "^3.0.0", 2282 | "is-obj": "^1.0.1", 2283 | "is-regexp": "^1.0.0" 2284 | } 2285 | }, 2286 | "strip-ansi": { 2287 | "version": "3.0.1", 2288 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 2289 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 2290 | "dev": true, 2291 | "requires": { 2292 | "ansi-regex": "^2.0.0" 2293 | } 2294 | }, 2295 | "strip-eof": { 2296 | "version": "1.0.0", 2297 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", 2298 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", 2299 | "dev": true 2300 | }, 2301 | "supports-color": { 2302 | "version": "2.0.0", 2303 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 2304 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 2305 | "dev": true 2306 | }, 2307 | "symbol-observable": { 2308 | "version": "1.2.0", 2309 | "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", 2310 | "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", 2311 | "dev": true 2312 | }, 2313 | "synchronous-promise": { 2314 | "version": "2.0.7", 2315 | "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.7.tgz", 2316 | "integrity": "sha512-16GbgwTmFMYFyQMLvtQjvNWh30dsFe1cAW5Fg1wm5+dg84L9Pe36mftsIRU95/W2YsISxsz/xq4VB23sqpgb/A==", 2317 | "dev": true 2318 | }, 2319 | "to-object-path": { 2320 | "version": "0.3.0", 2321 | "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", 2322 | "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", 2323 | "dev": true, 2324 | "requires": { 2325 | "kind-of": "^3.0.2" 2326 | }, 2327 | "dependencies": { 2328 | "kind-of": { 2329 | "version": "3.2.2", 2330 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 2331 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 2332 | "dev": true, 2333 | "requires": { 2334 | "is-buffer": "^1.1.5" 2335 | } 2336 | } 2337 | } 2338 | }, 2339 | "to-regex": { 2340 | "version": "3.0.2", 2341 | "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", 2342 | "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", 2343 | "dev": true, 2344 | "requires": { 2345 | "define-property": "^2.0.2", 2346 | "extend-shallow": "^3.0.2", 2347 | "regex-not": "^1.0.2", 2348 | "safe-regex": "^1.1.0" 2349 | } 2350 | }, 2351 | "to-regex-range": { 2352 | "version": "2.1.1", 2353 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", 2354 | "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", 2355 | "dev": true, 2356 | "requires": { 2357 | "is-number": "^3.0.0", 2358 | "repeat-string": "^1.6.1" 2359 | } 2360 | }, 2361 | "toposort": { 2362 | "version": "2.0.2", 2363 | "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", 2364 | "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=", 2365 | "dev": true 2366 | }, 2367 | "tslib": { 2368 | "version": "1.9.3", 2369 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", 2370 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", 2371 | "dev": true 2372 | }, 2373 | "tslint": { 2374 | "version": "5.11.0", 2375 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz", 2376 | "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", 2377 | "dev": true, 2378 | "requires": { 2379 | "babel-code-frame": "^6.22.0", 2380 | "builtin-modules": "^1.1.1", 2381 | "chalk": "^2.3.0", 2382 | "commander": "^2.12.1", 2383 | "diff": "^3.2.0", 2384 | "glob": "^7.1.1", 2385 | "js-yaml": "^3.7.0", 2386 | "minimatch": "^3.0.4", 2387 | "resolve": "^1.3.2", 2388 | "semver": "^5.3.0", 2389 | "tslib": "^1.8.0", 2390 | "tsutils": "^2.27.2" 2391 | } 2392 | }, 2393 | "tsutils": { 2394 | "version": "2.29.0", 2395 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 2396 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 2397 | "dev": true, 2398 | "requires": { 2399 | "tslib": "^1.8.1" 2400 | } 2401 | }, 2402 | "typescript": { 2403 | "version": "3.0.1", 2404 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.0.1.tgz", 2405 | "integrity": "sha512-zQIMOmC+372pC/CCVLqnQ0zSBiY7HHodU7mpQdjiZddek4GMj31I3dUJ7gAs9o65X7mnRma6OokOkc6f9jjfBg==", 2406 | "dev": true 2407 | }, 2408 | "union-value": { 2409 | "version": "1.0.0", 2410 | "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", 2411 | "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", 2412 | "dev": true, 2413 | "requires": { 2414 | "arr-union": "^3.1.0", 2415 | "get-value": "^2.0.6", 2416 | "is-extendable": "^0.1.1", 2417 | "set-value": "^0.4.3" 2418 | }, 2419 | "dependencies": { 2420 | "extend-shallow": { 2421 | "version": "2.0.1", 2422 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 2423 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 2424 | "dev": true, 2425 | "requires": { 2426 | "is-extendable": "^0.1.0" 2427 | } 2428 | }, 2429 | "set-value": { 2430 | "version": "0.4.3", 2431 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", 2432 | "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", 2433 | "dev": true, 2434 | "requires": { 2435 | "extend-shallow": "^2.0.1", 2436 | "is-extendable": "^0.1.1", 2437 | "is-plain-object": "^2.0.1", 2438 | "to-object-path": "^0.3.0" 2439 | } 2440 | } 2441 | } 2442 | }, 2443 | "unset-value": { 2444 | "version": "1.0.0", 2445 | "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", 2446 | "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", 2447 | "dev": true, 2448 | "requires": { 2449 | "has-value": "^0.3.1", 2450 | "isobject": "^3.0.0" 2451 | }, 2452 | "dependencies": { 2453 | "has-value": { 2454 | "version": "0.3.1", 2455 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", 2456 | "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", 2457 | "dev": true, 2458 | "requires": { 2459 | "get-value": "^2.0.3", 2460 | "has-values": "^0.1.4", 2461 | "isobject": "^2.0.0" 2462 | }, 2463 | "dependencies": { 2464 | "isobject": { 2465 | "version": "2.1.0", 2466 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", 2467 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", 2468 | "dev": true, 2469 | "requires": { 2470 | "isarray": "1.0.0" 2471 | } 2472 | } 2473 | } 2474 | }, 2475 | "has-values": { 2476 | "version": "0.1.4", 2477 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", 2478 | "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", 2479 | "dev": true 2480 | } 2481 | } 2482 | }, 2483 | "urix": { 2484 | "version": "0.1.0", 2485 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", 2486 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", 2487 | "dev": true 2488 | }, 2489 | "use": { 2490 | "version": "3.1.1", 2491 | "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", 2492 | "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", 2493 | "dev": true 2494 | }, 2495 | "validate-npm-package-license": { 2496 | "version": "3.0.4", 2497 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 2498 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 2499 | "dev": true, 2500 | "requires": { 2501 | "spdx-correct": "^3.0.0", 2502 | "spdx-expression-parse": "^3.0.0" 2503 | } 2504 | }, 2505 | "which": { 2506 | "version": "1.3.1", 2507 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 2508 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 2509 | "dev": true, 2510 | "requires": { 2511 | "isexe": "^2.0.0" 2512 | } 2513 | }, 2514 | "wrap-ansi": { 2515 | "version": "3.0.1", 2516 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", 2517 | "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", 2518 | "dev": true, 2519 | "requires": { 2520 | "string-width": "^2.1.1", 2521 | "strip-ansi": "^4.0.0" 2522 | }, 2523 | "dependencies": { 2524 | "ansi-regex": { 2525 | "version": "3.0.0", 2526 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 2527 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 2528 | "dev": true 2529 | }, 2530 | "is-fullwidth-code-point": { 2531 | "version": "2.0.0", 2532 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 2533 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 2534 | "dev": true 2535 | }, 2536 | "string-width": { 2537 | "version": "2.1.1", 2538 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 2539 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 2540 | "dev": true, 2541 | "requires": { 2542 | "is-fullwidth-code-point": "^2.0.0", 2543 | "strip-ansi": "^4.0.0" 2544 | } 2545 | }, 2546 | "strip-ansi": { 2547 | "version": "4.0.0", 2548 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 2549 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 2550 | "dev": true, 2551 | "requires": { 2552 | "ansi-regex": "^3.0.0" 2553 | } 2554 | } 2555 | } 2556 | }, 2557 | "wrappy": { 2558 | "version": "1.0.2", 2559 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2560 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2561 | "dev": true 2562 | }, 2563 | "yup": { 2564 | "version": "0.26.10", 2565 | "resolved": "https://registry.npmjs.org/yup/-/yup-0.26.10.tgz", 2566 | "integrity": "sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw==", 2567 | "dev": true, 2568 | "requires": { 2569 | "@babel/runtime": "7.0.0", 2570 | "fn-name": "~2.0.1", 2571 | "lodash": "^4.17.10", 2572 | "property-expr": "^1.5.0", 2573 | "synchronous-promise": "^2.0.5", 2574 | "toposort": "^2.0.2" 2575 | } 2576 | } 2577 | } 2578 | } 2579 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tslint-stencil", 3 | "version": "1.0.1", 4 | "description": "Adds stylistic rules to tslint for Stencil projects", 5 | "keywords": [ 6 | "tslint", 7 | "rules", 8 | "stencil", 9 | "stenciljs" 10 | ], 11 | "main": "rules/index.js", 12 | "directories": { 13 | "test": "test" 14 | }, 15 | "scripts": { 16 | "compile": "tsc", 17 | "build": "rm -rf rules && npm run compile && npm run docs", 18 | "test": "tslint --test test/rules/**/*", 19 | "verify": "npm run build && npm run test", 20 | "commit": "node scripts/commit", 21 | "predocs": "rm -rf docs", 22 | "docs": "node scripts/docs" 23 | }, 24 | "author": "Nate Moore", 25 | "contributors": [ 26 | { 27 | "name": "Nate Moore", 28 | "email": "nate@natemoo.re", 29 | "url": "https://natemoo.re" 30 | } 31 | ], 32 | "repository": { 33 | "type": "git", 34 | "url": "git+https://github.com/natemoo-re/tslint-stencil.git" 35 | }, 36 | "license": "MIT", 37 | "devDependencies": { 38 | "@types/node": "^10.9.2", 39 | "cli-spinner": "^0.2.8", 40 | "colorette": "^1.0.1", 41 | "husky": "^1.3.1", 42 | "lint-staged": "^8.1.5", 43 | "prettier": "^1.17.0", 44 | "prompts": "^1.1.0", 45 | "tslint": "^5.11.0", 46 | "typescript": "^3.0.1" 47 | }, 48 | "husky": { 49 | "hooks": { 50 | "pre-commit": "lint-staged" 51 | } 52 | }, 53 | "lint-staged": { 54 | "*.{js,ts,json,md}": [ 55 | "prettier --write", 56 | "git add" 57 | ] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /scripts/commit.js: -------------------------------------------------------------------------------- 1 | const prompt = require("prompts"); 2 | const { run } = require("./shared/run"); 3 | const { dim } = require("colorette"); 4 | 5 | async function commit() { 6 | const TYPES = new Map([ 7 | ["feat", "A new feature"], 8 | ["fix", "A bug fix"], 9 | ["docs", "Documentation only changes"], 10 | [ 11 | "style", 12 | "Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)" 13 | ], 14 | ["refactor", "A code change that neither fixes a bug nor adds a feature"], 15 | ["perf", "A code change that improves performance"], 16 | ["test", "Adding missing tests"], 17 | [ 18 | "chore", 19 | "Changes to the build process or auxiliary tools and libraries such as documentation generation" 20 | ] 21 | ]); 22 | 23 | const typeChoices = []; 24 | for (let [key, doc] of TYPES.entries()) { 25 | typeChoices.push({ 26 | title: `${key} ${dim(doc)}`, 27 | value: key 28 | }); 29 | } 30 | 31 | // const scopeChoices = Array.from(new Set(SCOPES)).map(scope => ({ title: scope, value: scope })); 32 | 33 | const { type, scope, subject } = await prompt([ 34 | { 35 | type: "select", 36 | name: "type", 37 | message: "Select commit type", 38 | choices: typeChoices, 39 | initial: 0 40 | }, 41 | { 42 | type: "text", 43 | name: "scope", 44 | message: "Describe commit scope" 45 | }, 46 | { 47 | type: "text", 48 | name: "subject", 49 | message: "Describe commit subject", 50 | validate: value => { 51 | if (!value) return `Please enter a commit message`; 52 | return value.length > 50 53 | ? `Message must be shorter than 50 characters` 54 | : true; 55 | } 56 | } 57 | ]); 58 | 59 | if (!type || !subject) { 60 | process.exit(0); 61 | } 62 | 63 | const message = `${type}(${scope}): ${subject}`; 64 | return run(`git commit -m "${message}"`); 65 | } 66 | 67 | commit(); 68 | -------------------------------------------------------------------------------- /scripts/docs/README.js: -------------------------------------------------------------------------------- 1 | exports.README = ` 2 | # tslint-stencil 3 | Adds stylistic [tslint](https://github.com/palantir/tslint) rules for [Stencil](https://github.com/ionic-team/stencil) projects 4 | 5 | ## Getting started 6 | Add the following line to your \`tslint.json\` file to enable the default ruleset (which follows the [Stencil Style Guide](https://stenciljs.com/docs/style-guide)) 7 | 8 | \`\`\`json 9 | { 10 | "extends": ["tslint-stencil/default"], 11 | } 12 | \`\`\` 13 | 14 | Alternatively, you can extend the bare package and enable each [rule](#rules) on a individual basis 15 | \`\`\`json 16 | { 17 | "extends": ["tslint-stencil"], 18 | "rules": { 19 | "host-data-precedes-render": true 20 | } 21 | } 22 | \`\`\` 23 | 24 | ## Rules 25 | %docs% 26 | 27 | ## Contributing 28 | Rules in the \`src/\` directory must be **camelCased** and end in **Rule**. 29 | More information on developing custom tslint rules can be found on the [tslint site](https://palantir.github.io/tslint/develop/custom-rules/) 30 | 31 | Before adding your custom rule, be sure to write a test for it. Then, you should be able to verify that it works by running: 32 | \`\`\` 33 | npm run verify 34 | \`\`\` 35 | `; 36 | -------------------------------------------------------------------------------- /scripts/docs/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { promisify } = require("util"); 3 | const readdir = promisify(require("fs").readdir); 4 | const mkdir = promisify(require("fs").mkdir); 5 | const writeFile = promisify(require("fs").writeFile); 6 | const { render, renderREADME } = require("./render"); 7 | 8 | const cwd = path.join(".", "scripts"); 9 | 10 | async function docs() { 11 | const dir = path.resolve(cwd, path.join("..", "rules")); 12 | const files = await readdir(dir); 13 | const rules = files 14 | .filter(x => x.endsWith("js")) 15 | .filter(x => x !== "index.js") 16 | .map(async file => { 17 | const fileName = path.join(dir, file); 18 | try { 19 | const { Rule } = require(fileName); 20 | if (Rule) { 21 | const { metadata } = Rule; 22 | if (metadata) return metadata; 23 | 24 | throw new Error(fileToRuleName(file)); 25 | } else { 26 | throw new Error(fileToRuleName(file)); 27 | } 28 | } catch (e) { 29 | return { ruleName: e.message }; 30 | } 31 | }); 32 | 33 | let metadata = await Promise.all(rules); 34 | metadata = [...metadata].sort((a, b) => a.ruleName - b.ruleName); 35 | 36 | await writeReadme(metadata); 37 | } 38 | 39 | async function writeReadme(rules) { 40 | const docsPath = path.resolve(cwd, path.join("..", "docs")); 41 | const readmePath = path.resolve(cwd, path.join("..", "README.md")); 42 | const readmeContent = renderREADME(rules); 43 | 44 | await mkdir(docsPath); 45 | rules.map(async metadata => { 46 | const fileName = `${metadata.ruleName}.md`; 47 | const content = await render(metadata); 48 | await writeFile(path.join(docsPath, fileName), content); 49 | }); 50 | 51 | await writeFile(readmePath, readmeContent); 52 | return; 53 | } 54 | 55 | function camelToDash(str) { 56 | return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); 57 | } 58 | 59 | function fileToRuleName(str) { 60 | return camelToDash(str) 61 | .replace("-rule", "") 62 | .replace(".js", ""); 63 | } 64 | 65 | docs(); 66 | -------------------------------------------------------------------------------- /scripts/docs/render.js: -------------------------------------------------------------------------------- 1 | const { README } = require("./README"); 2 | 3 | // https://github.com/palantir/tslint/blob/0437cd9fc85d65f53dbecf0decdfb137171811b5/src/utils.ts#L66 4 | function dedent(strings, ...values) { 5 | let fullString = strings.reduce( 6 | (accumulator, str, i) => `${accumulator}${values[i - 1]}${str}` 7 | ); 8 | 9 | // match all leading spaces/tabs at the start of each line 10 | const match = fullString.match(/^[ \t]*(?=\S)/gm); 11 | if (match === null) { 12 | // e.g. if the string is empty or all whitespace. 13 | return fullString; 14 | } 15 | 16 | // find the smallest indent, we don't want to remove all leading whitespace 17 | const indent = Math.min(...match.map(el => el.length)); 18 | const regexp = new RegExp(`^[ \\t]{${indent}}`, "gm"); 19 | fullString = indent > 0 ? fullString.replace(regexp, "") : fullString; 20 | return fullString; 21 | } 22 | 23 | function renderDescription(metadata) { 24 | const details = metadata.descriptionDetails 25 | ? `\n${metadata.descriptionDetails}` 26 | : ""; 27 | return metadata.description ? `${metadata.description}${details}` : false; 28 | } 29 | 30 | function renderNotes(metadata) { 31 | const notes = []; 32 | // Stencil is always written in Typescript 33 | // So let's ignore this... (just know it's there) 34 | // if (metadata.typescriptOnly) notes.push(`📄 TS Only`); 35 | if (metadata.hasFix) notes.push("**`🛠 Has Fixer`**"); 36 | if (metadata.requiresTypeInfo) notes.push("**`ℹ️ Requires Type Info`**"); 37 | 38 | return notes.length ? notes.join(" | ") : false; 39 | } 40 | 41 | function renderRationale(metadata) { 42 | return metadata.rationale 43 | ? `## Rationale 44 | ${metadata.rationale}` 45 | : false; 46 | } 47 | 48 | function renderConfig(metadata) { 49 | const config = [ 50 | "## Config", 51 | metadata.optionsDescription 52 | ? metadata.optionsDescription 53 | : "Not configurable.", 54 | "", 55 | "### Config examples", 56 | [...(metadata.optionExamples || [`{ "${metadata.ruleName}": true }`])] 57 | .map(x => "```ts\n" + x.trim() + "\n```") 58 | .join("\n") 59 | ].join("\n"); 60 | 61 | return config; 62 | } 63 | 64 | function renderSchema(metadata) { 65 | const schema = [ 66 | "## Schema", 67 | metadata.optionsDescription 68 | ? "```ts\n" + JSON.stringify(metadata.options, null, 2) + "\n```" 69 | : "```ts\nnull\n```" 70 | ].join("\n"); 71 | 72 | return schema; 73 | } 74 | 75 | function renderCodeExample(title, example, padding = 4) { 76 | const pad = " ".repeat(padding); 77 | if (example) { 78 | return [ 79 | pad, 80 | `${pad}**${title}**`, 81 | `${pad}\`\`\`ts\n${example 82 | .trim() 83 | .split("\n") 84 | .map(x => pad + x) 85 | .join("\n")}\n${pad}\`\`\`` 86 | ].join("\n"); 87 | } else { 88 | return ""; 89 | } 90 | } 91 | 92 | function renderCodeExamples(metadata) { 93 | const codeExamples = metadata.codeExamples || []; 94 | const examples = [ 95 | "## Code Examples", 96 | codeExamples 97 | .map(example => { 98 | return [ 99 | `- ${example.description}`, 100 | renderCodeExample("⚙️ Config", example.config), 101 | renderCodeExample("✅ Pass", example.pass), 102 | renderCodeExample("🚫 Fail", example.fail) 103 | ].join("\n"); 104 | }) 105 | .join("\n") 106 | ].join("\n"); 107 | 108 | return codeExamples.length ? examples : false; 109 | } 110 | 111 | exports.render = function(metadata) { 112 | return [ 113 | `# \`${metadata.ruleName}\``, 114 | renderDescription(metadata), 115 | renderNotes(metadata), 116 | renderRationale(metadata), 117 | renderConfig(metadata), 118 | renderSchema(metadata), 119 | renderCodeExamples(metadata) 120 | ] 121 | .filter(x => x) 122 | .map(x => `\n${x}`) 123 | .join("\n"); 124 | 125 | // const readme = README.replace('%docs%', docs.join('\n')); 126 | // return readme; 127 | }; 128 | 129 | exports.renderREADME = function(rules) { 130 | const docs = rules.map(metadata => { 131 | return [ 132 | "", 133 | `### [\`${metadata.ruleName}\`](docs/${metadata.ruleName}.md)`, 134 | metadata.description 135 | ].join("\n"); 136 | }); 137 | 138 | const readme = README.replace("%docs%", docs.join("\n")); 139 | return readme; 140 | }; 141 | -------------------------------------------------------------------------------- /scripts/prepare.js: -------------------------------------------------------------------------------- 1 | const { Spinner } = require("cli-spinner"); 2 | const { run } = require("./shared/run"); 3 | // const { spawn } = require('./shared/spawn'); 4 | const { verify } = require("./verify"); 5 | const { version } = require("./version"); 6 | const { red, green, bold } = require("colorette"); 7 | 8 | const loading = new Spinner(); 9 | loading.setSpinnerString(18); 10 | loading.setSpinnerTitle("Running tests"); 11 | 12 | let pendingVerify = true; 13 | 14 | async function handleVerify({ success, output }) { 15 | loading.stop(true); 16 | 17 | if (success) { 18 | console.log(`${green("✔")} ${bold("All tests passed")}\n`); 19 | console.log(output); 20 | } else { 21 | console.log(`${red("✖")} ${bold("Tests failed")}\n`); 22 | console.log(output); 23 | } 24 | console.log(); 25 | 26 | return success ? Promise.resolve() : Promise.reject(); 27 | } 28 | 29 | async function postVerify() { 30 | loading.setSpinnerTitle("Updating Docs"); 31 | loading.start(); 32 | await run(`npm run docs`); 33 | loading.stop(true); 34 | console.log(`${green("✔")} ${bold("Updated Docs")}\n`); 35 | 36 | loading.setSpinnerTitle("Pushing to Git"); 37 | loading.start(); 38 | try { 39 | await run(`git push`); 40 | await run(`git push --tags`); 41 | loading.stop(true); 42 | console.log(`${green("✔")} ${bold("Pushed to Git")}\n`); 43 | } catch (e) { 44 | loading.stop(true); 45 | console.log(`${red("✖")} ${bold("Unable to push to Git")}\n`); 46 | console.log(e.stderr); 47 | process.exit(1); 48 | } 49 | } 50 | 51 | async function main() { 52 | const verified = verify().then(args => { 53 | pendingVerify = false; 54 | return args; 55 | }); 56 | 57 | const v = await version(); 58 | if (!v) process.exit(0); 59 | try { 60 | await run(`npm version ${v}`); 61 | } catch (e) { 62 | console.log( 63 | `${red("✖")} Unable to execute ${green("npm version")}!`, 64 | red(`${e.stderr.split("\n")[0].replace("npm ERR! ", "")}`) 65 | ); 66 | console.log(); 67 | process.exit(1); 68 | } 69 | console.log(); 70 | 71 | verified 72 | .then(result => handleVerify(result)) 73 | .then(() => postVerify()) 74 | .catch(() => process.exit()); 75 | if (pendingVerify) loading.start(); 76 | } 77 | 78 | main(); 79 | -------------------------------------------------------------------------------- /scripts/shared/eval-text.js: -------------------------------------------------------------------------------- 1 | function evalText(text) { 2 | const fnStr = `return ${text};`; 3 | return new Function(fnStr)(); 4 | } 5 | 6 | exports.evalText = evalText; 7 | -------------------------------------------------------------------------------- /scripts/shared/run.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require("util"); 2 | const exec = promisify(require("child_process").exec); 3 | 4 | async function run(command) { 5 | const result = await exec(command); 6 | 7 | if (!!result.code) { 8 | return Promise.reject(result.stdout); 9 | } 10 | 11 | return Promise.resolve(result.stdout); 12 | } 13 | 14 | exports.run = run; 15 | -------------------------------------------------------------------------------- /scripts/shared/spawn.js: -------------------------------------------------------------------------------- 1 | const _spawn = require("child_process").spawn; 2 | exports.spawn = command => { 3 | const [name, ...args] = command.split(" "); 4 | return _spawn(name, args, { stdio: "inherit" }); 5 | }; 6 | -------------------------------------------------------------------------------- /scripts/verify.js: -------------------------------------------------------------------------------- 1 | const { run } = require("./shared/run"); 2 | const { dim, green, red, underline } = require("colorette"); 3 | 4 | async function verify() { 5 | try { 6 | const result = await run(`npm run verify`); 7 | 8 | const output = result 9 | .split("> tslint --test test/rules/**/*")[1] 10 | .trim() 11 | .replace(/Passed/g, green("Passed")); 12 | 13 | return Promise.resolve({ success: true, output }); 14 | } catch (e) { 15 | const output = e.stdout 16 | .split("> tslint --test test/rules/**/*")[1] 17 | .trim() 18 | .replace(/Passed/g, green("Passed")) 19 | .replace(/Failed!/g, red("Failed!")) 20 | .split("\n") 21 | .map(ln => { 22 | if (ln === "Expected (from .lint file)") return red(ln); 23 | if (ln === "Actual (from TSLint)") return green(ln); 24 | if (ln.startsWith("+")) return green(ln); 25 | if (ln.startsWith("-")) return red(ln); 26 | 27 | if (ln.startsWith("test/rules")) return ln; 28 | return dim(ln); 29 | }) 30 | .join("\n"); 31 | return Promise.resolve({ success: false, output }); 32 | } 33 | } 34 | 35 | exports.verify = verify; 36 | -------------------------------------------------------------------------------- /scripts/version.js: -------------------------------------------------------------------------------- 1 | const { run } = require("./shared/run"); 2 | const { evalText } = require("./shared/eval-text"); 3 | const { dim, yellow, green, cyan } = require("colorette"); 4 | const semver = require("semver"); 5 | const prompt = require("prompts"); 6 | 7 | async function version() { 8 | const current = evalText(await run("npm version"))["tslint-stencil"]; 9 | const preids = ["alpha", "beta", "rc"]; 10 | const pre = semver.parse(current).prerelease; 11 | const bumped = { 12 | patch: semver.inc(current, "patch"), 13 | minor: semver.inc(current, "minor"), 14 | major: semver.inc(current, "major") 15 | }; 16 | 17 | let response; 18 | if (pre && pre[0]) { 19 | response = await prompt({ 20 | type: "select", 21 | name: "type", 22 | message: "Select a version", 23 | choices: [ 24 | { title: "Prerelease", value: "prerelease" }, 25 | { title: `Release ${dim(bumped.patch)}`, value: "patch" } 26 | ], 27 | initial: 0 28 | }); 29 | } else { 30 | response = await prompt({ 31 | type: "select", 32 | name: "type", 33 | message: "Select a version", 34 | choices: [ 35 | { title: "Prerelease", value: "prerelease" }, 36 | { title: `Patch ${dim(bumped.patch)}`, value: "patch" }, 37 | { title: `Minor ${dim(bumped.minor)}`, value: "minor" }, 38 | { title: `Major ${dim(bumped.major)}`, value: "major" } 39 | ], 40 | initial: 0 41 | }); 42 | } 43 | if (!response) process.exit(0); 44 | const { type } = response; 45 | 46 | if (type === "prerelease") { 47 | const next = preids[preids.findIndex(x => x === pre[0]) + 1]; 48 | 49 | if (pre.length) { 50 | if (!next) 51 | return Promise.resolve( 52 | semver.inc(current, "prerelease", false, pre[0]) 53 | ); 54 | 55 | const { increment } = await prompt({ 56 | type: "toggle", 57 | name: "increment", 58 | message: `Select a prerelease version`, 59 | initial: false, 60 | inactive: `${pre[0]}.${pre[1] + 1}`, 61 | active: `${next}.0` 62 | }); 63 | 64 | return increment 65 | ? Promise.resolve(semver.inc(current, "prerelease", false, next)) 66 | : Promise.resolve(semver.inc(current, "prerelease", false, pre[0])); 67 | } else { 68 | const prereleaseId = preids[0]; 69 | const { prereleaseType } = await prompt({ 70 | type: "select", 71 | name: "prereleaseType", 72 | message: "Select a prerelease version", 73 | choices: [ 74 | // { title: `Prerelease ${dim(current + '-' + prereleaseId + '.0')}`, value: 'prerelease' }, 75 | { 76 | title: `Patch ${dim(bumped.patch + "-" + prereleaseId + ".0")}`, 77 | value: "prepatch" 78 | }, 79 | { 80 | title: `Minor ${dim(bumped.minor + "-" + prereleaseId + ".0")}`, 81 | value: "preminor" 82 | }, 83 | { 84 | title: `Major ${dim(bumped.major + "-" + prereleaseId + ".0")}`, 85 | value: "premajor" 86 | } 87 | ], 88 | initial: 0 89 | }); 90 | return Promise.resolve( 91 | semver.inc(current, prereleaseType, false, prereleaseId) 92 | ); 93 | } 94 | } 95 | 96 | if (type === "patch" || !pre[0]) { 97 | const next = preids.slice(preids.findIndex(x => x === pre[0]) + 1); 98 | if (!next.length) return Promise.resolve(undefined); 99 | 100 | console.log(` 101 | ${yellow("▲")} Warning! Updating from ${green(current)} to ${green( 102 | bumped[type] 103 | )} skips ${next.map(cyan).join(", ")} prerelease${ 104 | next.length > 1 ? "s" : "" 105 | }`); 106 | const { skip } = await prompt({ 107 | type: "toggle", 108 | name: "skip", 109 | message: "Do you wish to proceed?", 110 | initial: false, 111 | active: "yes", 112 | inactive: "no" 113 | }); 114 | 115 | if (skip) { 116 | return Promise.resolve(bumped.patch); 117 | } else { 118 | return Promise.resolve(undefined); 119 | } 120 | } 121 | } 122 | 123 | exports.version = version; 124 | -------------------------------------------------------------------------------- /src/banPrefixRule.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import * as Lint from "tslint"; 3 | import { 4 | isComponentClass, 5 | hasDecoratorNamed, 6 | getDeclarationParameters 7 | } from "./shared/utils"; 8 | 9 | type Options = { 10 | banned: string[]; 11 | }; 12 | 13 | export class Rule extends Lint.Rules.AbstractRule { 14 | public static metadata: Lint.IRuleMetadata = { 15 | ruleName: "ban-prefix", 16 | description: `Ensures that a Component's \`tag\` does not use any of the given prefixes.`, 17 | optionsDescription: Lint.Utils.dedent` 18 | An array of \`"string"\`s which no Component \`tag\` will be allowed to use as a prefix. 19 | `, 20 | options: { 21 | type: "array", 22 | items: { 23 | type: "string" 24 | }, 25 | minLength: 1 26 | }, 27 | optionExamples: [ 28 | `{ "ban-prefix": [true, "stencil"] }`, 29 | `{ "ban-prefix": [true, "stencil", "st", "stnl"] }` 30 | ], 31 | type: "style", 32 | typescriptOnly: true 33 | }; 34 | public static FAILURE_STRING = 'Invalid tag prefix "%s"'; 35 | 36 | public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { 37 | const options: Options = { 38 | banned: this.getOptions() 39 | .ruleArguments.filter(x => x) 40 | .map(x => x.trim().replace(/-$/, "")) 41 | }; 42 | 43 | return this.applyWithFunction(sourceFile, walk, options); 44 | } 45 | } 46 | 47 | function walk(ctx: Lint.WalkContext) { 48 | return ts.forEachChild(ctx.sourceFile, cb); 49 | 50 | function cb(node: ts.Node): void { 51 | if (!ts.isClassDeclaration(node)) return; 52 | if (!isComponentClass(node)) return; 53 | 54 | const dec: ts.Decorator = node.decorators!.find( 55 | hasDecoratorNamed("Component") 56 | )!; 57 | const [{ tag }] = getDeclarationParameters<{ tag: string }>(dec); 58 | 59 | if (!tag) return; 60 | 61 | let valid = !ctx.options.banned.some(prefix => 62 | tag.startsWith(`${prefix}-`) 63 | ); 64 | if (valid) return; 65 | 66 | const obj = 67 | ts.isCallExpression(dec.expression) && 68 | (dec.expression as ts.CallExpression).arguments[0]; 69 | if (obj && ts.isObjectLiteralExpression(obj)) { 70 | const property = obj.properties.filter(property => { 71 | let name = property.name!.getText(ctx.sourceFile); 72 | return name.indexOf("tag") > -1; 73 | })[0]; 74 | if (property) { 75 | ctx.addFailureAtNode( 76 | property.getChildAt(2, ctx.sourceFile), 77 | Rule.FAILURE_STRING.replace("%s", tag.split("-")[0]) 78 | ); 79 | } 80 | } 81 | 82 | return ts.forEachChild(node, cb); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/code-examples/decoratedMemberStyle.examples.ts: -------------------------------------------------------------------------------- 1 | import * as Lint from "tslint"; 2 | 3 | export const codeExamples: Lint.ICodeExample[] = [ 4 | { 5 | description: "Require all decorated component properties to be singleline.", 6 | config: `"rules": { "decorated-member-style": [true, { "properties": "singleline" }] }`, 7 | pass: `@Prop() propName: string;`, 8 | fail: Lint.Utils.dedent` 9 | @Prop() 10 | propName: string; 11 | `.trim() 12 | }, 13 | { 14 | description: "Require all decorated component properties to be multiline.", 15 | config: `"rules": { "decorated-member-style": [true, { "properties": "multiline" }] }`, 16 | pass: Lint.Utils.dedent` 17 | @Prop() 18 | propName: string; 19 | `.trim(), 20 | fail: `@Prop() propName: string;` 21 | }, 22 | { 23 | description: "Require all decorated component methods to be inlined.", 24 | config: `"rules": { "decorated-member-style": [true, { "methods": "singleline" }] }`, 25 | pass: `@Listen('click') handleClick() {}`, 26 | fail: Lint.Utils.dedent` 27 | @Listen('click') 28 | handleClick() {} 29 | `.trim() 30 | }, 31 | { 32 | description: "Require all decorated component methods to be multiline.", 33 | config: `"rules": { "decorated-member-style": [true, { "methods": "multiline" }] }`, 34 | pass: Lint.Utils.dedent` 35 | @Listen('click') 36 | handleClick() {} 37 | 38 | @Listen('click') 39 | @Listen('tap') 40 | handleClickOrTap() {} 41 | `.trim(), 42 | fail: `@Listen('click') handleClick() {}` 43 | } 44 | ]; 45 | -------------------------------------------------------------------------------- /src/code-examples/lifecycleSort.example.ts: -------------------------------------------------------------------------------- 1 | import * as Lint from "tslint"; 2 | 3 | export const codeExamples: Lint.ICodeExample[] = [ 4 | { 5 | description: 6 | "Order lifecycle methods by their natural call order (`call-order` or `default`)", 7 | config: Lint.Utils.dedent` 8 | "rules": { "lifecycle-sort": [true, "call-order"] } 9 | `, 10 | pass: Lint.Utils.dedent` 11 | componentWillLoad() { } 12 | componentDidLoad() { } 13 | componentWillUpdate() { } 14 | componentDidUpdate() { } 15 | componentDidUnload() { } 16 | ` 17 | }, 18 | { 19 | description: "Order lifecycle methods alphabetically (`alphabetical`)", 20 | config: Lint.Utils.dedent` 21 | "rules": { "lifecycle-sort": [true, "alphabetical"] } 22 | `, 23 | pass: Lint.Utils.dedent` 24 | componentDidLoad() { } 25 | componentDidUnload() { } 26 | componentDidUpdate() { } 27 | componentWillLoad() { } 28 | componentWillUpdate() { } 29 | ` 30 | } 31 | ]; 32 | -------------------------------------------------------------------------------- /src/componentMemberOrderRule.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import * as Lint from "tslint"; 3 | import { 4 | isComponentClass, 5 | getDeclarationParameters, 6 | hasDecoratorNamed, 7 | followsOrder, 8 | checkGroupings, 9 | firstGroupOutOfOrder, 10 | getIndentationAtNode, 11 | getDecoratorArgs 12 | } from "./shared/utils"; 13 | import { 14 | LIFECYCLE_METHODS, 15 | STENCIL_METHODS, 16 | VERBOSE_COMPONENT_MEMBERS 17 | } from "./shared/constants"; 18 | 19 | type ComponentMember = 20 | | "element" 21 | | "event" 22 | | "internal-prop" 23 | | "lifecycle" 24 | | "listen" 25 | | "method" 26 | | "own-method" 27 | | "own-prop" 28 | | "prop" 29 | | "state" 30 | | "stencil-method" 31 | | "watch" 32 | | "watched-prop" 33 | | "watched-state"; 34 | export interface ComponentMetadata { 35 | name: string; 36 | key: ComponentMember; 37 | node: ts.Node; 38 | watches?: string | false; 39 | watchedBy?: ComponentMetadata; 40 | } 41 | type Options = { 42 | order: ComponentMember[]; 43 | "watch-follows-prop": boolean; 44 | alphabetical: boolean; 45 | }; 46 | 47 | export class Rule extends Lint.Rules.AbstractRule { 48 | public static metadata: Lint.IRuleMetadata = { 49 | ruleName: "component-member-order", 50 | description: "Ensures that Component members are ordered consistently", 51 | optionsDescription: Lint.Utils.dedent` 52 | One argument, which is an object, must be provided. It should contain an \`"order"\` property. The \`"order"\` property should be an array consisting of the following strings: 53 | 54 | - \`element\`, which refers to \`@Element()\` decorated properties 55 | - \`event\`, which refers to \`@Event()\` decorated properties 56 | - \`internal-prop\`, which refers to \`@Prop()\` decorated properties using \`context\` or \`connect\` 57 | - \`lifecycle\`, which refers to Stencil lifecycle methods (such as \`componentWillLoad\`) 58 | - \`listen\`, which refers to \`@Listen()\` decorated methods 59 | - \`method\`, which refers to \`@Method()\` decorated methods 60 | - \`own-method\`, which refers to undecorated methods 61 | - \`own-prop\`, which refers to undecorated properties 62 | - \`prop\`, which refers to \`@Prop()\` decorated properties 63 | - \`state\`, which refers to \`@State()\` decorated properties 64 | - \`stencil-method\`, which refers to Stencil \`render()\` method 65 | - \`watch\`, which refers to \`@Watch()\` decorated methods 66 | - \`watched-prop\`, which refers to \`@Prop()\` decorated properties that have a \`@Watch()\` method 67 | - \`watched-state\`, which refers to \`@State()\` decorated properties that have a \`@Watch()\` method 68 | 69 | `, 70 | options: { 71 | type: "object", 72 | properties: { 73 | order: { 74 | type: "array", 75 | items: { 76 | type: "string", 77 | enum: [ 78 | "element", 79 | "event", 80 | "internal-prop", 81 | "lifecycle", 82 | "listen", 83 | "method", 84 | "own-method", 85 | "own-prop", 86 | "prop", 87 | "state", 88 | "stencil-method", 89 | "watch", 90 | "watched-state", 91 | "watched-prop" 92 | ] 93 | }, 94 | minLength: 2, 95 | maxLength: 12 96 | }, 97 | "watch-follows-prop": { 98 | type: "boolean" 99 | }, 100 | alphabetical: { 101 | type: "boolean" 102 | } 103 | }, 104 | additionalProperties: false 105 | }, 106 | optionExamples: [ 107 | `{ 108 | "component-member-order": [ 109 | true, 110 | { 111 | "order": [ 112 | "own-prop", 113 | "element", 114 | "state", 115 | "watched-state", 116 | "internal-prop", 117 | "prop", 118 | "watched-prop", 119 | "event", 120 | "lifecycle", 121 | "listen", 122 | "method", 123 | "own-method", 124 | "stencil-method" 125 | ], 126 | "alphabetical": true 127 | } 128 | ] 129 | }`, 130 | `{ 131 | "component-member-order": [ 132 | true, 133 | { 134 | "order": false, 135 | "watch-follows-prop": true 136 | } 137 | ] 138 | }` 139 | ], 140 | type: "maintainability", 141 | typescriptOnly: true 142 | }; 143 | public static FAILURE_STRING_ORDER = `Component member "%a" should be placed %b`; 144 | public static FAILURE_STRING_GROUP = `%a and %b should not be mixed`; 145 | public static FAILURE_STRING_ALPHABETICAL = `Component members of the same type should be alphabetized`; 146 | public static FAILURE_STRING_WATCH = `Watch methods should immediately follow the declaration of the Prop/State they watch`; 147 | 148 | public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { 149 | const options: Options = Object.assign( 150 | { 151 | order: false, 152 | "watch-follows-prop": false, 153 | alphabetical: false 154 | }, 155 | this.getOptions().ruleArguments[0] 156 | ); 157 | 158 | return this.applyWithFunction(sourceFile, walk, options); 159 | } 160 | } 161 | 162 | function walk(ctx: Lint.WalkContext) { 163 | const { 164 | order, 165 | "watch-follows-prop": watchFollowsProp, 166 | alphabetical 167 | } = ctx.options; 168 | 169 | function cb(node: ts.Node): void { 170 | let collected: any[] = []; 171 | 172 | if (ts.isClassDeclaration(node) && isComponentClass(node)) { 173 | node.members.forEach((member: ts.ClassElement) => { 174 | const name = 175 | member.name && ts.isIdentifier(member.name) && member.name.text; 176 | const key = getOrderKey(member); 177 | const watches = determineWatchedProp(member, key); 178 | 179 | if (name && key) { 180 | collected.push({ name, key, watches, node: member }); 181 | } 182 | }); 183 | 184 | const watchable = ["prop", "state"]; 185 | 186 | const watchers = collected.filter(x => x.watches); 187 | const watchedNames = watchers.map(watcher => watcher.watches); 188 | collected.forEach(componentMember => { 189 | const { key, name } = componentMember; 190 | 191 | if (watchedNames.includes(componentMember.name)) { 192 | componentMember.watchedBy = watchers.find( 193 | watcher => watcher.watches === name 194 | ); 195 | componentMember.key = watchable.includes(key) 196 | ? (`watched-${key}` as ComponentMember) 197 | : key; 198 | } 199 | }); 200 | } 201 | 202 | const collectedKeys = collected.map(x => x.key); 203 | const collectedKeysSet = new Set(collectedKeys); 204 | 205 | if (collected.length) { 206 | if (order) { 207 | // First, check that all items of the same type are grouped together 208 | const ungrouped = checkGroupings(collected); 209 | if (ungrouped.length) { 210 | let groups: ComponentMetadata[] = ungrouped; 211 | 212 | // filter out all watchers and watched props/state 213 | if (watchFollowsProp) { 214 | groups = ungrouped.reduce((acc, componentMemb) => { 215 | if (componentMemb.watches || componentMemb.watchedBy) { 216 | return acc; 217 | } 218 | 219 | return [...acc, componentMemb]; 220 | }, []); 221 | } 222 | 223 | if (groups.length) { 224 | const failures = [ 225 | ...collected.filter( 226 | x => groups.findIndex(g => g.key === x.key) > -1 227 | ) 228 | ].map(x => x.node); 229 | 230 | const firstGroupMember = groups[0]; 231 | const misplacedGroupMemberIndex = 232 | [...collectedKeysSet].findIndex(x => x === firstGroupMember.key) + 233 | 1; 234 | const misplacedGroupMemberKey: string = [...collectedKeysSet][ 235 | misplacedGroupMemberIndex 236 | ]; 237 | 238 | const a = VERBOSE_COMPONENT_MEMBERS[firstGroupMember.key]; 239 | const b = VERBOSE_COMPONENT_MEMBERS[misplacedGroupMemberKey]; 240 | 241 | return addFailureToNodeGroup( 242 | ctx, 243 | failures, 244 | Rule.FAILURE_STRING_GROUP.replace(/\%a/g, a).replace(/\%b/g, b) 245 | ); 246 | } 247 | return; 248 | } 249 | 250 | // Next, add failures to the nodes that are out of order 251 | const actual = Array.from( 252 | new Set(collected.map(value => value.key)) 253 | ).filter(x => order.includes(x)); 254 | const follows = followsOrder(actual, order); 255 | if (!follows) { 256 | const group: ComponentMember = firstGroupOutOfOrder( 257 | actual, 258 | order 259 | ) as ComponentMember; 260 | const existing = order.filter(x => actual.includes(x)); 261 | const prev = existing[existing.indexOf(group) - 1]; 262 | const next = existing[existing.indexOf(group) + 1]; 263 | const failures = collected 264 | .filter(x => x.key === group) 265 | .map(x => x.node); 266 | 267 | addFailureToNodeGroup( 268 | ctx, 269 | failures, 270 | Rule.FAILURE_STRING_ORDER.replace(/\%a/g, group).replace( 271 | /\%b/g, 272 | () => { 273 | if (next && prev) { 274 | return `between "${prev}" and "${next}"`; 275 | } 276 | 277 | return next ? `before "${next}"` : `after "${prev}"`; 278 | } 279 | ) 280 | ); 281 | } 282 | } 283 | 284 | if (watchFollowsProp) { 285 | const watched = collected 286 | .map((value, index) => ({ value, index })) 287 | .filter(({ value }) => value.key === "watch") 288 | .map(({ value, index }) => { 289 | const name = getDeclarationParameters( 290 | value.node.decorators!.find(hasDecoratorNamed("Watch"))! 291 | )[0]; 292 | return { 293 | node: value.node, 294 | name, 295 | index 296 | }; 297 | }); 298 | collected.forEach((current, i) => { 299 | if (current.key.startsWith("watched-")) { 300 | const watch = watched.find(x => x.name === current.name); 301 | if (!watch) return; 302 | if (i === watch.index - 1) return; 303 | 304 | return ctx.addFailureAtNode(watch.node, Rule.FAILURE_STRING_WATCH); 305 | } 306 | }); 307 | } 308 | 309 | // Finally, if alphabetical, check that groupings are in alphabetical order 310 | if (alphabetical) { 311 | let actual: ComponentMember[] = []; 312 | if (order) 313 | actual = Array.from( 314 | new Set(collected.map(value => value.key)) 315 | ).filter(x => order.includes(x)); 316 | if (!order) 317 | actual = Array.from(new Set(collected.map(value => value.key))); 318 | 319 | const groups = actual 320 | .map(key => { 321 | if (key === "lifecycle" || key === "stencil-method") { 322 | return { key, alphabetical: true }; 323 | } 324 | const group = collected.filter(x => x.key === key).map(x => x.name); 325 | const alpha = group.every((item, i, arr) => { 326 | const next = arr[i + 1]; 327 | if (!next) return true; 328 | return item.toUpperCase() < next.toUpperCase(); 329 | }); 330 | 331 | return { key, alphabetical: alpha }; 332 | }) 333 | .filter(x => !x.alphabetical) 334 | .map(x => x.key); 335 | 336 | if (groups.length) { 337 | const failures = [...collected.filter(x => groups.includes(x.key))]; 338 | const fix = createFixAlphabetical(failures, ctx.sourceFile); 339 | return addFailureToNodeGroup( 340 | ctx, 341 | failures.map(x => x.node), 342 | Rule.FAILURE_STRING_ALPHABETICAL, 343 | fix 344 | ); 345 | } 346 | } 347 | } 348 | 349 | return node.forEachChild(cb); 350 | } 351 | 352 | ts.forEachChild(ctx.sourceFile, cb); 353 | } 354 | 355 | function getOrderKey(node: ts.Node): ComponentMember | false { 356 | if (!ts.isClassElement(node)) return false; 357 | 358 | let key: ComponentMember | false = false; 359 | if (node.decorators && Array.isArray(node.decorators)) { 360 | const decorators: string[] = node.decorators 361 | .map( 362 | dec => 363 | ts.isCallExpression(dec.expression) && 364 | ts.isIdentifier(dec.expression.expression) && 365 | dec.expression.expression.text.toLowerCase() 366 | ) 367 | .filter(x => x) as string[]; 368 | if (decorators.length === 1) { 369 | key = decorators[0] as ComponentMember; 370 | if (key === "prop") { 371 | const args = getDeclarationParameters( 372 | node.decorators.find(hasDecoratorNamed("Prop"))! 373 | )[0]; 374 | if (args && (args.context || args.connect)) key = "internal-prop"; 375 | } 376 | } 377 | } else { 378 | switch (node.kind) { 379 | case ts.SyntaxKind.PropertyDeclaration: 380 | key = "own-prop"; 381 | break; 382 | case ts.SyntaxKind.MethodDeclaration: 383 | const name = node.name && ts.isIdentifier(node.name) && node.name.text; 384 | if (name) { 385 | if (LIFECYCLE_METHODS.includes(name)) key = "lifecycle"; 386 | else if (STENCIL_METHODS.includes(name)) key = "stencil-method"; 387 | else key = "own-method"; 388 | break; 389 | } 390 | } 391 | } 392 | 393 | return key; 394 | } 395 | 396 | function addFailureToNodeGroup( 397 | ctx: Lint.WalkContext, 398 | nodes: ts.Node[], 399 | failure: string, 400 | fix?: Lint.Replacement | Lint.Replacement[] 401 | ) { 402 | if (nodes.length === 1) { 403 | ctx.addFailureAtNode(nodes[0], failure, fix); 404 | } else { 405 | const start = nodes[0].getStart(ctx.sourceFile, true); 406 | const width = nodes[nodes.length - 1].getEnd() - start; 407 | 408 | return ctx.addFailureAt(start, width, failure, fix); 409 | } 410 | } 411 | 412 | function createFixAlphabetical( 413 | collected: ComponentMetadata[], 414 | sourceFile: ts.SourceFile 415 | ) { 416 | const fix: Lint.Replacement[] = []; 417 | const nodes = collected.map(x => x.node); 418 | const start = nodes[0].getStart(sourceFile, true); 419 | const end = nodes[nodes.length - 1].getEnd(); 420 | const indent = getIndentationAtNode(nodes[0], sourceFile); 421 | 422 | const sorted = [...collected] 423 | .sort((a, b) => { 424 | const nameA = a.name.toUpperCase(); 425 | const nameB = b.name.toUpperCase(); 426 | if (nameA < nameB) return -1; 427 | if (nameA > nameB) return 1; 428 | return 0; 429 | }) 430 | .map(({ node }, i) => { 431 | const text = node.getFullText(sourceFile); 432 | if (i === 0) return `${text.trim()}`; 433 | else return `${indent}${text.trim()}`; 434 | }); 435 | fix.push(Lint.Replacement.replaceFromTo(start, end, sorted.join("\n"))); 436 | 437 | return fix; 438 | } 439 | 440 | function determineWatchedProp( 441 | member: ts.ClassElement, 442 | key: ComponentMember | false 443 | ): string { 444 | if (!key || key !== "watch" || !member.decorators || !member.decorators[0]) { 445 | return ""; 446 | } 447 | return getDecoratorArgs(member.decorators[0]) || ""; 448 | } 449 | -------------------------------------------------------------------------------- /src/componentsPerFileRule.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import * as Lint from "tslint"; 3 | import { isComponentClass } from "./shared/utils"; 4 | 5 | interface Options { 6 | maxComponents: number; 7 | } 8 | 9 | export class Rule extends Lint.Rules.AbstractRule { 10 | public static metadata: Lint.IRuleMetadata = { 11 | ruleName: "components-per-file", 12 | description: `Allows a maximum number of Components to be placed in a single file`, 13 | optionsDescription: Lint.Utils.dedent` 14 | This rule requires a single argument – a \`"number"\` representing the maximum number of @Component() decorated classes allowed in a single file. 15 | `, 16 | options: { 17 | type: "array", 18 | items: { 19 | type: "number" 20 | }, 21 | minLength: 1, 22 | maxLength: 1 23 | }, 24 | optionExamples: [`{ "components-per-file": [true, 1] }`], 25 | type: "maintainability", 26 | typescriptOnly: true 27 | }; 28 | public static FAILURE_STRING = "Files may only contain %s component"; 29 | 30 | public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { 31 | const options: Options = { 32 | maxComponents: this.getOptions().ruleArguments[0] 33 | }; 34 | return this.applyWithFunction(sourceFile, walk, options); 35 | } 36 | } 37 | 38 | function walk(ctx: Lint.WalkContext) { 39 | let components = 0; 40 | let failure = false; 41 | function cb(node: ts.Node): void { 42 | if (!ts.isClassDeclaration(node)) return; 43 | if (!isComponentClass(node)) return; 44 | 45 | components++; 46 | failure = components > ctx.options.maxComponents; 47 | if (!failure) return; 48 | 49 | let FAILURE_STRING = Rule.FAILURE_STRING.replace( 50 | "%s", 51 | `${ctx.options.maxComponents}` 52 | ); 53 | if (ctx.options.maxComponents > 1) FAILURE_STRING += "s"; 54 | ctx.addFailureAtNode(node, FAILURE_STRING); 55 | 56 | return ts.forEachChild(node, cb); 57 | } 58 | 59 | return ts.forEachChild(ctx.sourceFile, cb); 60 | } 61 | -------------------------------------------------------------------------------- /src/decoratedMemberStyleRule.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import * as Lint from "tslint"; 3 | import { 4 | isComponentClass, 5 | getIndentationAtNode, 6 | getFirstNonDecoratorToken 7 | } from "./shared/utils"; 8 | import { codeExamples } from "./code-examples/decoratedMemberStyle.examples"; 9 | 10 | interface Options { 11 | properties: "singleline" | "multiline" | "ignore"; 12 | methods: "singleline" | "multiline" | "ignore"; 13 | } 14 | 15 | export class Rule extends Lint.Rules.AbstractRule { 16 | public static metadata: Lint.IRuleMetadata = { 17 | ruleName: "decorated-member-style", 18 | description: `Requires decorated class members to follow a consistent style (singleline or multiline)`, 19 | optionsDescription: Lint.Utils.dedent` 20 | One argument which is an object with the keys \`"properties"\` and \`"methods"\`. Both can be set to a string, which must be one of the following values: 21 | - \`"singleline"\` 22 | - \`"multiline"\` 23 | - \`"ignore"\` 24 | 25 | If either key is excluded, the default behavior (\`"ignore"\`) will be applied. 26 | 27 | A member is considered “multiline” if its declaration is on a line after the last decorator. If decorators are composed (multiple decorators for a single declaration), "multiline" requires each decorator to be on its own line. 28 | `, 29 | options: { 30 | type: "object", 31 | properties: { 32 | properties: { 33 | type: "string", 34 | enum: ["singleline", "multiline", "ignore"] 35 | }, 36 | methods: { 37 | type: "string", 38 | enum: ["singleline", "multiline", "ignore"] 39 | } 40 | } 41 | }, 42 | optionExamples: [ 43 | Lint.Utils.dedent` 44 | { 45 | "decorated-member-style": [ 46 | true, 47 | { 48 | "methods": "multiline" 49 | } 50 | ] 51 | } 52 | `, 53 | Lint.Utils.dedent` 54 | { 55 | "decorated-member-style": [ 56 | true, 57 | { 58 | "properties": "singleline", 59 | "methods": "multiline" 60 | } 61 | ] 62 | } 63 | ` 64 | ], 65 | type: "style", 66 | typescriptOnly: true, 67 | hasFix: true, 68 | codeExamples 69 | }; 70 | 71 | public static FAILURE_STRING_SINGLE = 72 | "Component %s decorators should be inlined"; 73 | public static FAILURE_STRING_MULTI = 74 | "Component %s decorators should be multiline"; 75 | public static FAILURE_STRING_MULTI_COMPOSITION = 76 | "Component %s decorators should each be on their own lines"; 77 | 78 | public static DEFAULT_ARGUMENTS = { 79 | properties: "ignore", 80 | methods: "ignore" 81 | }; 82 | 83 | public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { 84 | let args = this.getOptions().ruleArguments; 85 | if (args) args = args[0]; 86 | const options: Options = Object.assign( 87 | {}, 88 | Rule.DEFAULT_ARGUMENTS, 89 | args 90 | ) as Options; 91 | 92 | return this.applyWithWalker( 93 | new MethodDecoratorWalker(sourceFile, this.getOptions(), options) 94 | ); 95 | } 96 | } 97 | 98 | // The walker takes care of all the work. 99 | class MethodDecoratorWalker extends Lint.RuleWalker { 100 | constructor( 101 | sourceFile: ts.SourceFile, 102 | options: Lint.IOptions, 103 | private _options: Options 104 | ) { 105 | super(sourceFile, options); 106 | } 107 | 108 | getOptions(): Options { 109 | return this._options; 110 | } 111 | 112 | public visitMethodDeclaration(node: ts.MethodDeclaration) { 113 | const { methods: style } = this.getOptions(); 114 | 115 | if (style === "ignore") return; 116 | 117 | if ( 118 | style && 119 | isComponentClass(node.parent) && 120 | node.decorators && 121 | Array.isArray(node.decorators) 122 | ) { 123 | if (style === "multiline" && node.decorators.length > 1) { 124 | const decoratorLines = node.decorators.map( 125 | dec => this.getLineAndCharacterOfPosition(dec.getEnd()).line 126 | ); 127 | const { line: propertyLine } = this.getLineAndCharacterOfPosition( 128 | node.name.getEnd() 129 | ); 130 | const allMultiline = decoratorLines.every((line, i) => { 131 | if (decoratorLines[i - 1] === undefined) return true; 132 | return line > decoratorLines[i - 1]; 133 | }); 134 | 135 | if (!allMultiline) { 136 | const fix = createFixMultilineDecorators(node, this.getSourceFile()); 137 | return this.addFailureAtNode( 138 | node, 139 | Rule.FAILURE_STRING_MULTI_COMPOSITION.replace("%s", "method"), 140 | fix 141 | ); 142 | } 143 | if (decoratorLines[decoratorLines.length - 1] === propertyLine) { 144 | const fix = createFixMultiline(node, this.getSourceFile()); 145 | return this.addFailureAtNode( 146 | node, 147 | Rule.FAILURE_STRING_MULTI.replace("%s", "method"), 148 | fix 149 | ); 150 | } 151 | } else { 152 | const dec: ts.Decorator = node.decorators[node.decorators.length - 1]; 153 | 154 | const { line: decoratorLine } = this.getLineAndCharacterOfPosition( 155 | dec.getEnd() 156 | ); 157 | const { line: propertyLine } = this.getLineAndCharacterOfPosition( 158 | node.name.getEnd() 159 | ); 160 | 161 | if (style === "singleline") { 162 | if (decoratorLine !== propertyLine) { 163 | const fix = createFixSingleline(node, this.getSourceFile()); 164 | return this.addFailureAtNode( 165 | node, 166 | Rule.FAILURE_STRING_SINGLE.replace("%s", "method"), 167 | fix 168 | ); 169 | } 170 | } else if (style === "multiline") { 171 | const fix = createFixMultiline(node, this.getSourceFile()); 172 | if (decoratorLine === propertyLine) 173 | return this.addFailureAtNode( 174 | node, 175 | Rule.FAILURE_STRING_MULTI.replace("%s", "method"), 176 | fix 177 | ); 178 | } 179 | } 180 | } 181 | 182 | super.visitMethodDeclaration(node); 183 | } 184 | 185 | public visitPropertyDeclaration(node: ts.PropertyDeclaration) { 186 | const { properties: style } = this.getOptions(); 187 | 188 | if (style === "ignore") return; 189 | 190 | if ( 191 | style && 192 | isComponentClass(node.parent) && 193 | node.decorators && 194 | Array.isArray(node.decorators) 195 | ) { 196 | const dec: ts.Decorator = node.decorators[node.decorators.length - 1]; 197 | 198 | const { line: decoratorLine } = this.getLineAndCharacterOfPosition( 199 | dec.getEnd() 200 | ); 201 | const { line: propertyLine } = this.getLineAndCharacterOfPosition( 202 | node.name.getEnd() 203 | ); 204 | 205 | if (style === "singleline") { 206 | if (decoratorLine !== propertyLine) { 207 | const fix = createFixSingleline(node, this.getSourceFile()); 208 | return this.addFailureAtNode( 209 | node, 210 | Rule.FAILURE_STRING_SINGLE.replace("%s", "property"), 211 | fix 212 | ); 213 | } 214 | } else if (style === "multiline") { 215 | const fix = createFixMultiline(node, this.getSourceFile()); 216 | if (decoratorLine === propertyLine) 217 | return this.addFailureAtNode( 218 | node, 219 | Rule.FAILURE_STRING_MULTI.replace("%s", "property"), 220 | fix 221 | ); 222 | } 223 | } 224 | 225 | super.visitPropertyDeclaration(node); 226 | } 227 | } 228 | 229 | function createFixSingleline( 230 | node: ts.Node, 231 | sourceFile: ts.SourceFile 232 | ): Lint.Replacement[] { 233 | const dec: ts.Decorator = node.decorators![node.decorators!.length - 1]; 234 | let token = getFirstNonDecoratorToken(node); 235 | let fix: Lint.Replacement[] = []; 236 | 237 | if (token) { 238 | const decEnd = dec.getEnd(); 239 | const tokenStart = token.getStart(sourceFile); 240 | fix.push(Lint.Replacement.replaceFromTo(decEnd, tokenStart, " ")); 241 | } 242 | 243 | return fix; 244 | } 245 | 246 | function createFixMultiline( 247 | node: ts.Node, 248 | sourceFile: ts.SourceFile 249 | ): Lint.Replacement[] { 250 | const dec: ts.Decorator = node.decorators![node.decorators!.length - 1]; 251 | const indent = getIndentationAtNode(node, sourceFile); 252 | let token = getFirstNonDecoratorToken(node); 253 | let fix: Lint.Replacement[] = []; 254 | 255 | if (token) { 256 | const decStart = dec.getFullStart(); 257 | const tokenStart = token.getStart(sourceFile); 258 | fix.push( 259 | Lint.Replacement.replaceFromTo( 260 | decStart, 261 | tokenStart, 262 | dec.getFullText(sourceFile).trimRight() 263 | ) 264 | ); 265 | fix.push(Lint.Replacement.appendText(tokenStart, `\n${indent}`)); 266 | } 267 | 268 | return fix; 269 | } 270 | 271 | function createFixMultilineDecorators( 272 | node: ts.Node, 273 | sourceFile: ts.SourceFile 274 | ): Lint.Replacement[] { 275 | const decFirst: ts.Decorator = node.decorators![0]; 276 | const indent = getIndentationAtNode(node, sourceFile); 277 | let token = getFirstNonDecoratorToken(node); 278 | let fix: Lint.Replacement[] = []; 279 | 280 | if (token) { 281 | const decEnd = decFirst.getEnd(); 282 | const tokenStart = token.getStart(sourceFile); 283 | 284 | fix.push( 285 | Lint.Replacement.replaceFromTo( 286 | decEnd, 287 | tokenStart, 288 | `\n${indent}` + 289 | node 290 | .decorators!.slice(1) 291 | .map(dec => { 292 | return dec.getFullText(sourceFile).trim(); 293 | }) 294 | .join(`\n${indent}`) 295 | ) 296 | ); 297 | fix.push(Lint.Replacement.appendText(tokenStart, `\n${indent}`)); 298 | } 299 | 300 | return fix; 301 | } 302 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export = { rulesDirectory: "." }; 2 | -------------------------------------------------------------------------------- /src/lifecycleOrderRule.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import * as Lint from "tslint"; 3 | import { codeExamples } from "./code-examples/lifecycleSort.example"; 4 | import { isComponentClass } from "./shared/utils"; 5 | import { LIFECYCLE_METHODS } from "./shared/constants"; 6 | 7 | type Options = "call-order" | "alphabetical"; 8 | 9 | export class Rule extends Lint.Rules.AbstractRule { 10 | public static metadata: Lint.IRuleMetadata = { 11 | ruleName: "lifecycle-order", 12 | description: 13 | "Ensures that Component lifecycle methods are ordered consistently", 14 | optionsDescription: Lint.Utils.dedent` 15 | This rule optionally accepts a single argument, which is a string. It should be one of the following values: 16 | - \`call-order\` 17 | - \`alphabetical\` 18 | 19 | If no argument is provided, this rule will enforce the default functionality (which matches that of \`call-order\`.) 20 | `, 21 | options: { 22 | type: "array", 23 | items: { 24 | type: "string", 25 | enum: ["alphabetical", "call-order"] 26 | }, 27 | minLength: 0, 28 | maxLength: 2 29 | }, 30 | optionExamples: [ 31 | `{ "lifecycle-sort": [true, "call-order"] }`, 32 | `{ "lifecycle-sort": [true, "alphabetical"] }` 33 | ], 34 | rationale: Lint.Utils.dedent` 35 | A consistent ordering for Component lifecycle methods can make Components easier to read, navigate, and edit. 36 | 37 | Ordering lifecycle methods by their natural call order (\`call-order\`) makes the functionality of each self-documenting. 38 | `, 39 | type: "style", 40 | typescriptOnly: true, 41 | codeExamples 42 | }; 43 | public static FAILURE_STRING_CALL_ORDER = 44 | "Component lifecycle methods should be ordered according to their call order"; 45 | public static FAILURE_STRING_ALPHABETICAL = 46 | "Component lifecycle methods should be ordered alphabetically"; 47 | 48 | public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { 49 | let args = this.getOptions().ruleArguments[0]; 50 | if (args) args = args.trim(); 51 | let options: Options; 52 | 53 | if (args && args.match(/^(call-order|alphabetical)$/)) { 54 | options = args; 55 | } else { 56 | options = "call-order"; 57 | } 58 | 59 | return this.applyWithFunction(sourceFile, walk, options); 60 | } 61 | } 62 | 63 | function walk(ctx: Lint.WalkContext) { 64 | return ts.forEachChild(ctx.sourceFile, cb); 65 | 66 | function cb(node: ts.Node): void { 67 | if (!ts.isClassDeclaration(node)) return; 68 | if (!isComponentClass(node)) return; 69 | 70 | const match = 71 | ctx.options === "call-order" 72 | ? [...LIFECYCLE_METHODS] 73 | : [...LIFECYCLE_METHODS].sort(); 74 | 75 | const nodes = new Map(); 76 | const names: string[] = []; 77 | 78 | node.members.forEach(member => { 79 | if ( 80 | member.name && 81 | ts.isIdentifier(member.name) && 82 | LIFECYCLE_METHODS.includes(member.name.text) 83 | ) { 84 | nodes.set(member.name.text, member.name); 85 | names.push(member.name.text); 86 | } 87 | }); 88 | 89 | if (names.length < 2) return; 90 | 91 | names.forEach((name, i) => { 92 | const prev = names[i - 1]; 93 | const next = names[i + 1]; 94 | 95 | let orders = { 96 | prev: prev ? match.findIndex(n => n === prev) : -1, 97 | current: match.findIndex(n => n === name), 98 | next: next ? match.findIndex(n => n === next) : 999 99 | }; 100 | 101 | if (!(orders.prev < orders.current && orders.current < orders.next)) 102 | return ctx.addFailureAtNode( 103 | nodes.get(name)!, 104 | getFailureString(ctx.options) 105 | ); 106 | }); 107 | 108 | return ts.forEachChild(node, cb); 109 | } 110 | } 111 | 112 | function getFailureString(options: Options): string { 113 | return options === "call-order" 114 | ? Rule.FAILURE_STRING_CALL_ORDER 115 | : Rule.FAILURE_STRING_ALPHABETICAL; 116 | } 117 | -------------------------------------------------------------------------------- /src/requirePrefixRule.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import * as Lint from "tslint"; 3 | import { 4 | isComponentClass, 5 | hasDecoratorNamed, 6 | getDeclarationParameters 7 | } from "./shared/utils"; 8 | 9 | type Options = { 10 | valid: string[]; 11 | }; 12 | 13 | export class Rule extends Lint.Rules.AbstractRule { 14 | public static metadata: Lint.IRuleMetadata = { 15 | ruleName: "require-prefix", 16 | description: `Ensures that a Component's \`tag\` begins with the given prefix(es).`, 17 | optionsDescription: Lint.Utils.dedent` 18 | An array of \`"string"\` which a Component \`tag\` must use as a prefix. 19 | `, 20 | options: { 21 | type: "array", 22 | items: { 23 | type: "string" 24 | }, 25 | minLength: 1 26 | }, 27 | optionExamples: [ 28 | `{ "ban-prefix": [true, "ion"] }`, 29 | `{ "ban-prefix": [true, "ion", "ionic"] }` 30 | ], 31 | type: "style", 32 | typescriptOnly: true 33 | }; 34 | public static FAILURE_STRING = 35 | 'Invalid tag prefix "%s". Tag must begin with "%s"'; 36 | 37 | public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { 38 | const options: Options = { 39 | valid: this.getOptions().ruleArguments.map(x => 40 | x.trim().replace(/-$/, "") 41 | ) 42 | }; 43 | 44 | return this.applyWithFunction(sourceFile, walk, options); 45 | } 46 | } 47 | 48 | function walk(ctx: Lint.WalkContext) { 49 | return ts.forEachChild(ctx.sourceFile, cb); 50 | 51 | function cb(node: ts.Node): void { 52 | if (!ts.isClassDeclaration(node)) return; 53 | if (!isComponentClass(node)) return; 54 | 55 | const dec: ts.Decorator = node.decorators!.find( 56 | hasDecoratorNamed("Component") 57 | )!; 58 | const [{ tag }] = getDeclarationParameters<{ tag: string }>(dec); 59 | 60 | if (!tag) return; 61 | 62 | let valid = ctx.options.valid.some(prefix => tag.startsWith(`${prefix}-`)); 63 | 64 | if (valid) return; 65 | const obj = 66 | ts.isCallExpression(dec.expression) && 67 | (dec.expression as ts.CallExpression).arguments[0]; 68 | if (obj && ts.isObjectLiteralExpression(obj)) { 69 | const property = obj.properties.filter(property => { 70 | let name = property.name!.getText(ctx.sourceFile); 71 | return name.indexOf("tag") > -1; 72 | })[0]; 73 | if (property) { 74 | ctx.addFailureAtNode( 75 | property.getChildAt(2, ctx.sourceFile), 76 | Rule.FAILURE_STRING.replace("%s", tag.split("-")[0]).replace( 77 | "%s", 78 | Array.isArray(ctx.options.valid) 79 | ? ctx.options.valid.join("|") 80 | : ctx.options.valid 81 | ) 82 | ); 83 | } 84 | } 85 | 86 | return ts.forEachChild(node, cb); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/shared/constants.ts: -------------------------------------------------------------------------------- 1 | export const LIFECYCLE_METHODS = [ 2 | "componentWillLoad", 3 | "componentDidLoad", 4 | "componentWillUpdate", 5 | "componentDidUpdate", 6 | "componentDidUnload" 7 | ]; 8 | 9 | export const STENCIL_METHODS = ["render"]; 10 | 11 | export const VERBOSE_COMPONENT_MEMBERS: Record = { 12 | element: "@Element property", 13 | event: "@Event properties", 14 | "internal-prop": "internal properties", 15 | lifecycle: "lifecycle methods", 16 | listen: "@Listen methods", 17 | "own-method": "regular internal methods", 18 | "own-prop": "regular internal properties", 19 | prop: "@Prop properties without watcher", 20 | state: "@State properties without watcher", 21 | "stencil-method": "render() method", 22 | watch: "@Watch methods", 23 | "watched-prop": "@Prop properties with a watcher", 24 | "watched-state": "@State properties with a watcher" 25 | }; 26 | -------------------------------------------------------------------------------- /src/shared/utils.ts: -------------------------------------------------------------------------------- 1 | import * as ts from "typescript"; 2 | import { ComponentMetadata } from "../componentMemberOrderRule"; 3 | 4 | export function evalText(text: string) { 5 | const fnStr = `return ${text};`; 6 | return new Function(fnStr)(); 7 | } 8 | 9 | export interface GetDeclarationParameters { 10 | (decorator: ts.Decorator): [T]; 11 | (decorator: ts.Decorator): [T, T1]; 12 | (decorator: ts.Decorator): [T, T1, T2]; 13 | } 14 | export const getDeclarationParameters: GetDeclarationParameters = ( 15 | decorator: ts.Decorator 16 | ): any => { 17 | if (!ts.isCallExpression(decorator.expression)) { 18 | return []; 19 | } 20 | 21 | return decorator.expression.arguments.map(arg => { 22 | return evalText(arg.getText().trim()); 23 | }); 24 | }; 25 | 26 | export function isComponentClass(node: ts.Node): node is ts.ClassDeclaration { 27 | if (!ts.isClassDeclaration(node)) return false; 28 | 29 | return ( 30 | Array.isArray(node.decorators) && 31 | !!node.decorators.filter(hasDecoratorNamed("Component")).length 32 | ); 33 | } 34 | 35 | export function isIdentifierNamed(node: ts.Node, value: string): boolean { 36 | if ( 37 | !( 38 | ts.isClassElement(node) || 39 | ts.isMethodDeclaration(node) || 40 | ts.isPropertyDeclaration(node) 41 | ) 42 | ) 43 | return false; 44 | 45 | return !!( 46 | node.name && 47 | ts.isIdentifier(node.name) && 48 | node.name.text === value 49 | ); 50 | } 51 | 52 | export function hasDecoratorNamed( 53 | name: string 54 | ): (dec: ts.Decorator) => boolean { 55 | return (dec: ts.Decorator) => { 56 | if (!ts.isDecorator(dec)) return false; 57 | return ( 58 | ts.isCallExpression(dec.expression) && 59 | dec.expression.expression && 60 | ts.isIdentifier(dec.expression.expression) && 61 | dec.expression.expression.text === name 62 | ); 63 | }; 64 | } 65 | 66 | export function getIndentationAtNode( 67 | node: ts.Node, 68 | sourceFile: ts.SourceFile 69 | ): string { 70 | const text = node 71 | .getFullText(sourceFile) 72 | .split("\n") 73 | .map(ln => { 74 | const text = /^(\s+)\S/g.exec(ln); 75 | return text ? text[1] : false; 76 | }) 77 | .filter(x => x); 78 | return text[0] as string; 79 | } 80 | 81 | export function getFirstNonDecoratorToken(node: ts.Node): ts.Node | false { 82 | let token: boolean | ts.Node = false; 83 | function isNonDecorator(node: ts.Node) { 84 | if (!token) token = !ts.isDecorator(node) && node; 85 | } 86 | node.forEachChild(isNonDecorator); 87 | return token; 88 | } 89 | 90 | // TODO Actual Implementation 91 | export function getDecoratorArgs(dec: ts.Decorator): T | null { 92 | const args = 93 | dec.expression && 94 | ts.isCallExpression(dec.expression) && 95 | ts.isStringLiteral(dec.expression.arguments[0]) && 96 | (dec.expression.arguments[0] as any).text; 97 | return args ? (args as any) : null; 98 | } 99 | 100 | export function followsOrder(actual: string[], expected: string[]): boolean { 101 | expected = expected.filter(x => actual.includes(x)); 102 | return actual.map((item, i) => expected[i] === item).every(x => x); 103 | } 104 | 105 | export function firstGroupOutOfOrder( 106 | actual: string[], 107 | expected: string[] 108 | ): false | string { 109 | expected = expected.filter(x => actual.includes(x)); 110 | const map = actual.map((item, i) => expected[i] === item); 111 | 112 | return map.every(x => x) ? false : actual[map.findIndex(x => x === false)]; 113 | } 114 | 115 | export function count(arr: ComponentMetadata[], key: string): number { 116 | return arr.filter(x => x.key === key).length; 117 | } 118 | 119 | export function checkGroupings(test: ComponentMetadata[]): ComponentMetadata[] { 120 | const ungrouped: string[] = []; 121 | 122 | // Loop through and save any items that occur more than once 123 | let counts: { [key: string]: number } = {}; 124 | test.forEach(value => { 125 | if (counts[value.key] !== undefined) return; 126 | const num = count(test, value.key); 127 | if (num > 1) counts[value.key] = num; 128 | }); 129 | const multiples = Object.keys(counts); 130 | 131 | // Save original value and index 132 | // Then get all the items that occur more than once 133 | const map = test 134 | .map((value, index) => ({ value, index })) 135 | .filter(x => multiples.includes(x.value.key)); 136 | 137 | // For each unique key, check all of the items of that key 138 | // and determine if they are in sequential order 139 | multiples.forEach(key => { 140 | const sequential = map 141 | .filter(x => x.value.key === key) 142 | .every((curr, i, arr) => { 143 | const next = arr[i + 1]; 144 | if (!next) return true; 145 | return curr.index === next.index - 1; 146 | }); 147 | if (!sequential) ungrouped.push(key); 148 | }); 149 | 150 | return test.filter(comp => ungrouped.includes(comp.key)); 151 | } 152 | -------------------------------------------------------------------------------- /test/rules/ban-prefix/default/ban-prefix.lint: -------------------------------------------------------------------------------- 1 | import { Component } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'my-component' 5 | }) 6 | export class ElementA { } 7 | 8 | @Component({ 9 | tag: 'stencil-component' 10 | ~~~~~~~~~~~~~~~~~~~ [failure % ('stencil')] 11 | }) 12 | export class StencilComponent { } 13 | 14 | @Component({ 15 | tag: 'st-component' 16 | ~~~~~~~~~~~~~~ [failure % ('st')] 17 | }) 18 | export class StComponent { } 19 | 20 | @Component({ 21 | tag: 'stnl-component' 22 | ~~~~~~~~~~~~~~~~ [failure % ('stnl')] 23 | }) 24 | export class StnlComponent { } 25 | 26 | @Component({ 27 | 'tag': 'stencil-component' 28 | ~~~~~~~~~~~~~~~~~~~ [failure % ('stencil')] 29 | }) 30 | export class StencilComponent { } 31 | 32 | @Component({ 33 | "tag": 'stencil-component' 34 | ~~~~~~~~~~~~~~~~~~~ [failure % ('stencil')] 35 | }) 36 | export class StencilComponent { } 37 | 38 | @Component({ 39 | [`tag`]: 'stencil-component' 40 | ~~~~~~~~~~~~~~~~~~~ [failure % ('stencil')] 41 | }) 42 | export class StencilComponent { } 43 | 44 | [failure]: Invalid tag prefix "%s" 45 | -------------------------------------------------------------------------------- /test/rules/ban-prefix/default/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "ban-prefix": [true, "st", "stnl", "stencil"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/rules/component-member-order/alphabetical/simple.lint: -------------------------------------------------------------------------------- 1 | @Component({ 2 | tag: 'my-component' 3 | }) 4 | export class Component { 5 | @Prop() propA: string; 6 | @Prop() propB: string; 7 | @Prop() propC: string; 8 | } 9 | 10 | @Component({ 11 | tag: 'my-component' 12 | }) 13 | export class Component { 14 | @Prop() propA: string; 15 | ~~~~~~~~~~~~~~~~~~~~~~ 16 | @Prop() propC: string; 17 | ~~~~~~~~~~~~~~~~~~~~~~~~ 18 | @Prop() propB: string; 19 | ~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 20 | } 21 | 22 | [failure]: Component members of the same type should be alphabetized -------------------------------------------------------------------------------- /test/rules/component-member-order/alphabetical/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "component-member-order": [ 5 | true, 6 | { 7 | "alphabetical": true 8 | } 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/rules/component-member-order/combined-order-watch/simple.lint: -------------------------------------------------------------------------------- 1 | @Component({ 2 | tag: 'my-component' 3 | }) 4 | export class Component { 5 | @Prop() myProp: string; 6 | @Watch('myProp') myPropChanged() {} 7 | 8 | @Prop() myProp2: string; 9 | @Watch('myProp2') myPropChangedAlso() {} 10 | } 11 | -------------------------------------------------------------------------------- /test/rules/component-member-order/combined-order-watch/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "component-member-order": [ 5 | true, 6 | { 7 | "order": [ 8 | "own-prop", 9 | "element", 10 | "state", 11 | "watched-state", 12 | "internal-prop", 13 | "prop", 14 | "watched-prop", 15 | "event", 16 | "lifecycle", 17 | "listen", 18 | "method", 19 | "own-method", 20 | "stencil-method" 21 | ], 22 | "watch-follows-prop": true 23 | } 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/rules/component-member-order/combined/component-member-order.lint: -------------------------------------------------------------------------------- 1 | @Component({ 2 | tag: 'my-component' 3 | }) 4 | export class Component { 5 | @Prop() myProp: string; 6 | @Event() myEvent: EventEmitter; 7 | } 8 | 9 | @Component({ 10 | tag: 'my-component' 11 | }) 12 | export class Component { 13 | @Prop() myPropB: string; 14 | ~~~~~~~~~~~~~~~~~~~~~~~~ 15 | @Event() myEvent: EventEmitter; 16 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 17 | @Prop() myPropA: string; 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure-group] 19 | } 20 | 21 | @Component({ 22 | tag: 'my-component' 23 | }) 24 | export class Component { 25 | @Event() myEvent: EventEmitter; 26 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure-order] 27 | 28 | @Prop() myPropA: string; 29 | ~~~~~~~~~~~~~~~~~~~~~~~~ 30 | @Prop() myPropC: string; 31 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 | @Prop() myPropB: string; 33 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure-alphabetical] 34 | } 35 | 36 | @Component({ 37 | tag: 'my-component' 38 | }) 39 | export class Component { 40 | @Prop() myPropA: string; 41 | ~~~~~~~~~~~~~~~~~~~~~~~~ 42 | @Prop() myPropC: string; 43 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 44 | @Prop() myPropB: string; 45 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure-alphabetical] 46 | 47 | @Event() myEvent: EventEmitter; 48 | } 49 | 50 | [failure-order]: Component member "event" should be placed after "prop" 51 | [failure-group]: @Prop properties without watcher and @Event properties should not be mixed 52 | [failure-alphabetical]: Component members of the same type should be alphabetized -------------------------------------------------------------------------------- /test/rules/component-member-order/combined/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "component-member-order": [ 5 | true, 6 | { 7 | "order": ["prop", "event"], 8 | "alphabetical": true 9 | } 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/rules/component-member-order/group/simple.lint: -------------------------------------------------------------------------------- 1 | @Component({ 2 | tag: 'my-component' 3 | }) 4 | export class Component { 5 | 6 | num: number; 7 | someText = 'default'; 8 | 9 | @Element() el: HTMLElement; 10 | 11 | @Prop() content: string; 12 | ~~~~~~~~~~~~~~~~~~~~~~~~ 13 | @State() isOpen = false; 14 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | @Prop() enabled: boolean; 16 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 17 | 18 | componentWillLoad() {} 19 | componentDidLoad() {} 20 | 21 | @Method() 22 | open() { } 23 | 24 | render() { 25 | return ( 26 | 29 | ); 30 | } 31 | } 32 | 33 | [failure]: @Prop properties without watcher and @State properties without watcher should not be mixed -------------------------------------------------------------------------------- /test/rules/component-member-order/group/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "component-member-order": [ 5 | true, 6 | { 7 | "order": [ 8 | "own-prop", 9 | "element", 10 | "state", 11 | "internal-prop", 12 | "prop", 13 | "event", 14 | "lifecycle", 15 | "listen", 16 | "method", 17 | "own-method", 18 | "stencil-method" 19 | ] 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/rules/component-member-order/order/simple.lint: -------------------------------------------------------------------------------- 1 | @Component({ 2 | tag: 'my-component' 3 | }) 4 | export class Component { 5 | 6 | @State() isOpen = false; 7 | ~~~~~~~~~~~~~~~~~~~~~~~~ 8 | @State() isClosed = true; 9 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 10 | 11 | num: number; 12 | someText = 'default'; 13 | 14 | 15 | @Prop() content: string; 16 | @Prop() enabled: boolean; 17 | 18 | componentWillLoad() {} 19 | componentDidLoad() {} 20 | 21 | @Method() 22 | open() { } 23 | 24 | render() { 25 | return ( 26 | 29 | ); 30 | } 31 | } 32 | 33 | @Component({ 34 | tag: 'my-component' 35 | }) 36 | export class Component { 37 | @Method() 38 | open() { } 39 | 40 | 41 | render() { 42 | ~~~~~~~~~~ 43 | return ( 44 | ~~~~~~~~~~~~ 45 | 50 | ~~~~~~~~~~~~ 51 | ); 52 | ~~~~~~ 53 | } 54 | ~~~ [failure-after] 55 | 56 | ownMethod() {} [failure-after] 57 | } 58 | 59 | [failure]: Component member "state" should be placed between "own-prop" and "prop" 60 | [failure-after]: Component member "stencil-method" should be placed after "own-method" -------------------------------------------------------------------------------- /test/rules/component-member-order/order/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "component-member-order": [ 5 | true, 6 | { 7 | "order": [ 8 | "own-prop", 9 | "element", 10 | "state", 11 | "internal-prop", 12 | "prop", 13 | "event", 14 | "lifecycle", 15 | "listen", 16 | "method", 17 | "own-method", 18 | "stencil-method" 19 | ] 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/rules/component-member-order/stencil-style/invalid.lint: -------------------------------------------------------------------------------- 1 | @Component({ 2 | tag: 'my-component' 3 | }) 4 | export class Component { 5 | @State() valid = false; 6 | @Prop() myProp: boolean; 7 | render() {} 8 | } 9 | 10 | @Component({ 11 | tag: 'my-component' 12 | }) 13 | export class Component { 14 | @Prop() myProp: boolean; 15 | ~~~~~~~~~~~~~~~~~~~~~~~~ ([failure] % "prop", between "state" and "stencil-method") 16 | @State() valid = false; 17 | render() {} 18 | } 19 | 20 | @Component({ 21 | tag: 'my-component' 22 | }) 23 | export class Component { 24 | @State() valid = false; 25 | render() {} 26 | ~~~~~~~~~~~~~~~~~~~~~~~~ ([failure] % "stencil-method", after \"prop\") 27 | @Prop() myProp: boolean; 28 | } 29 | 30 | @Component({ 31 | tag: 'my-component' 32 | }) 33 | export class Component { 34 | render() {} 35 | ~~~~~~~~~~~ ([failure] % "stencil-method", after "prop") 36 | @State() valid = false; 37 | @Prop() myProp: boolean; 38 | } 39 | 40 | 41 | [failure]: Component member %s should be placed %s -------------------------------------------------------------------------------- /test/rules/component-member-order/stencil-style/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "component-member-order": [ 5 | true, 6 | { 7 | "order": [ 8 | "own-prop", 9 | "element", 10 | "state", 11 | "watched-state", 12 | "internal-prop", 13 | "prop", 14 | "watched-prop", 15 | "event", 16 | "lifecycle", 17 | "listen", 18 | "method", 19 | "own-method", 20 | "stencil-method" 21 | ], 22 | "watch-follows-prop": true, 23 | "alphabetical": true 24 | } 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/rules/component-member-order/stencil-style/valid.lint: -------------------------------------------------------------------------------- 1 | @Component({ 2 | tag: 'ion-something', 3 | styleUrl: 'something.scss', 4 | styleUrls: { 5 | ios: 'something.ios.scss', 6 | md: 'something.md.scss', 7 | wp: 'something.wp.scss' 8 | }, 9 | host: { 10 | theme: 'something' 11 | } 12 | }) 13 | export class Something { 14 | 15 | /** 16 | * 1. Own Properties 17 | * Always set the type if a default value has not 18 | * been set. If a default value is being set, then type 19 | * is already inferred. List the own properties in 20 | * alphabetical order. Note that because these properties 21 | * do not have the @Prop() decorator, they will not be exposed 22 | * publicly on the host element, but only used internally. 23 | */ 24 | num: number; 25 | someText = 'default'; 26 | 27 | /** 28 | * 2. Reference to host HTML element. 29 | * Inlined decorator 30 | */ 31 | @Element() el: HTMLElement; 32 | 33 | /** 34 | * 3. State() variables 35 | * Inlined decorator, alphabetical order. 36 | */ 37 | @State() isValidated: boolean; 38 | @State() status = 0; 39 | 40 | /** 41 | * 4. Internal props (context and connect) 42 | * Inlined decorator, alphabetical order. 43 | */ 44 | @Prop({ context: 'config' }) config: Config; 45 | @Prop({ connect: 'ion-menu-controller' }) lazyMenuCtrl: Lazy; 46 | 47 | /** 48 | * 5. Public Property API 49 | * Inlined decorator, alphabetical order. These are 50 | * different than "own properties" in that public props 51 | * are exposed as properties and attributes on the host element. 52 | * Requires JSDocs for public API documentation. 53 | */ 54 | @Prop() content: string; 55 | @Prop() enabled: boolean; 56 | @Prop() menuId: string; 57 | @Prop() type = 'overlay'; 58 | 59 | /** 60 | * Prop lifecycle events SHOULD go just behind the Prop they listen to. 61 | * This makes sense since both statements are strongly connected. 62 | * - If renaming the instance variable name you must also update the name in @Watch() 63 | * - Code is easier to follow and maintain. 64 | */ 65 | @Prop() swipeEnabled = true; 66 | 67 | @Watch('swipeEnabled') 68 | swipeEnabledChanged() { 69 | this.updateState(); 70 | } 71 | 72 | /** 73 | * 6. Events section 74 | * Inlined decorator, alphabetical order. 75 | * Requires JSDocs for public API documentation. 76 | */ 77 | @Event() ionClose: EventEmitter; 78 | @Event() ionDrag: EventEmitter; 79 | @Event() ionOpen: EventEmitter; 80 | 81 | componentDidLoad() {} 82 | componentDidUnload() {} 83 | componentDidUpdate() {} 84 | componentWillLoad() {} 85 | componentWillUpdate() {} 86 | 87 | /** 88 | * 8. Listeners 89 | * It is ok to place them in a different location 90 | * if makes more sense in the context. Recommend 91 | * starting a listener method with "on". 92 | * Always use two lines. 93 | */ 94 | @Listen('click', { enabled: false }) 95 | onClick(ev: UIEvent) { 96 | console.log('hi!') 97 | } 98 | 99 | /** 100 | * 9. Public methods API 101 | * These methods are exposed on the host element. 102 | * Always use two lines. 103 | * Requires JSDocs for public API documentation. 104 | */ 105 | @Method() 106 | close() { } 107 | 108 | @Method() 109 | open() { } 110 | 111 | 112 | /** 113 | * 10. Local methods 114 | * Internal business logic. These methods cannot be 115 | * called from the host element. 116 | */ 117 | prepareAnimation(): Promise { } 118 | 119 | updateState() { } 120 | 121 | /** 122 | * 11. hostData() function 123 | * Used to dynamically set host element attributes. 124 | * Should be placed directly above render() 125 | */ 126 | hostData() { 127 | return { 128 | attribute: 'navigation', 129 | side: this.isRightSide ? 'right' : 'left', 130 | type: this.type, 131 | class: { 132 | 'something-is-animating': this.isAnimating 133 | } 134 | }; 135 | } 136 | 137 | /** 138 | * 12. render() function 139 | * Always the last one in the class. 140 | */ 141 | render() { 142 | return ( 143 | 146 | ); 147 | } 148 | } -------------------------------------------------------------------------------- /test/rules/component-member-order/watch/simple.lint: -------------------------------------------------------------------------------- 1 | @Component({ 2 | tag: 'my-component' 3 | }) 4 | export class Component { 5 | @Prop() myPropA: string; 6 | @Watch('myPropA') myPropAChanged() { } 7 | 8 | @Prop() myPropB: string; 9 | @Watch('myPropB') myPropBChanged() { } 10 | 11 | @Prop() myPropC: string; 12 | @Watch('myPropC') myPropCChanged() { } 13 | } 14 | 15 | @Component({ 16 | tag: 'my-component' 17 | }) 18 | export class Component { 19 | @Prop() myPropA: string; 20 | @Prop() myPropB: string; 21 | @Prop() myPropC: string; 22 | 23 | @Watch('myPropA') myPropAChanged() { } 24 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 25 | @Watch('myPropB') myPropBChanged() { } 26 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 27 | @Watch('myPropC') myPropCChanged() { } 28 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 29 | } 30 | 31 | @Component({ 32 | tag: 'my-component' 33 | }) 34 | export class Component { 35 | @State() myState: string; 36 | @Watch('myState') myStateChanged() {} 37 | 38 | @Prop() myProp: string; 39 | @Watch('myProp') myPropChanged() {} 40 | } 41 | 42 | @Component({ 43 | tag: 'my-component' 44 | }) 45 | export class Component { 46 | @State() myState: string; 47 | @Prop() myProp: string; 48 | 49 | @Watch('myState') myStateChanged() {} 50 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 51 | @Watch('myProp') myPropChanged() {} 52 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 53 | } 54 | 55 | [failure]: Watch methods should immediately follow the declaration of the Prop/State they watch -------------------------------------------------------------------------------- /test/rules/component-member-order/watch/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "component-member-order": [ 5 | true, 6 | { 7 | "watch-follows-prop": true 8 | } 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/rules/components-per-file/one/components-per-file.ts.lint: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from '@stencil/core'; 2 | 3 | class NonComponent { 4 | render() { } 5 | someOtherMethod() { } 6 | } 7 | 8 | @Component({ 9 | tag: 'my-element-a' 10 | }) 11 | export class ElementA { } -------------------------------------------------------------------------------- /test/rules/components-per-file/one/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "components-per-file": [true, 1] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/rules/components-per-file/three/components-per-file.ts.lint: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from '@stencil/core'; 2 | 3 | class NonComponent { 4 | render() { } 5 | someOtherMethod() { } 6 | } 7 | 8 | @Component({ 9 | tag: 'my-element-a' 10 | }) 11 | export class ElementA { } 12 | 13 | @Component({ 14 | tag: 'my-element-b' 15 | }) 16 | export class ElementB { } 17 | 18 | @Component({ 19 | tag: 'my-element-c' 20 | }) 21 | export class ElementC { } 22 | 23 | @Component({ 24 | ~~~~~~~~~~~~ 25 | tag: 'my-element-b' 26 | ~~~~~~~~~~~~~~~~~~~~~~~ 27 | }) 28 | ~~ 29 | export class ElementB { } 30 | ~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 31 | 32 | [failure]: Files may only contain 3 components -------------------------------------------------------------------------------- /test/rules/components-per-file/three/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "components-per-file": [true, 3] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/rules/components-per-file/two/components-per-file.ts.lint: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from '@stencil/core'; 2 | 3 | class NonComponent { 4 | render() { } 5 | someOtherMethod() { } 6 | } 7 | 8 | @Component({ 9 | tag: 'my-element-a' 10 | }) 11 | export class ElementA { } 12 | 13 | @Component({ 14 | ~~~~~~~~~~~~ 15 | tag: 'my-element-b' 16 | ~~~~~~~~~~~~~~~~~~~~~~~ 17 | }) 18 | ~~ 19 | export class ElementA { } 20 | ~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 21 | 22 | [failure]: Files may only contain 1 component -------------------------------------------------------------------------------- /test/rules/components-per-file/two/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "components-per-file": [true, 1] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/rules/decorated-member-style/methods-multiline/decorated-member-style.lint: -------------------------------------------------------------------------------- 1 | import { Component, Listen, Method } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'my-component' 5 | }) 6 | export class ElementA { 7 | 8 | localMethod() { 9 | return false; 10 | } 11 | 12 | @Listen('click') mySingleMethod(): void { }; 13 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 14 | 15 | @Listen('click') myMixedMethod(): void { 16 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 17 | }; 18 | ~~~~~ [failure] 19 | 20 | @Method() 21 | myMultiMethod(): string { 22 | 23 | }; 24 | 25 | @Listen('eventA') 26 | @Listen('eventB') 27 | myComposedHandler(): string { 28 | 29 | }; 30 | 31 | @Listen('eventA') 32 | ~~~~~~~~~~~~~~~~~ 33 | @Listen('eventB') myComposedHandler(): string { 34 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 35 | }; 36 | ~~~~~ [failure] 37 | 38 | @Listen('eventA') @Listen('eventB') 39 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 40 | myComposedHandler(): string { 41 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 42 | }; 43 | ~~~~~ [failure-composition] 44 | 45 | @Listen('eventA') 46 | ~~~~~~~~~~~~~~~~~ 47 | @Listen('eventB') 48 | ~~~~~~~~~~~~~~~~~~~~~ 49 | @Listen('eventC') @Listen('eventD') 50 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 | myComposedHandler(): string { 52 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 53 | }; 54 | ~~~~~ [failure-composition] 55 | 56 | @Listen('eventA') @Listen('eventB') @Listen('eventC') myComposedHandler(): string { 57 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 58 | }; 59 | ~~~~~ [failure-composition] 60 | } 61 | 62 | [failure]: Component method decorators should be multiline 63 | [failure-composition]: Component method decorators should each be on their own lines -------------------------------------------------------------------------------- /test/rules/decorated-member-style/methods-multiline/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "decorated-member-style": [ 5 | true, 6 | { 7 | "methods": "multiline" 8 | } 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/rules/decorated-member-style/methods-singleline/decorated-member-style.lint: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'my-component' 5 | }) 6 | export class ElementA { 7 | 8 | 9 | @Listen('click') mySingleMethod(): void { }; 10 | 11 | @Listen('click') myMixedMethod(): void { 12 | 13 | }; 14 | 15 | @Method() 16 | ~~~~~~~~~ 17 | myMultiMethod(): string { 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | }; 20 | ~~~~~ [failure] 21 | } 22 | 23 | [failure]: Component method decorators should be inlined -------------------------------------------------------------------------------- /test/rules/decorated-member-style/methods-singleline/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "decorated-member-style": [ 5 | true, 6 | { 7 | "methods": "singleline" 8 | } 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/rules/decorated-member-style/properties-multiline/decorated-member-style.lint: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'my-component' 5 | }) 6 | export class ElementA { 7 | 8 | ownProp = false; 9 | 10 | @Prop() protected mySingleProp: string; 11 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 12 | 13 | @Prop() 14 | myMultiProp: string; 15 | } 16 | 17 | [failure]: Component property decorators should be multiline -------------------------------------------------------------------------------- /test/rules/decorated-member-style/properties-multiline/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "decorated-member-style": [ 5 | true, 6 | { 7 | "properties": "multiline" 8 | } 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/rules/decorated-member-style/properties-singleline/decorated-member-style.lint: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'my-component' 5 | }) 6 | export class ElementA { 7 | 8 | ownProp = false; 9 | 10 | @Prop() mySingleProp: string; 11 | 12 | @Prop() 13 | ~~~~~~~ 14 | myMultiProp: string; 15 | ~~~~~~~~~~~~~~~~~~~~~~~~ [failure] 16 | } 17 | 18 | [failure]: Component property decorators should be inlined -------------------------------------------------------------------------------- /test/rules/decorated-member-style/properties-singleline/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "decorated-member-style": [ 5 | true, 6 | { 7 | "properties": "singleline" 8 | } 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/rules/lifecycle-order/alphabetical/lifecycle-sort.lint: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'my-component' 5 | }) 6 | export class Component { 7 | someFunction() { } 8 | } 9 | 10 | @Component({ 11 | tag: 'my-component' 12 | }) 13 | export class Component { 14 | componentWillLoad() { } 15 | } 16 | 17 | @Component({ 18 | tag: 'my-component' 19 | }) 20 | export class Component { 21 | componentDidLoad() {} 22 | componentDidUnload() {} 23 | componentDidUpdate() {} 24 | componentWillLoad() {} 25 | componentWillUpdate() {} 26 | } 27 | 28 | @Component({ 29 | tag: 'my-component' 30 | }) 31 | export class Component { 32 | @Prop() propA: string; 33 | @Prop() propB: string; 34 | @Prop() propC: string; 35 | 36 | componentWillUpdate() { } 37 | ~~~~~~~~~~~~~~~~~~~ [failure] 38 | componentWillLoad() { } 39 | ~~~~~~~~~~~~~~~~~ [failure] 40 | componentDidUpdate() { } 41 | ~~~~~~~~~~~~~~~~~~ [failure] 42 | componentDidUnload() { } 43 | ~~~~~~~~~~~~~~~~~~ [failure] 44 | componentDidLoad() { } 45 | ~~~~~~~~~~~~~~~~ [failure] 46 | 47 | hostData() { } 48 | render() { } 49 | } 50 | 51 | @Component({ 52 | tag: 'my-component' 53 | }) 54 | export class Component { 55 | componentDidUnload() { } 56 | ~~~~~~~~~~~~~~~~~~ [failure] 57 | componentDidLoad() { } 58 | ~~~~~~~~~~~~~~~~ [failure] 59 | } 60 | 61 | @Component({ 62 | tag: 'my-component' 63 | }) 64 | export class Component { 65 | @Prop() propA: string; 66 | @Prop() propB: string; 67 | @Prop() propC: string; 68 | 69 | componentDidLoad() { } 70 | componentDidUnload() { } 71 | componentDidUpdate() { } 72 | componentWillUpdate() { } 73 | ~~~~~~~~~~~~~~~~~~~ [failure] 74 | componentWillLoad() { } 75 | ~~~~~~~~~~~~~~~~~ [failure] 76 | 77 | 78 | render() { } 79 | } 80 | 81 | @Component({ 82 | tag: 'my-component' 83 | }) 84 | export class Component { 85 | componentDidUnload() { } 86 | componentWillLoad() { } 87 | componentWillUpdate() { } 88 | } 89 | 90 | [failure]: Component lifecycle methods should be ordered alphabetically 91 | -------------------------------------------------------------------------------- /test/rules/lifecycle-order/alphabetical/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "lifecycle-order": [true, "alphabetical"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/rules/lifecycle-order/call-order/lifecycle-sort.lint: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'my-component' 5 | }) 6 | export class Component { 7 | someFunction() { } 8 | } 9 | 10 | @Component({ 11 | tag: 'my-component' 12 | }) 13 | export class Component { 14 | componentWillLoad() { } 15 | } 16 | 17 | @Component({ 18 | tag: 'my-component' 19 | }) 20 | export class Component { 21 | componentWillLoad() { } 22 | componentDidLoad() { } 23 | componentWillUpdate() { } 24 | componentDidUpdate() { } 25 | componentDidUnload() { } 26 | } 27 | 28 | @Component({ 29 | tag: 'my-component' 30 | }) 31 | export class Component { 32 | @Prop() propA: string; 33 | @Prop() propB: string; 34 | @Prop() propC: string; 35 | 36 | componentDidUnload() { } 37 | ~~~~~~~~~~~~~~~~~~ [failure] 38 | componentDidUpdate() { } 39 | ~~~~~~~~~~~~~~~~~~ [failure] 40 | componentWillUpdate() { } 41 | ~~~~~~~~~~~~~~~~~~~ [failure] 42 | componentDidLoad() { } 43 | ~~~~~~~~~~~~~~~~ [failure] 44 | componentWillLoad() { } 45 | ~~~~~~~~~~~~~~~~~ [failure] 46 | 47 | hostData() { } 48 | render() { } 49 | } 50 | 51 | @Component({ 52 | tag: 'my-component' 53 | }) 54 | export class Component { 55 | componentDidUnload() { } 56 | ~~~~~~~~~~~~~~~~~~ [failure] 57 | componentDidLoad() { } 58 | ~~~~~~~~~~~~~~~~ [failure] 59 | } 60 | 61 | @Component({ 62 | tag: 'my-component' 63 | }) 64 | export class Component { 65 | @Prop() propA: string; 66 | @Prop() propB: string; 67 | @Prop() propC: string; 68 | 69 | componentWillLoad() { } 70 | componentDidLoad() { } 71 | componentWillUpdate() { } 72 | componentDidUnload() { } 73 | ~~~~~~~~~~~~~~~~~~ [failure] 74 | componentDidUpdate() { } 75 | ~~~~~~~~~~~~~~~~~~ [failure] 76 | 77 | render() { } 78 | } 79 | 80 | @Component({ 81 | tag: 'my-component' 82 | }) 83 | export class Component { 84 | componentWillLoad() { } 85 | componentWillUpdate() { } 86 | componentDidUnload() { } 87 | } 88 | 89 | [failure]: Component lifecycle methods should be ordered according to their call order 90 | -------------------------------------------------------------------------------- /test/rules/lifecycle-order/call-order/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "lifecycle-order": [true, "call-order"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/rules/lifecycle-order/default/lifecycle-sort.lint: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'my-component' 5 | }) 6 | export class Component { 7 | someFunction() { } 8 | } 9 | 10 | @Component({ 11 | tag: 'my-component' 12 | }) 13 | export class Component { 14 | componentWillLoad() { } 15 | } 16 | 17 | @Component({ 18 | tag: 'my-component' 19 | }) 20 | export class Component { 21 | componentWillLoad() { } 22 | componentDidLoad() { } 23 | componentWillUpdate() { } 24 | componentDidUpdate() { } 25 | componentDidUnload() { } 26 | } 27 | 28 | @Component({ 29 | tag: 'my-component' 30 | }) 31 | export class Component { 32 | @Prop() propA: string; 33 | @Prop() propB: string; 34 | @Prop() propC: string; 35 | 36 | componentDidUnload() { } 37 | ~~~~~~~~~~~~~~~~~~ [failure] 38 | componentDidUpdate() { } 39 | ~~~~~~~~~~~~~~~~~~ [failure] 40 | componentWillUpdate() { } 41 | ~~~~~~~~~~~~~~~~~~~ [failure] 42 | componentDidLoad() { } 43 | ~~~~~~~~~~~~~~~~ [failure] 44 | componentWillLoad() { } 45 | ~~~~~~~~~~~~~~~~~ [failure] 46 | 47 | hostData() { } 48 | render() { } 49 | } 50 | 51 | @Component({ 52 | tag: 'my-component' 53 | }) 54 | export class Component { 55 | componentDidUnload() { } 56 | ~~~~~~~~~~~~~~~~~~ [failure] 57 | componentDidLoad() { } 58 | ~~~~~~~~~~~~~~~~ [failure] 59 | } 60 | 61 | @Component({ 62 | tag: 'my-component' 63 | }) 64 | export class Component { 65 | @Prop() propA: string; 66 | @Prop() propB: string; 67 | @Prop() propC: string; 68 | 69 | componentWillLoad() { } 70 | componentDidLoad() { } 71 | componentWillUpdate() { } 72 | componentDidUnload() { } 73 | ~~~~~~~~~~~~~~~~~~ [failure] 74 | componentDidUpdate() { } 75 | ~~~~~~~~~~~~~~~~~~ [failure] 76 | 77 | render() { } 78 | } 79 | 80 | @Component({ 81 | tag: 'my-component' 82 | }) 83 | export class Component { 84 | componentWillLoad() { } 85 | componentWillUpdate() { } 86 | componentDidUnload() { } 87 | } 88 | 89 | [failure]: Component lifecycle methods should be ordered according to their call order 90 | -------------------------------------------------------------------------------- /test/rules/lifecycle-order/default/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "lifecycle-order": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/rules/require-prefix/multiple/require-prefix.lint: -------------------------------------------------------------------------------- 1 | import { Component } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'ion-component' 5 | }) 6 | export class Component { } 7 | 8 | @Component({ 9 | tag: 'ionic-component' 10 | }) 11 | export class Component { } 12 | 13 | @Component({ 14 | tag: 'my-component' 15 | ~~~~~~~~~~~~~~ [failure % ('my')] 16 | }) 17 | export class Component { } 18 | 19 | 20 | [failure]: Invalid tag prefix "%s". Tag must begin with "ion|ionic" 21 | -------------------------------------------------------------------------------- /test/rules/require-prefix/multiple/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "require-prefix": [true, "ion", "ionic"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/rules/require-prefix/single/require-prefix.lint: -------------------------------------------------------------------------------- 1 | import { Component } from '@stencil/core'; 2 | 3 | @Component({ 4 | tag: 'ion-component' 5 | }) 6 | export class Component { } 7 | 8 | @Component({ 9 | tag: 'ionic-component' 10 | ~~~~~~~~~~~~~~~~~ [failure % ('ionic')] 11 | }) 12 | export class Component { } 13 | 14 | @Component({ 15 | tag: 'my-component' 16 | ~~~~~~~~~~~~~~ [failure % ('my')] 17 | }) 18 | export class Component { } 19 | 20 | 21 | [failure]: Invalid tag prefix "%s". Tag must begin with "ion" 22 | -------------------------------------------------------------------------------- /test/rules/require-prefix/single/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["../../../../rules"], 3 | "rules": { 4 | "require-prefix": [true, "ion"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "forceConsistentCasingInFileNames": true, 4 | "downlevelIteration": true, 5 | "noEmitOnError": true, 6 | "noFallthroughCasesInSwitch": true, 7 | "noImplicitAny": true, 8 | "noImplicitReturns": true, 9 | "noImplicitThis": true, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "strictNullChecks": true, 13 | "module": "commonjs", 14 | "target": "es5", 15 | "inlineSourceMap": true, 16 | "outDir": "rules", 17 | "lib": ["es2015", "es2016.array.include", "dom"] 18 | }, 19 | "include": ["src/*.ts"] 20 | } 21 | -------------------------------------------------------------------------------- /tslint-stencil.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": "rules", 3 | "rules": { 4 | "ban-prefix": false, 5 | "decorated-member-style": false, 6 | "lifecycle-order": false, 7 | "one-component-per-file": false, 8 | "watch-follows-prop": false, 9 | "render-as-final-method": false, 10 | "host-data-precedes-render": false, 11 | "require-prefix": false 12 | } 13 | } 14 | --------------------------------------------------------------------------------