diff --git a/.circleci/config.yml b/.circleci/config.yml index adf50b42cb2..8ca7220c2bb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -96,6 +96,17 @@ jobs: key: dependency-cache-{{ checksum "yarn.lock" }} - run: yarn add typescript@2.9 - run: yarn test + test3.0: + docker: + - image: circleci/node:6 + steps: + - checkout + - attach_workspace: + at: '.' + - restore_cache: + key: dependency-cache-{{ checksum "yarn.lock" }} + - run: yarn add typescript@3.0.1 + - run: yarn test testRc: docker: - image: circleci/node:6 @@ -145,6 +156,9 @@ workflows: - test2.9: requires: - build + - test3.0: + requires: + - build - testRc: requires: - build diff --git a/.prettierrc.json b/.prettierrc.json index a27a5d7f6ff..6bc5f32c899 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,4 +1,5 @@ { "tabWidth": 4, - "printWidth": 100 + "printWidth": 100, + "trailingComma": "all" } diff --git a/docs/_config.yml b/docs/_config.yml index ce26a2f8b20..940935cf025 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -2,11 +2,11 @@ title: TSLint email: your-email@domain.com description: > # this means to ignore newlines until "baseurl:" - TSLint documentation. A linter for the TypeScript language. + TSLint documentation. A linter for the TypeScript language. baseurl: "/tslint" # the subpath of your site, e.g. /blog/ url: "https://palantir.github.io/" # the base hostname & protocol for your site twitter_username: PalantirTech -github_username: palantir/tslint +github_username: palantir/tslint # Build settings markdown: kramdown @@ -14,7 +14,7 @@ markdown_ext: md exclude: [vendor] page_gen: - - data: rules - template: rule - name: ruleName - dir: rules + - data: rules + template: rule + name: ruleName + dir: rules diff --git a/docs/_sass/_base.scss b/docs/_sass/_base.scss index a1e7726d4de..edccd7e93b7 100644 --- a/docs/_sass/_base.scss +++ b/docs/_sass/_base.scss @@ -1,27 +1,46 @@ /** * Reset some basic elements */ -body, h1, h2, h3, h4, h5, h6, -p, blockquote, pre, hr, -dl, dd, ol, ul, figure { +body, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +hr, +dl, +dd, +ol, +ul, +figure { margin: 0; padding: 0; } - - /** * Set `margin-bottom` to maintain vertical rhythm */ -h1, h2, h3, h4, h5, h6, -p, blockquote, pre, -ul, ol, dl, figure, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +ul, +ol, +dl, +figure, %vertical-rhythm { margin-bottom: 1rem; } - - /** * Images */ @@ -30,8 +49,6 @@ img { vertical-align: middle; } - - /** * Figures */ @@ -58,7 +75,6 @@ figcaption { * Icons */ .icon { - > svg { display: inline-block; width: 16px; @@ -71,18 +87,17 @@ figcaption { } } - /** * Rules & Feature Badges */ - .rules-list { +.rules-list { list-style: none; margin: 0 !important; //need to override the `main-content ul` selector > li { &:nth-child(odd) { a { - background-color: rgba(0, 0, 0, .03); + background-color: rgba(0, 0, 0, 0.03); } } @@ -90,27 +105,27 @@ figcaption { display: block; border-left: 3px solid transparent; text-decoration: none; - padding: .75rem; + padding: 0.75rem; &:hover { - background-color: rgba(0, 0, 0,.075); + background-color: rgba(0, 0, 0, 0.075); border-left-color: #159957; } } } - } +} - .rule-features { - //This is the container for a list of feature badges +.rule-features { + //This is the container for a list of feature badges display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; - } +} - .feature { - //This is the setup for the a feature badge +.feature { + //This is the setup for the a feature badge display: inline-block; margin-right: 2px; padding: 2px 4px; @@ -120,7 +135,7 @@ figcaption { white-space: nowrap; vertical-align: baseline; border: 1px solid transparent; - border-radius: .25rem; + border-radius: 0.25rem; cursor: help; &:before { @@ -137,9 +152,9 @@ figcaption { &.feature-ts-only { //This feature badge is added to rules that are "TypeScript Only" - background-color: #FCF8E3; - border-color: #FAF2CC; - color: #8A6D3B; + background-color: #fcf8e3; + border-color: #faf2cc; + color: #8a6d3b; &:before { content: "\1F4C4"; //"page facing up" icon - http://www.fileformat.info/info/unicode/char/1F4C4/index.htm @@ -148,9 +163,9 @@ figcaption { &.feature-fixer { //This feature badge is added to rules that have an auto-fixer - background-color: #DFF0D8; - border-color: #D0E9C6; - color: #3C763D; + background-color: #dff0d8; + border-color: #d0e9c6; + color: #3c763d; &:before { content: "\1f527"; //"wrench" icon - http://www.fileformat.info/info/unicode/char/1f527/index.htm @@ -159,20 +174,20 @@ figcaption { &.feature-requires-type-info { //This feature badge is added to rules that require type information - background-color: #F2DEDE; - border-color: #EBCCCC; - color: #A94442; + background-color: #f2dede; + border-color: #ebcccc; + color: #a94442; &:before { content: "\2139"; //"information source" icon - http://www.fileformat.info/info/unicode/char/2139/index.htm //Surround it with a blue circle border-radius: 50%; - background: #0078D7; - color: #FFF; + background: #0078d7; + color: #fff; width: 1em; } } - } +} .wrapper__code-example { margin-bottom: 64px; @@ -195,7 +210,8 @@ figcaption { background-color: #fff5f5; } - pre, .highlight { + pre, + .highlight { background: transparent; } } diff --git a/docs/_sass/_cayman.scss b/docs/_sass/_cayman.scss index 265338c51bc..9dbbc3d2a27 100644 --- a/docs/_sass/_cayman.scss +++ b/docs/_sass/_cayman.scss @@ -2,55 +2,67 @@ $large-breakpoint: 64em; $medium-breakpoint: 36em; @mixin large { - @media screen and (min-width: #{$large-breakpoint}) { - @content; - } + @media screen and (min-width: #{$large-breakpoint}) { + @content; + } } @mixin medium { - @media screen and (min-width: #{$medium-breakpoint}) and (max-width: #{$large-breakpoint}) { - @content; - } + @media screen and (min-width: #{$medium-breakpoint}) and (max-width: #{$large-breakpoint}) { + @content; + } } @mixin small { - @media screen and (max-width: #{$medium-breakpoint}) { - @content; - } + @media screen and (max-width: #{$medium-breakpoint}) { + @content; + } } * { - box-sizing: border-box; + box-sizing: border-box; } body { - padding: 0; - margin: 0; - font-family: $font-stack; - font-size: $base-font-size; - line-height: $base-line-height; - color: $text-color; + padding: 0; + margin: 0; + font-family: $font-stack; + font-size: $base-font-size; + line-height: $base-line-height; + color: $text-color; } a { - color: $link-color; - text-decoration: none; + color: $link-color; + text-decoration: none; - &:hover { - text-decoration: underline; - } + &:hover { + text-decoration: underline; + } - &:visited { - color: $link-visited-color; - } + &:visited { + color: $link-visited-color; + } } -h1 { font-size: 2.5rem; } -h2 { font-size: 2rem; } -h3 { font-size: 1.6rem; } -h4 { font-size: 1.4rem; } -h5 { font-size: 1.2rem; } -h6 { font-size: 1rem; } +h1 { + font-size: 2.5rem; +} +h2 { + font-size: 2rem; +} +h3 { + font-size: 1.6rem; +} +h4 { + font-size: 1.4rem; +} +h5 { + font-size: 1.2rem; +} +h6 { + font-size: 1rem; +} /** * Site header @@ -71,7 +83,8 @@ $header-hover-color: rgba(255, 255, 255, 0.8); margin-bottom: 0; float: left; - &, &:visited { + &, + &:visited { color: $header-content-color; } @@ -81,8 +94,8 @@ $header-hover-color: rgba(255, 255, 255, 0.8); } @include small { - display: block; - text-align: left; + display: block; + text-align: left; } } @@ -91,7 +104,8 @@ $header-hover-color: rgba(255, 255, 255, 0.8); line-height: 56px; .page-link { - &, &:visited { + &, + &:visited { color: $header-content-color; } @@ -107,394 +121,394 @@ $header-hover-color: rgba(255, 255, 255, 0.8); } @include small { - display: block; - text-align: left; - &:not(:first-child) { - margin-left: 0; - } + display: block; + text-align: left; + &:not(:first-child) { + margin-left: 0; + } } } } .btn { - display: inline-block; - margin-bottom: 1rem; - background-color: rgba(255, 255, 255, 0.08); - border-color: rgba(255, 255, 255, 0.2); - border-style: solid; - border-width: 1px; - border-radius: 0.3rem; - transition: color 0.2s, background-color 0.2s, border-color 0.2s; - - &, &:visited { - color: $header-content-color; - } - - &:hover { - color: $header-hover-color; - text-decoration: none; - background-color: rgba(255, 255, 255, 0.2); - border-color: rgba(255, 255, 255, 0.3); - } + display: inline-block; + margin-bottom: 1rem; + background-color: rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.2); + border-style: solid; + border-width: 1px; + border-radius: 0.3rem; + transition: color 0.2s, background-color 0.2s, border-color 0.2s; - + .btn { - margin-left: 1rem; - } + &, + &:visited { + color: $header-content-color; + } - @include large { - padding: 0.75rem 1rem; - } + &:hover { + color: $header-hover-color; + text-decoration: none; + background-color: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.3); + } - @include medium { - padding: 0.6rem 0.9rem; - font-size: 0.9rem; - } + + .btn { + margin-left: 1rem; + } - @include small { - display: block; - width: 100%; - padding: 0.75rem; - font-size: 0.9rem; + @include large { + padding: 0.75rem 1rem; + } - + .btn { - margin-top: 1rem; - margin-left: 0; + @include medium { + padding: 0.6rem 0.9rem; + font-size: 0.9rem; + } + + @include small { + display: block; + width: 100%; + padding: 0.75rem; + font-size: 0.9rem; + + + .btn { + margin-top: 1rem; + margin-left: 0; + } } - } } .header { - color: #fff; - text-align: center; - background-color: #159957; - background-image: linear-gradient(120deg, #155799, #159957); + color: #fff; + text-align: center; + background-color: #159957; + background-image: linear-gradient(120deg, #155799, #159957); } .page-header { - @include large { - padding: 3rem; - } + @include large { + padding: 3rem; + } - @include medium { - padding: 2rem; - } + @include medium { + padding: 2rem; + } - @include small { - padding: 1rem; - } + @include small { + padding: 1rem; + } } .project-name { - margin-top: 0; - margin-bottom: 0.1rem; + margin-top: 0; + margin-bottom: 0.1rem; - @include large { - font-size: 3.25rem; - } + @include large { + font-size: 3.25rem; + } - @include medium { - font-size: 2.25rem; - } + @include medium { + font-size: 2.25rem; + } - @include small { - font-size: 1.75rem; - } + @include small { + font-size: 1.75rem; + } } .project-tagline { - margin-bottom: 2rem; - font-weight: normal; - opacity: 0.7; + margin-bottom: 2rem; + font-weight: normal; + opacity: 0.7; - @include large { - font-size: 1.25rem; - } + @include large { + font-size: 1.25rem; + } - @include medium { - font-size: 1.15rem; - } + @include medium { + font-size: 1.15rem; + } - @include small { - font-size: 1rem; - } + @include small { + font-size: 1rem; + } } .main-content { + :first-child { + margin-top: 0; + } - :first-child { - margin-top: 0; - } - - @include large { - max-width: 68rem; - padding: 2rem 6rem; - margin: 0 auto; - font-size: 1.1rem; - } - - @include medium { - padding: 2rem 4rem; - font-size: 1.1rem; - } - - @include small { - padding: 2rem 1rem; - font-size: 1rem; - } - - img { - max-width: 100%; - } - - h1, - h2, - h3, - h4, - h5, - h6 { - margin-top: 2rem; - margin-bottom: 1rem; - font-weight: normal; - color: $heading-color; - } + @include large { + max-width: 68rem; + padding: 2rem 6rem; + margin: 0 auto; + font-size: 1.1rem; + } - p { - margin-bottom: 1rem; - } + @include medium { + padding: 2rem 4rem; + font-size: 1.1rem; + } - code { - padding: 2px 4px; - font-family: $code-font-stack; - font-size: 0.9rem; - color: #383e41; - background-color: #f3f6fa; - border-radius: 0.3rem; - } + @include small { + padding: 2rem 1rem; + font-size: 1rem; + } - pre { - padding: 0.8rem; - margin-top: 0; - margin-bottom: 1rem; - font: 1rem $code-font-stack; - color: #567482; - word-wrap: normal; - background-color: #f3f6fa; - border: solid 1px #dce6f0; - border-radius: 0.3rem; + img { + max-width: 100%; + } - > code { - padding: 0; - margin: 0; - font-size: 0.9rem; - color: #567482; - word-break: normal; - white-space: pre; - background: transparent; - border: 0; + h1, + h2, + h3, + h4, + h5, + h6 { + margin-top: 2rem; + margin-bottom: 1rem; + font-weight: normal; + color: $heading-color; } - } - .highlight { - margin-bottom: 1rem; + p { + margin-bottom: 1rem; + } + + code { + padding: 2px 4px; + font-family: $code-font-stack; + font-size: 0.9rem; + color: #383e41; + background-color: #f3f6fa; + border-radius: 0.3rem; + } pre { - margin-bottom: 0; - word-break: normal; + padding: 0.8rem; + margin-top: 0; + margin-bottom: 1rem; + font: 1rem $code-font-stack; + color: #567482; + word-wrap: normal; + background-color: #f3f6fa; + border: solid 1px #dce6f0; + border-radius: 0.3rem; + + > code { + padding: 0; + margin: 0; + font-size: 0.9rem; + color: #567482; + word-break: normal; + white-space: pre; + background: transparent; + border: 0; + } } - } - .highlight pre, - pre { - padding: 0.8rem; - overflow: auto; - font-size: 0.9rem; - line-height: 1.45; - border-radius: 0.3rem; - -webkit-overflow-scrolling: touch; - } + .highlight { + margin-bottom: 1rem; - pre code, - pre tt { - display: inline; - max-width: initial; - padding: 0; - margin: 0; - overflow: initial; - line-height: inherit; - word-wrap: normal; - background-color: transparent; - border: 0; + pre { + margin-bottom: 0; + word-break: normal; + } + } - &:before, - &:after { - content: normal; + .highlight pre, + pre { + padding: 0.8rem; + overflow: auto; + font-size: 0.9rem; + line-height: 1.45; + border-radius: 0.3rem; + -webkit-overflow-scrolling: touch; } - } - ul, - ol { - margin-top: 0; - margin-left: 30px; - margin-bottom: 1rem; + pre code, + pre tt { + display: inline; + max-width: initial; + padding: 0; + margin: 0; + overflow: initial; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0; + + &:before, + &:after { + content: normal; + } + } ul, ol { - margin-bottom: 0; + margin-top: 0; + margin-left: 30px; + margin-bottom: 1rem; + + ul, + ol { + margin-bottom: 0; + } } - } - blockquote { - padding: 0 1rem; - margin-left: 0; - color: #819198; - border-left: 0.3rem solid #dce6f0; + blockquote { + padding: 0 1rem; + margin-left: 0; + color: #819198; + border-left: 0.3rem solid #dce6f0; - > :first-child { - margin-top: 0; - } + > :first-child { + margin-top: 0; + } - > :last-child { - margin-bottom: 0; + > :last-child { + margin-bottom: 0; + } } - } - table { - display: block; - width: 100%; - overflow: auto; - word-break: normal; - word-break: keep-all; // For Firefox to horizontally scroll wider tables. - -webkit-overflow-scrolling: touch; + table { + display: block; + width: 100%; + overflow: auto; + word-break: normal; + word-break: keep-all; // For Firefox to horizontally scroll wider tables. + -webkit-overflow-scrolling: touch; - th { - font-weight: bold; - } + th { + font-weight: bold; + } - th, - td { - padding: 0.5rem 1rem; - border: 1px solid #e9ebec; + th, + td { + padding: 0.5rem 1rem; + border: 1px solid #e9ebec; + } } - } - dl { - padding: 0; + dl { + padding: 0; - dt { - padding: 0; - margin-top: 1rem; - font-size: 1rem; - font-weight: bold; - } + dt { + padding: 0; + margin-top: 1rem; + font-size: 1rem; + font-weight: bold; + } - dd { - padding: 0; - margin-bottom: 1rem; + dd { + padding: 0; + margin-bottom: 1rem; + } } - } - hr { - height: 2px; - padding: 0; - margin: 1rem 0; - background-color: #eff0f1; - border: 0; - } + hr { + height: 2px; + padding: 0; + margin: 1rem 0; + background-color: #eff0f1; + border: 0; + } } .page { - @extend %clearfix; - width: 100%; + @extend %clearfix; + width: 100%; } .page-content { - width: 80%; - padding: 1rem; - float: left; + width: 80%; + padding: 1rem; + float: left; } .page-sidebar { - width: 20%; - padding: 1rem; - float: left; + width: 20%; + padding: 1rem; + float: left; - .active { - font-style: italic; - } + .active { + font-style: italic; + } } .sidebar-title { - border-bottom: 1px solid $heading-color; + border-bottom: 1px solid $heading-color; } ul.sidebar-links { - list-style: none; - margin-left: 0; + list-style: none; + margin-left: 0; - h6 { - margin-bottom: 0.33rem; - } + h6 { + margin-bottom: 0.33rem; + } } /** * Posts */ ul.post-list { - margin-left: 0; - list-style: none; + margin-left: 0; + list-style: none; - > li { - margin-bottom: 1rem; - } + > li { + margin-bottom: 1rem; + } } .post-meta { - font-size: $small-font-size; - color: #828282; - font-style: italic; + font-size: $small-font-size; + color: #828282; + font-style: italic; } .post-link { - display: inline-block; - color: inherit; + display: inline-block; + color: inherit; } .post-header { - margin-bottom: 2rem; + margin-bottom: 2rem; } .post-title { - letter-spacing: -1px; - line-height: 1; + letter-spacing: -1px; + line-height: 1; } /** * Site footer */ .site-footer { - padding-top: 2rem; - margin-top: 2rem; - border-top: solid 1px #eff0f1; - font-size: 0.9rem; + padding-top: 2rem; + margin-top: 2rem; + border-top: solid 1px #eff0f1; + font-size: 0.9rem; } ul.contact-list, ul.social-media-list { - list-style: none; - margin-left: 0; + list-style: none; + margin-left: 0; } .footer-col-wrapper { -@extend %clearfix; + @extend %clearfix; } .footer-col { -float: left; + float: left; } .footer-col-2 { - float: right; - @include small { - float: left; - } + float: right; + @include small { + float: left; + } } diff --git a/docs/_sass/_normalize.scss b/docs/_sass/_normalize.scss index 81c6f31ea4b..46f646a5c00 100644 --- a/docs/_sass/_normalize.scss +++ b/docs/_sass/_normalize.scss @@ -7,9 +7,9 @@ */ html { - font-family: sans-serif; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ } /** @@ -17,7 +17,7 @@ html { */ body { - margin: 0; + margin: 0; } /* HTML5 display definitions @@ -43,7 +43,7 @@ menu, nav, section, summary { - display: block; + display: block; } /** @@ -55,8 +55,8 @@ audio, canvas, progress, video { - display: inline-block; /* 1 */ - vertical-align: baseline; /* 2 */ + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ } /** @@ -65,8 +65,8 @@ video { */ audio:not([controls]) { - display: none; - height: 0; + display: none; + height: 0; } /** @@ -76,7 +76,7 @@ audio:not([controls]) { [hidden], template { - display: none; + display: none; } /* Links @@ -87,7 +87,7 @@ template { */ a { - background-color: transparent; + background-color: transparent; } /** @@ -96,7 +96,7 @@ a { a:active, a:hover { - outline: 0; + outline: 0; } /* Text-level semantics @@ -107,7 +107,7 @@ a:hover { */ abbr[title] { - border-bottom: 1px dotted; + border-bottom: 1px dotted; } /** @@ -116,7 +116,7 @@ abbr[title] { b, strong { - font-weight: bold; + font-weight: bold; } /** @@ -124,7 +124,7 @@ strong { */ dfn { - font-style: italic; + font-style: italic; } /** @@ -133,8 +133,8 @@ dfn { */ h1 { - font-size: 2em; - margin: 0.67em 0; + font-size: 2em; + margin: 0.67em 0; } /** @@ -142,8 +142,8 @@ h1 { */ mark { - background: #ff0; - color: #000; + background: #ff0; + color: #000; } /** @@ -151,7 +151,7 @@ mark { */ small { - font-size: 80%; + font-size: 80%; } /** @@ -160,18 +160,18 @@ small { sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } sup { - top: -0.5em; + top: -0.5em; } sub { - bottom: -0.25em; + bottom: -0.25em; } /* Embedded content @@ -182,7 +182,7 @@ sub { */ img { - border: 0; + border: 0; } /** @@ -190,7 +190,7 @@ img { */ svg:not(:root) { - overflow: hidden; + overflow: hidden; } /* Grouping content @@ -201,7 +201,7 @@ svg:not(:root) { */ figure { - margin: 1em 40px; + margin: 1em 40px; } /** @@ -209,9 +209,9 @@ figure { */ hr { - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0; + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; } /** @@ -219,7 +219,7 @@ hr { */ pre { - overflow: auto; + overflow: auto; } /** @@ -230,8 +230,8 @@ code, kbd, pre, samp { - font-family: monospace, monospace; - font-size: 1em; + font-family: monospace, monospace; + font-size: 1em; } /* Forms @@ -254,9 +254,9 @@ input, optgroup, select, textarea { - color: inherit; /* 1 */ - font: inherit; /* 2 */ - margin: 0; /* 3 */ + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ } /** @@ -264,7 +264,7 @@ textarea { */ button { - overflow: visible; + overflow: visible; } /** @@ -276,7 +276,7 @@ button { button, select { - text-transform: none; + text-transform: none; } /** @@ -291,8 +291,8 @@ button, html input[type="button"], /* 1 */ input[type="reset"], input[type="submit"] { - -webkit-appearance: button; /* 2 */ - cursor: pointer; /* 3 */ + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ } /** @@ -301,7 +301,7 @@ input[type="submit"] { button[disabled], html input[disabled] { - cursor: default; + cursor: default; } /** @@ -310,8 +310,8 @@ html input[disabled] { button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; + border: 0; + padding: 0; } /** @@ -320,7 +320,7 @@ input::-moz-focus-inner { */ input { - line-height: normal; + line-height: normal; } /** @@ -333,8 +333,8 @@ input { input[type="checkbox"], input[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ } /** @@ -345,7 +345,7 @@ input[type="radio"] { input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { - height: auto; + height: auto; } /** @@ -355,10 +355,10 @@ input[type="number"]::-webkit-outer-spin-button { */ input[type="search"] { - -webkit-appearance: textfield; /* 1 */ - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; /* 2 */ - box-sizing: content-box; + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; } /** @@ -369,7 +369,7 @@ input[type="search"] { input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; + -webkit-appearance: none; } /** @@ -377,9 +377,9 @@ input[type="search"]::-webkit-search-decoration { */ fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; } /** @@ -388,8 +388,8 @@ fieldset { */ legend { - border: 0; /* 1 */ - padding: 0; /* 2 */ + border: 0; /* 1 */ + padding: 0; /* 2 */ } /** @@ -397,7 +397,7 @@ legend { */ textarea { - overflow: auto; + overflow: auto; } /** @@ -406,7 +406,7 @@ textarea { */ optgroup { - font-weight: bold; + font-weight: bold; } /* Tables @@ -417,11 +417,11 @@ optgroup { */ table { - border-collapse: collapse; - border-spacing: 0; + border-collapse: collapse; + border-spacing: 0; } td, th { - padding: 0; -} \ No newline at end of file + padding: 0; +} diff --git a/docs/_sass/_syntax-highlighting.scss b/docs/_sass/_syntax-highlighting.scss index e36627da7a6..a4b69b44fa6 100644 --- a/docs/_sass/_syntax-highlighting.scss +++ b/docs/_sass/_syntax-highlighting.scss @@ -5,63 +5,196 @@ background: #fff; @extend %vertical-rhythm; - .c { color: #998; font-style: italic } // Comment - .err { color: #a61717; background-color: #e3d2d2 } // Error - .k { font-weight: bold } // Keyword - .o { font-weight: bold } // Operator - .cm { color: #998; font-style: italic } // Comment.Multiline - .cp { color: #999; font-weight: bold } // Comment.Preproc - .c1 { color: #998; font-style: italic } // Comment.Single - .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special - .gd { color: #000; background-color: #fdd } // Generic.Deleted - .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific - .ge { font-style: italic } // Generic.Emph - .gr { color: #a00 } // Generic.Error - .gh { color: #999 } // Generic.Heading - .gi { color: #000; background-color: #dfd } // Generic.Inserted - .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific - .go { color: #888 } // Generic.Output - .gp { color: #555 } // Generic.Prompt - .gs { font-weight: bold } // Generic.Strong - .gu { color: #aaa } // Generic.Subheading - .gt { color: #a00 } // Generic.Traceback - .kc { font-weight: bold } // Keyword.Constant - .kd { font-weight: bold } // Keyword.Declaration - .kp { font-weight: bold } // Keyword.Pseudo - .kr { font-weight: bold } // Keyword.Reserved - .kt { color: #458; font-weight: bold } // Keyword.Type - .m { color: #099 } // Literal.Number - .s { color: #d14 } // Literal.String - .na { color: #008080 } // Name.Attribute - .nb { color: #0086B3 } // Name.Builtin - .nc { color: #458; font-weight: bold } // Name.Class - .no { color: #008080 } // Name.Constant - .ni { color: #800080 } // Name.Entity - .ne { color: #900; font-weight: bold } // Name.Exception - .nf { color: #900; font-weight: bold } // Name.Function - .nn { color: #555 } // Name.Namespace - .nt { color: #000080 } // Name.Tag - .nv { color: #008080 } // Name.Variable - .ow { font-weight: bold } // Operator.Word - .w { color: #bbb } // Text.Whitespace - .mf { color: #099 } // Literal.Number.Float - .mh { color: #099 } // Literal.Number.Hex - .mi { color: #099 } // Literal.Number.Integer - .mo { color: #099 } // Literal.Number.Oct - .sb { color: #d14 } // Literal.String.Backtick - .sc { color: #d14 } // Literal.String.Char - .sd { color: #d14 } // Literal.String.Doc - .s2 { color: #d14 } // Literal.String.Double - .se { color: #d14 } // Literal.String.Escape - .sh { color: #d14 } // Literal.String.Heredoc - .si { color: #d14 } // Literal.String.Interpol - .sx { color: #d14 } // Literal.String.Other - .sr { color: #009926 } // Literal.String.Regex - .s1 { color: #d14 } // Literal.String.Single - .ss { color: #990073 } // Literal.String.Symbol - .bp { color: #999 } // Name.Builtin.Pseudo - .vc { color: #008080 } // Name.Variable.Class - .vg { color: #008080 } // Name.Variable.Global - .vi { color: #008080 } // Name.Variable.Instance - .il { color: #099 } // Literal.Number.Integer.Long + .c { + color: #998; + font-style: italic; + } // Comment + .err { + color: #a61717; + background-color: #e3d2d2; + } // Error + .k { + font-weight: bold; + } // Keyword + .o { + font-weight: bold; + } // Operator + .cm { + color: #998; + font-style: italic; + } // Comment.Multiline + .cp { + color: #999; + font-weight: bold; + } // Comment.Preproc + .c1 { + color: #998; + font-style: italic; + } // Comment.Single + .cs { + color: #999; + font-weight: bold; + font-style: italic; + } // Comment.Special + .gd { + color: #000; + background-color: #fdd; + } // Generic.Deleted + .gd .x { + color: #000; + background-color: #faa; + } // Generic.Deleted.Specific + .ge { + font-style: italic; + } // Generic.Emph + .gr { + color: #a00; + } // Generic.Error + .gh { + color: #999; + } // Generic.Heading + .gi { + color: #000; + background-color: #dfd; + } // Generic.Inserted + .gi .x { + color: #000; + background-color: #afa; + } // Generic.Inserted.Specific + .go { + color: #888; + } // Generic.Output + .gp { + color: #555; + } // Generic.Prompt + .gs { + font-weight: bold; + } // Generic.Strong + .gu { + color: #aaa; + } // Generic.Subheading + .gt { + color: #a00; + } // Generic.Traceback + .kc { + font-weight: bold; + } // Keyword.Constant + .kd { + font-weight: bold; + } // Keyword.Declaration + .kp { + font-weight: bold; + } // Keyword.Pseudo + .kr { + font-weight: bold; + } // Keyword.Reserved + .kt { + color: #458; + font-weight: bold; + } // Keyword.Type + .m { + color: #099; + } // Literal.Number + .s { + color: #d14; + } // Literal.String + .na { + color: #008080; + } // Name.Attribute + .nb { + color: #0086b3; + } // Name.Builtin + .nc { + color: #458; + font-weight: bold; + } // Name.Class + .no { + color: #008080; + } // Name.Constant + .ni { + color: #800080; + } // Name.Entity + .ne { + color: #900; + font-weight: bold; + } // Name.Exception + .nf { + color: #900; + font-weight: bold; + } // Name.Function + .nn { + color: #555; + } // Name.Namespace + .nt { + color: #000080; + } // Name.Tag + .nv { + color: #008080; + } // Name.Variable + .ow { + font-weight: bold; + } // Operator.Word + .w { + color: #bbb; + } // Text.Whitespace + .mf { + color: #099; + } // Literal.Number.Float + .mh { + color: #099; + } // Literal.Number.Hex + .mi { + color: #099; + } // Literal.Number.Integer + .mo { + color: #099; + } // Literal.Number.Oct + .sb { + color: #d14; + } // Literal.String.Backtick + .sc { + color: #d14; + } // Literal.String.Char + .sd { + color: #d14; + } // Literal.String.Doc + .s2 { + color: #d14; + } // Literal.String.Double + .se { + color: #d14; + } // Literal.String.Escape + .sh { + color: #d14; + } // Literal.String.Heredoc + .si { + color: #d14; + } // Literal.String.Interpol + .sx { + color: #d14; + } // Literal.String.Other + .sr { + color: #009926; + } // Literal.String.Regex + .s1 { + color: #d14; + } // Literal.String.Single + .ss { + color: #990073; + } // Literal.String.Symbol + .bp { + color: #999; + } // Name.Builtin.Pseudo + .vc { + color: #008080; + } // Name.Variable.Class + .vg { + color: #008080; + } // Name.Variable.Global + .vi { + color: #008080; + } // Name.Variable.Instance + .il { + color: #099; + } // Literal.Number.Integer.Long } diff --git a/docs/circle.yml b/docs/circle.yml index 1e8b5a738ae..b462a52ae1a 100644 --- a/docs/circle.yml +++ b/docs/circle.yml @@ -1,7 +1,7 @@ machine: - ruby: - # see available versions here: https://circleci.com/docs/build-image-precise/#ruby - version: 2.2.3 + ruby: + # see available versions here: https://circleci.com/docs/build-image-precise/#ruby + version: 2.2.3 test: - override: - - bundle exec jekyll build + override: + - bundle exec jekyll build diff --git a/docs/css/main.scss b/docs/css/main.scss index 50119f13693..9eaa628d3da 100755 --- a/docs/css/main.scss +++ b/docs/css/main.scss @@ -1,26 +1,15 @@ --- # Only the main Sass file needs front matter (the dashes are enough) --- -@charset "utf-8"; - - -// Our variables +@charset "utf-8"; // Our variables $font-stack: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; $code-font-stack: Consolas, "Liberation Mono", Menlo, Courier, monospace; -$base-font-size: 16px; -$small-font-size: $base-font-size * 0.875; +$base-font-size: 16px; +$small-font-size: $base-font-size * 0.875; $base-line-height: 1.5; - -$heading-color: #159957; -$text-color: #606c71; -$link-color: #1e6bb8; -$link-visited-color: #7d0ce8; - -// Import partials from `sass_dir` (defaults to `_sass`) -@import - "normalize", - "base", - "cayman", - "syntax-highlighting" -; +$heading-color: #159957; +$text-color: #606c71; +$link-color: #1e6bb8; +$link-visited-color: #7d0ce8; // Import partials from `sass_dir` (defaults to `_sass`) +@import "normalize", "base", "cayman", "syntax-highlighting"; diff --git a/docs/index.md b/docs/index.md index 77d4c2e9028..dbf75d4229b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,7 +12,7 @@ TSLint is an extensible static analysis tool that checks [TypeScript][0] code fo # Install the global CLI and its peer dependency yarn global add tslint typescript -# Navigate to to your sources folder +# Navigate to your sources folder cd path/to/project # Generate a basic configuration file diff --git a/docs/usage/configuration/index.md b/docs/usage/configuration/index.md index 94622c22a96..0aa088af90c 100644 --- a/docs/usage/configuration/index.md +++ b/docs/usage/configuration/index.md @@ -29,10 +29,11 @@ A path to a directory or an array of paths to directories of [custom rules][2]. - A boolean value may be specified instead of the above object, and is equivalent to setting no options with default severity. - Any rules specified in this block will override those configured in any base configuration being extended. - [Check out the full rules list here][3]. -* `jsRules?: any`: Same format as `rules`. These rules are applied to `.js` and `.jsx` files. +* `jsRules?: any | boolean`: Same format as `rules` or explicit `true` to copy all valid active rules from rules. These rules are applied to `.js` and `.jsx` files. * `defaultSeverity?: "error" | "warning" | "off"`: The severity level that is applied to rules in this config file as well as rules in any inherited config files which have their severity set to "default". If undefined, "error" is used as the defaultSeverity. * `linterOptions?: { exclude?: string[] }`: - `exclude: string[]`: An array of globs. Any file matching these globs will not be linted. All exclude patterns are relative to the configuration file they were specified in. + - `format: string`: Default [lint formatter][4] `tslint.json` configuration files may have JavaScript-style `// single-line` and `/* multi-line */` comments in them (even though this is technically invalid JSON). If this confuses your syntax highlighter, you may want to switch it to JavaScript format. @@ -129,6 +130,7 @@ Some commonly used custom rule packages in the TSLint community are listed in th [1]: {{site.baseurl | append: "/usage/third-party-tools"}} [2]: {{site.baseurl | append: "/develop/custom-rules"}} [3]: {{site.baseurl | append: "/rules"}} +[4]: {{site.baseurl | append: "/formatters"}} [rule-ban]: {{site.baseurl | append: "/rules/ban"}} [rule-import-blacklist]: {{site.baseurl | append: "/rules/import-blacklist"}} [rule-file-header]: {{site.baseurl | append: "/rules/file-header"}} diff --git a/package.json b/package.json index a7fa83c49c4..a3be76e9d83 100644 --- a/package.json +++ b/package.json @@ -1,91 +1,92 @@ { - "name": "tslint", - "version": "5.11.0", - "description": "An extensible static analysis linter for the TypeScript language", - "bin": { - "tslint": "./bin/tslint" - }, - "main": "./lib/index.js", - "typings": "./lib/index.d.ts", - "repository": { - "type": "git", - "url": "https://github.com/palantir/tslint.git" - }, - "keywords": [ - "cli", - "typescript", - "linter" - ], - "scripts": { - "clean": "npm-run-all -p clean:core clean:test", - "clean:core": "rimraf lib", - "clean:test": "rimraf build && rimraf test/config/node_modules", - "docs": "node scripts/buildDocs.js", - "compile": "npm-run-all -p compile:core compile:test -s compile:scripts", - "compile:core": "tsc -p src", - "compile:scripts": "tsc -p scripts", - "compile:test": "tsc -p test", - "lint": "npm-run-all -p lint:global lint:from-bin", - "lint:global": "tslint --project test/tsconfig.json --format stylish", - "lint:from-bin": "node bin/tslint --project test/tsconfig.json --format stylish", - "precommit": "npm-run-all precommit:prettier", - "precommit:prettier": "pretty-quick --staged", - "prettier": "prettier --write ./**/*.{js,ts,css,scss,json,md,yml} --ignore-path ./.prettierignore", - "publish:local": "./scripts/npmPublish.sh", - "test": "npm-run-all test:pre -p test:mocha test:rules", - "test:pre": "cd ./test/config && npm install --no-save", - "test:mocha": "mocha --reporter spec --colors \"build/test/**/*Tests.js\"", - "test:rules": "node ./build/test/ruleTestRunner.js", - "verify": "npm-run-all clean compile lint test docs", - "coverage": "rimraf coverage .nyc_output && nyc npm test" - }, - "dependencies": { - "babel-code-frame": "^6.22.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^3.2.0", - "glob": "^7.1.1", - "js-yaml": "^3.7.0", - "minimatch": "^3.0.4", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.27.2" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev" - }, - "devDependencies": { - "@types/babel-code-frame": "^6.20.0", - "@types/chai": "^3.5.0", - "@types/diff": "^3.2.0", - "@types/glob": "^5.0.30", - "@types/js-yaml": "^3.5.31", - "@types/minimatch": "^2.0.29", - "@types/mocha": "^2.2.35", - "@types/node": "^7.0.29", - "@types/resolve": "^0.0.4", - "@types/rimraf": "^2.0.2", - "@types/semver": "^5.3.30", - "chai": "^3.5.0", - "github": "^8.2.1", - "husky": "^0.14.3", - "json-stringify-pretty-compact": "^1.0.3", - "mocha": "^3.2.0", - "npm-run-all": "^4.0.2", - "nyc": "^10.2.0", - "prettier": "1.13.7", - "pretty-quick": "^1.6.0", - "rimraf": "^2.5.4", - "ts-node": "^3.3.0", - "tslint": "^5.8.0", - "tslint-config-prettier": "^1.13.0", - "tslint-test-config-non-relative": "file:test/external/tslint-test-config-non-relative", - "typescript": "~2.9.2" - }, - "license": "Apache-2.0", - "engines": { - "node": ">=4.8.0" - } + "name": "tslint", + "version": "5.11.0", + "description": "An extensible static analysis linter for the TypeScript language", + "bin": { + "tslint": "./bin/tslint" + }, + "main": "./lib/index.js", + "typings": "./lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/palantir/tslint.git" + }, + "keywords": [ + "cli", + "typescript", + "linter" + ], + "homepage": "https://palantir.github.io/tslint", + "scripts": { + "clean": "npm-run-all -p clean:core clean:test", + "clean:core": "rimraf lib", + "clean:test": "rimraf build && rimraf test/config/node_modules", + "docs": "node scripts/buildDocs.js", + "compile": "npm-run-all -p compile:core compile:test -s compile:scripts", + "compile:core": "tsc -p src", + "compile:scripts": "tsc -p scripts", + "compile:test": "tsc -p test", + "lint": "npm-run-all -p lint:global lint:from-bin", + "lint:global": "tslint --project test/tsconfig.json --format stylish", + "lint:from-bin": "node bin/tslint --project test/tsconfig.json --format stylish", + "precommit": "npm-run-all precommit:prettier", + "precommit:prettier": "pretty-quick --staged", + "prettier": "prettier --write ./**/*.{js,ts,css,scss,json,md,yml} --ignore-path ./.prettierignore", + "publish:local": "./scripts/npmPublish.sh", + "test": "npm-run-all test:pre -p test:mocha test:rules", + "test:pre": "cd ./test/config && npm install --no-save", + "test:mocha": "mocha --reporter spec --colors \"build/test/**/*Tests.js\"", + "test:rules": "node ./build/test/ruleTestRunner.js", + "verify": "npm-run-all clean compile lint test docs", + "coverage": "rimraf coverage .nyc_output && nyc npm test" + }, + "dependencies": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.27.2" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev" + }, + "devDependencies": { + "@types/babel-code-frame": "^6.20.0", + "@types/chai": "^3.5.0", + "@types/diff": "^3.2.0", + "@types/glob": "^5.0.30", + "@types/js-yaml": "^3.5.31", + "@types/minimatch": "^2.0.29", + "@types/mocha": "^2.2.35", + "@types/node": "^7.0.29", + "@types/resolve": "^0.0.4", + "@types/rimraf": "^2.0.2", + "@types/semver": "^5.3.30", + "chai": "^3.5.0", + "github": "^8.2.1", + "husky": "^0.14.3", + "json-stringify-pretty-compact": "^1.0.3", + "mocha": "^3.2.0", + "npm-run-all": "^4.0.2", + "nyc": "^10.2.0", + "prettier": "1.14.3", + "pretty-quick": "^1.6.0", + "rimraf": "^2.5.4", + "ts-node": "^3.3.0", + "tslint": "^5.8.0", + "tslint-config-prettier": "^1.13.0", + "tslint-test-config-non-relative": "file:test/external/tslint-test-config-non-relative", + "typescript": "~2.9.2" + }, + "license": "Apache-2.0", + "engines": { + "node": ">=4.8.0" + } } diff --git a/scripts/buildDocs.ts b/scripts/buildDocs.ts index 4f70d71cb32..d944a01b05b 100644 --- a/scripts/buildDocs.ts +++ b/scripts/buildDocs.ts @@ -114,7 +114,8 @@ function buildDocumentation(documentation: IDocumentation) { // Create each module's documentation file. const modulePaths = glob.sync(documentation.globPattern); const metadataJson = modulePaths.map((modulePath: string) => - buildSingleModuleDocumentation(documentation, modulePath)); + buildSingleModuleDocumentation(documentation, modulePath), + ); // Delete outdated directories const rulesDirs = metadataJson.map((metadata: any) => metadata[documentation.nameMetadataKey]); @@ -133,17 +134,21 @@ function deleteOutdatedDocumentation(directory: string, rulesDirs: string[]) { // find if the thing at particular location is a directory const isDirectory = (source: string) => fs.lstatSync(source).isDirectory(); // get all subdirectories in source directory - const getDirectories = (source: string) => fs.readdirSync(source).filter((name) => isDirectory(path.join(source, name))); + const getDirectories = (source: string) => + fs.readdirSync(source).filter(name => isDirectory(path.join(source, name))); const subDirs = getDirectories(directory); - const outdatedDirs = subDirs.filter((dir) => rulesDirs.indexOf(dir) < 0); - outdatedDirs.forEach((outdatedDir) => rimraf.sync(path.join(directory, outdatedDir))); + const outdatedDirs = subDirs.filter(dir => rulesDirs.indexOf(dir) < 0); + outdatedDirs.forEach(outdatedDir => rimraf.sync(path.join(directory, outdatedDir))); } /** * Produces documentation for a single file/module. */ -function buildSingleModuleDocumentation(documentation: IDocumentation, modulePath: string): Metadata { +function buildSingleModuleDocumentation( + documentation: IDocumentation, + modulePath: string, +): Metadata { // Load the module. // tslint:disable-next-line:no-var-requires const module = require(modulePath); @@ -191,8 +196,9 @@ function generateJekyllData(metadata: any, layout: string, type: string, name: s function generateRuleFile(metadata: IRuleMetadata): string { if (metadata.optionExamples) { metadata = { ...metadata }; - metadata.optionExamples = (metadata.optionExamples as any[]).map((example) => - typeof example === "string" ? example : stringify(example)); + metadata.optionExamples = (metadata.optionExamples as any[]).map( + example => (typeof example === "string" ? example : stringify(example)), + ); } if (metadata.codeExamples) { @@ -208,7 +214,7 @@ function generateRuleFile(metadata: IRuleMetadata): string { const yamlData = generateJekyllData(metadata, "rule", "Rule", metadata.ruleName); yamlData.optionsJSON = JSON.stringify(metadata.options, undefined, 2); - return `---\n${yaml.safeDump(yamlData, {lineWidth: 140} as any)}---`; + return `---\n${yaml.safeDump(yamlData, { lineWidth: 140 } as any)}---`; } /** @@ -216,8 +222,13 @@ function generateRuleFile(metadata: IRuleMetadata): string { * that only consists of a YAML front matter block. */ function generateFormatterFile(metadata: IFormatterMetadata): string { - const yamlData = generateJekyllData(metadata, "formatter", "TSLint formatter", metadata.formatterName); - return `---\n${yaml.safeDump(yamlData, {lineWidth: 140} as any)}---`; + const yamlData = generateJekyllData( + metadata, + "formatter", + "TSLint formatter", + metadata.formatterName, + ); + return `---\n${yaml.safeDump(yamlData, { lineWidth: 140 } as any)}---`; } buildDocumentation(ruleDocumentation); diff --git a/scripts/generate-changelog.ts b/scripts/generate-changelog.ts index 2019de0f8bd..3c816b70596 100644 --- a/scripts/generate-changelog.ts +++ b/scripts/generate-changelog.ts @@ -45,7 +45,10 @@ const tokenFile = path.join(os.homedir(), "github_token.txt"); // authenticate const auth: GitHubApi.Auth = { - token: fs.readFileSync(tokenFile, "utf8").toString().trim(), + token: fs + .readFileSync(tokenFile, "utf8") + .toString() + .trim(), type: "oauth", }; console.log("Using OAuth token " + auth.token + "\n"); @@ -54,90 +57,101 @@ console.log("Using OAuth token " + auth.token + "\n"); github.authenticate(auth); const commits: ICommit[] = []; -github.repos.getLatestRelease(repoInfo).then((value) => { - console.log("Getting commits " + value.tag_name + "..master"); - // get the commits between the most recent release and the head of master - return github.repos.compareCommits({ - base: value.tag_name, - head: "master", - ...repoInfo, - }); -}).then((value) => { - // for each commit, get the PR, and extract changelog entries - const promises: Array> = []; - for (const commitInfo of value.commits) { - const commit: ICommit = { - fields: [], - sha: commitInfo.sha, - submitter: commitInfo.commit.author.name != null ? commitInfo.commit.author.name : commitInfo.author.login, - title: commitInfo.commit.message, - }; - commits.push(commit); - - // check for a pull request number in the commit title - const match = (commitInfo.commit.message as string).match(/\(#(\d+)\)/); - if (match && match.length > 1) { - commit.pushRequestNum = Number.parseInt(match[1], 10); - - // get the PR text - promises.push(github.issues.get({ - number: commit.pushRequestNum, - ...repoInfo, - }).then((comment) => { - // extract the changelog entries - const lines = (comment.body as string).split("\r\n"); - for (const line of lines) { - const fieldMatch = line.match(/^(\[[a-z\-]+\])/); - if (fieldMatch) { - commit.fields.push({ - tag: fieldMatch[1], - text: addLinks(line) + " (#" + commit.pushRequestNum + ")", - }); - } - } - })); +github.repos + .getLatestRelease(repoInfo) + .then(value => { + console.log("Getting commits " + value.tag_name + "..master"); + // get the commits between the most recent release and the head of master + return github.repos.compareCommits({ + base: value.tag_name, + head: "master", + ...repoInfo, + }); + }) + .then(value => { + // for each commit, get the PR, and extract changelog entries + const promises: Array> = []; + for (const commitInfo of value.commits) { + const commit: ICommit = { + fields: [], + sha: commitInfo.sha, + submitter: + commitInfo.commit.author.name != null + ? commitInfo.commit.author.name + : commitInfo.author.login, + title: commitInfo.commit.message, + }; + commits.push(commit); + + // check for a pull request number in the commit title + const match = (commitInfo.commit.message as string).match(/\(#(\d+)\)/); + if (match && match.length > 1) { + commit.pushRequestNum = Number.parseInt(match[1], 10); + + // get the PR text + promises.push( + github.issues + .get({ + number: commit.pushRequestNum, + ...repoInfo, + }) + .then(comment => { + // extract the changelog entries + const lines = (comment.body as string).split("\r\n"); + for (const line of lines) { + const fieldMatch = line.match(/^(\[[a-z\-]+\])/); + if (fieldMatch) { + commit.fields.push({ + tag: fieldMatch[1], + text: addLinks(line) + " (#" + commit.pushRequestNum + ")", + }); + } + } + }), + ); + } } - - } - return Promise.all(promises); -}).then(() => { - const entries: IField[] = []; - const noFields: string[] = []; - const contributors = new Set(); - for (const commit of commits) { - if (commit.fields.length > 0) { - for (const field of commit.fields) { - if (field.tag !== "[no-log]") { - entries.push(field); + return Promise.all(promises); + }) + .then(() => { + const entries: IField[] = []; + const noFields: string[] = []; + const contributors = new Set(); + for (const commit of commits) { + if (commit.fields.length > 0) { + for (const field of commit.fields) { + if (field.tag !== "[no-log]") { + entries.push(field); + } } + } else { + noFields.push(commit.title); } - } else { - noFields.push(commit.title); + contributors.add(commit.submitter); } - contributors.add(commit.submitter); - } - entries.sort((a, b) => { - return a.tag.localeCompare(b.tag); - }); + entries.sort((a, b) => { + return a.tag.localeCompare(b.tag); + }); - console.log("\n---- formatted changelog entries: ----"); - for (const entry of entries) { - console.log("- " + entry.text); - } + console.log("\n---- formatted changelog entries: ----"); + for (const entry of entries) { + console.log("- " + entry.text); + } - console.log("\n---- PRs with missing changelog entries: ----"); - for (const missing of noFields) { - console.log("- " + missing.replace(/[\r\n]+/, "\r\n ")); - } + console.log("\n---- PRs with missing changelog entries: ----"); + for (const missing of noFields) { + console.log("- " + missing.replace(/[\r\n]+/, "\r\n ")); + } - console.log("\n---- thanks ----"); - console.log("Thanks to our contributors!"); - contributors.forEach((contributor) => { - console.log("- " + contributor); + console.log("\n---- thanks ----"); + console.log("Thanks to our contributors!"); + contributors.forEach(contributor => { + console.log("- " + contributor); + }); + }) + .catch(error => { + console.log("Error:" + error); }); -}).catch((error) => { - console.log("Error:" + error); -}); const cache = new Map(); @@ -159,7 +173,9 @@ function addLinks(text: string): string { let match = regex.exec(text); while (match !== null) { if (isRule(match[1])) { - result += text.slice(lastIndex, match.index) + `[${match[0]}](https://palantir.github.io/tslint/rules/${match[1]}/)`; + result += + text.slice(lastIndex, match.index) + + `[${match[0]}](https://palantir.github.io/tslint/rules/${match[1]}/)`; lastIndex = regex.lastIndex; } match = regex.exec(text); diff --git a/src/configs/all.ts b/src/configs/all.ts index fd3093b697a..c408f18a666 100644 --- a/src/configs/all.ts +++ b/src/configs/all.ts @@ -36,6 +36,7 @@ export const rules = { ["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"], ], }, + "ban-ts-ignore": true, "member-access": [true, "check-accessor", "check-constructor", "check-parameter-property"], "member-ordering": [true, { "order": "statics-first", @@ -129,7 +130,7 @@ export const rules = { "no-unsafe-any": true, "no-unsafe-finally": true, "no-unused-expression": true, - "no-unused-variable": true, + // "no-unused-variable" - deprecated in #3919 "no-use-before-declare": true, "no-var-keyword": true, "no-void-expression": true, @@ -195,6 +196,7 @@ export const rules = { "encoding": true, "file-name-casing": [true, "camel-case"], "import-spacing": true, + "increment-decrement": true, "interface-name": true, "interface-over-type-literal": true, "jsdoc-format": [true, "check-multiline-start"], @@ -275,7 +277,7 @@ export const rules = { }; export const RULES_EXCLUDED_FROM_ALL_CONFIG = - ["ban", "fileHeader", "importBlacklist", "noInvalidThis", "noSwitchCaseFallThrough", "typeofCompare"]; + ["ban", "fileHeader", "importBlacklist", "noInvalidThis", "noSwitchCaseFallThrough", "typeofCompare", "noUnusedVariable"]; // Exclude typescript-only rules from jsRules, otherwise it's identical. export const jsRules: { [key: string]: any } = {}; diff --git a/src/configuration.ts b/src/configuration.ts index 6de1dd575a6..eec8256b92d 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -17,12 +17,14 @@ import * as fs from "fs"; import * as yaml from "js-yaml"; +import { Minimatch } from "minimatch"; import * as os from "os"; import * as path from "path"; import * as resolve from "resolve"; import { FatalError, showWarningOnce } from "./error"; import { IOptions, RuleSeverity } from "./language/rule/rule"; +import { findRule } from "./ruleLoader"; import { arrayify, hasOwnProperty, stripComments } from "./utils"; export interface IConfigurationFile { @@ -50,6 +52,7 @@ export interface IConfigurationFile { */ linterOptions?: Partial<{ exclude: string[]; + format: string; }>; /** @@ -100,9 +103,18 @@ const BUILT_IN_CONFIG = /^tslint:(.*)$/; * of the search for a configuration. * @returns Load status for a TSLint configuration object */ -export function findConfiguration(configFile: string | null, inputFilePath: string): IConfigurationLoadResult; -export function findConfiguration(configFile: string, inputFilePath?: string): IConfigurationLoadResult; -export function findConfiguration(configFile: string | null, inputFilePath?: string): IConfigurationLoadResult { +export function findConfiguration( + configFile: string | null, + inputFilePath: string, +): IConfigurationLoadResult; +export function findConfiguration( + configFile: string, + inputFilePath?: string, +): IConfigurationLoadResult; +export function findConfiguration( + configFile: string | null, + inputFilePath?: string, +): IConfigurationLoadResult { const configPath = findConfigurationPath(configFile, inputFilePath!); const loadResult: IConfigurationLoadResult = { path: configPath }; @@ -110,7 +122,10 @@ export function findConfiguration(configFile: string | null, inputFilePath?: str loadResult.results = loadConfigurationFromPath(configPath); return loadResult; } catch (error) { - throw new FatalError(`Failed to load ${configPath}: ${(error as Error).message}`, error as Error); + throw new FatalError( + `Failed to load ${configPath}: ${(error as Error).message}`, + error as Error, + ); } } @@ -124,12 +139,23 @@ export function findConfiguration(configFile: string | null, inputFilePath?: str * @returns An absolute path to a tslint.json or tslint.yml or tslint.yaml file * or undefined if neither can be found. */ -export function findConfigurationPath(suppliedConfigFilePath: string | null, inputFilePath: string): string | undefined; -export function findConfigurationPath(suppliedConfigFilePath: string, inputFilePath?: string): string | undefined; -export function findConfigurationPath(suppliedConfigFilePath: string | null, inputFilePath?: string): string | undefined { +export function findConfigurationPath( + suppliedConfigFilePath: string | null, + inputFilePath: string, +): string | undefined; +export function findConfigurationPath( + suppliedConfigFilePath: string, + inputFilePath?: string, +): string | undefined; +export function findConfigurationPath( + suppliedConfigFilePath: string | null, + inputFilePath?: string, +): string | undefined { if (suppliedConfigFilePath != undefined) { if (!fs.existsSync(suppliedConfigFilePath)) { - throw new FatalError(`Could not find config file at: ${path.resolve(suppliedConfigFilePath)}`); + throw new FatalError( + `Could not find config file at: ${path.resolve(suppliedConfigFilePath)}`, + ); } else { return path.resolve(suppliedConfigFilePath); } @@ -196,9 +222,11 @@ function findup(filenames: string[], directory: string): string | undefined { } // TODO: remove in v6.0.0 // Try reading in the entire directory and looking for a file with different casing. - const result = dirFiles.find((entry) => entry.toLowerCase() === filename); + const result = dirFiles.find(entry => entry.toLowerCase() === filename); if (result !== undefined) { - showWarningOnce(`Using mixed case ${filename} is deprecated. Found: ${path.join(cwd, result)}`); + showWarningOnce( + `Using mixed case ${filename} is deprecated. Found: ${path.join(cwd, result)}`, + ); return result; } } @@ -217,14 +245,17 @@ function findup(filenames: string[], directory: string): string | undefined { * @returns a configuration object for TSLint loaded from the file at configFilePath */ export function loadConfigurationFromPath(configFilePath?: string, _originalFilePath?: string) { - if (configFilePath == undefined) { return DEFAULT_CONFIG; } else { const resolvedConfigFilePath = resolveConfigurationPath(configFilePath); const rawConfigFile = readConfigurationFile(resolvedConfigFilePath); - return parseConfigFile(rawConfigFile, path.dirname(resolvedConfigFilePath), readConfigurationFile); + return parseConfigFile( + rawConfigFile, + path.dirname(resolvedConfigFilePath), + readConfigurationFile, + ); } } @@ -270,7 +301,9 @@ function resolveConfigurationPath(filePath: string, relativeTo?: string) { try { return require.resolve(`./configs/${configName}`); } catch (err) { - throw new Error(`${filePath} is not a built-in config, try "tslint:recommended" instead.`); + throw new Error( + `${filePath} is not a built-in config, try "tslint:recommended" instead.`, + ); } } @@ -281,16 +314,19 @@ function resolveConfigurationPath(filePath: string, relativeTo?: string) { try { return require.resolve(filePath); } catch (err) { - throw new Error(`Invalid "extends" configuration value - could not require "${filePath}". ` + - "Review the Node lookup algorithm (https://nodejs.org/api/modules.html#modules_all_together) " + - "for the approximate method TSLint uses to find the referenced configuration file."); + throw new Error( + `Invalid "extends" configuration value - could not require "${filePath}". ` + + "Review the Node lookup algorithm (https://nodejs.org/api/modules.html#modules_all_together) " + + "for the approximate method TSLint uses to find the referenced configuration file.", + ); } } } -export function extendConfigurationFile(targetConfig: IConfigurationFile, - nextConfigSource: IConfigurationFile): IConfigurationFile { - +export function extendConfigurationFile( + targetConfig: IConfigurationFile, + nextConfigSource: IConfigurationFile, +): IConfigurationFile { function combineProperties(targetProperty: T | undefined, nextProperty: T | undefined): T { const combinedProperty: { [key: string]: any } = {}; add(targetProperty); @@ -309,7 +345,10 @@ export function extendConfigurationFile(targetConfig: IConfigurationFile, } } - function combineMaps(target: Map>, next: Map>) { + function combineMaps( + target: Map>, + next: Map>, + ) { const combined = new Map>(); target.forEach((options, ruleName) => { combined.set(ruleName, options); @@ -331,7 +370,10 @@ export function extendConfigurationFile(targetConfig: IConfigurationFile, return { extends: [], jsRules: combineMaps(targetConfig.jsRules, nextConfigSource.jsRules), - linterOptions: combineProperties(targetConfig.linterOptions, nextConfigSource.linterOptions), + linterOptions: combineProperties( + targetConfig.linterOptions, + nextConfigSource.linterOptions, + ), rules: combineMaps(targetConfig.rules, nextConfigSource.rules), rulesDirectory: dedupedRulesDirs, }; @@ -363,25 +405,28 @@ export function useAsPath(directory: string) { * should be the path to the tslint.json file. * @return An array of absolute paths to directories potentially containing rules */ -export function getRulesDirectories(directories?: string | string[], relativeTo?: string): string[] { - return arrayify(directories) - .map((dir) => { - if (!useAsPath(dir)) { - try { - return path.dirname(resolve.sync(dir, { basedir: relativeTo })); - } catch (err) { - // swallow error and fallback to using directory as path - } +export function getRulesDirectories( + directories?: string | string[], + relativeTo?: string, +): string[] { + return arrayify(directories).map(dir => { + if (!useAsPath(dir)) { + try { + return path.dirname(resolve.sync(dir, { basedir: relativeTo })); + } catch (err) { + // swallow error and fallback to using directory as path } + } - const absolutePath = relativeTo === undefined ? path.resolve(dir) : path.resolve(relativeTo, dir); - if (absolutePath !== undefined) { - if (!fs.existsSync(absolutePath)) { - throw new FatalError(`Could not find custom rule directory: ${dir}`); - } + const absolutePath = + relativeTo === undefined ? path.resolve(dir) : path.resolve(relativeTo, dir); + if (absolutePath !== undefined) { + if (!fs.existsSync(absolutePath)) { + throw new FatalError(`Could not find custom rule directory: ${dir}`); } - return absolutePath; - }); + } + return absolutePath; + }); } /** @@ -389,7 +434,10 @@ export function getRulesDirectories(directories?: string | string[], relativeTo? * * @param ruleConfigValue The raw option setting of a rule */ -function parseRuleOptions(ruleConfigValue: RawRuleConfig, rawDefaultRuleSeverity: string | undefined): Partial { +function parseRuleOptions( + ruleConfigValue: RawRuleConfig, + rawDefaultRuleSeverity: string | undefined, +): Partial { let ruleArguments: any[] | undefined; let defaultRuleSeverity: RuleSeverity = "error"; @@ -462,15 +510,20 @@ export interface RawConfigFile { rulesDirectory?: string | string[]; defaultSeverity?: string; rules?: RawRulesConfig; - jsRules?: RawRulesConfig; + jsRules?: RawRulesConfig | boolean; } export interface RawRulesConfig { [key: string]: RawRuleConfig; } -export type RawRuleConfig = null | undefined | boolean | any[] | { - severity?: RuleSeverity | "warn" | "none" | "default"; - options?: any; -}; +export type RawRuleConfig = + | null + | undefined + | boolean + | any[] + | { + severity?: RuleSeverity | "warn" | "none" | "default"; + options?: any; + }; /** * Parses a config file and normalizes legacy config settings. @@ -491,12 +544,12 @@ export function parseConfigFile( } return loadExtendsRecursive(configFile, configFileDir) - .map(({dir, config}) => parse(config, dir)) + .map(({ dir, config }) => parse(config, dir)) .reduce(extendConfigurationFile, EMPTY_CONFIG); /** Read files in order, depth first, and assign `defaultSeverity` (last config in extends wins). */ function loadExtendsRecursive(raw: RawConfigFile, dir: string) { - const configs: Array<{dir: string; config: RawConfigFile}> = []; + const configs: Array<{ dir: string; config: RawConfigFile }> = []; for (const relativePath of arrayify(raw.extends)) { const resolvedPath = resolveConfigurationPath(relativePath, dir); const extendedRaw = readConfig!(resolvedPath); @@ -505,17 +558,24 @@ export function parseConfigFile( if (raw.defaultSeverity !== undefined) { defaultSeverity = raw.defaultSeverity; } - configs.push({dir, config: raw}); + configs.push({ dir, config: raw }); return configs; } function parse(config: RawConfigFile, dir?: string): IConfigurationFile { + const rulesDirectory: string | string[] = getRulesDirectories(config.rulesDirectory, dir); + const rules = parseRules(config.rules); + const jsRules = + typeof config.jsRules === "boolean" + ? filterValidJsRules(rules, config.jsRules, rulesDirectory) + : parseRules(config.jsRules); + return { extends: arrayify(config.extends), - jsRules: parseRules(config.jsRules), + jsRules, linterOptions: parseLinterOptions(config.linterOptions, dir), - rules: parseRules(config.rules), - rulesDirectory: getRulesDirectories(config.rulesDirectory, dir), + rules, + rulesDirectory, }; } @@ -531,14 +591,52 @@ export function parseConfigFile( return map; } - function parseLinterOptions(raw: RawConfigFile["linterOptions"], dir?: string): IConfigurationFile["linterOptions"] { - if (raw === undefined || raw.exclude === undefined) { + function filterValidJsRules( + rules: Map>, + copyRulestoJsRules = false, + rulesDirectory?: string | string[], + ): Map> { + const validJsRules = new Map>(); + if (copyRulestoJsRules) { + rules.forEach((ruleOptions, ruleName) => { + if (ruleOptions.ruleSeverity !== "off") { + const Rule = findRule(ruleName, rulesDirectory); + if ( + Rule !== undefined && + (Rule.metadata === undefined || !Rule.metadata.typescriptOnly) + ) { + validJsRules.set(ruleName, ruleOptions); + } + } + }); + } + + return validJsRules; + } + + function parseLinterOptions( + raw: RawConfigFile["linterOptions"], + dir?: string, + ): IConfigurationFile["linterOptions"] { + if (raw === undefined) { return {}; } return { - exclude: arrayify(raw.exclude).map( - (pattern) => dir === undefined ? path.resolve(pattern) : path.resolve(dir, pattern), - ), + ...(raw.exclude !== undefined + ? { + exclude: arrayify(raw.exclude).map( + pattern => + dir === undefined + ? path.resolve(pattern) + : path.resolve(dir, pattern), + ), + } + : {}), + ...(raw.format !== undefined + ? { + format: raw.format, + } + : {}), }; } } @@ -559,3 +657,15 @@ export function convertRuleOptions(ruleConfiguration: Map new Minimatch(pattern).match(fullPath)); +} diff --git a/src/enableDisableRules.ts b/src/enableDisableRules.ts index 2c6091c6bc7..7b30ca2ae66 100644 --- a/src/enableDisableRules.ts +++ b/src/enableDisableRules.ts @@ -30,21 +30,27 @@ import { RuleFailure } from "./language/rule/rule"; */ export const ENABLE_DISABLE_REGEX = /^\s*tslint:(enable|disable)(?:-(line|next-line))?(:|\s|$)/; -export function removeDisabledFailures(sourceFile: ts.SourceFile, failures: RuleFailure[]): RuleFailure[] { +export function removeDisabledFailures( + sourceFile: ts.SourceFile, + failures: RuleFailure[], +): RuleFailure[] { if (failures.length === 0) { // Usually there won't be failures anyway, so no need to look for "tslint:disable". return failures; } - const failingRules = new Set(failures.map((f) => f.getRuleName())); + const failingRules = new Set(failures.map(f => f.getRuleName())); const map = getDisableMap(sourceFile, failingRules); - return failures.filter((failure) => { + return failures.filter(failure => { const disabledIntervals = map.get(failure.getRuleName()); - return disabledIntervals === undefined || !disabledIntervals.some(({ pos, end }) => { - const failPos = failure.getStartPosition().getPosition(); - const failEnd = failure.getEndPosition().getPosition(); - return failEnd >= pos && (end === -1 || failPos < end); - }); + return ( + disabledIntervals === undefined || + !disabledIntervals.some(({ pos, end }) => { + const failPos = failure.getStartPosition().getPosition(); + const failEnd = failure.getEndPosition().getPosition(); + return failEnd >= pos && (end === -1 || failPos < end); + }) + ); }); } @@ -52,19 +58,26 @@ export function removeDisabledFailures(sourceFile: ts.SourceFile, failures: Rule * The map will have an array of TextRange for each disable of a rule in a file. * (It will have no entry if the rule is never disabled, meaning all arrays are non-empty.) */ -function getDisableMap(sourceFile: ts.SourceFile, failingRules: Set): ReadonlyMap { +function getDisableMap( + sourceFile: ts.SourceFile, + failingRules: Set, +): ReadonlyMap { const map = new Map(); utils.forEachComment(sourceFile, (fullText, comment) => { - const commentText = comment.kind === ts.SyntaxKind.SingleLineCommentTrivia - ? fullText.substring(comment.pos + 2, comment.end) - : fullText.substring(comment.pos + 2, comment.end - 2); + const commentText = + comment.kind === ts.SyntaxKind.SingleLineCommentTrivia + ? fullText.substring(comment.pos + 2, comment.end) + : fullText.substring(comment.pos + 2, comment.end - 2); const parsed = parseComment(commentText); if (parsed !== undefined) { const { rulesList, isEnabled, modifier } = parsed; const switchRange = getSwitchRange(modifier, comment, sourceFile); if (switchRange !== undefined) { - const rulesToSwitch = rulesList === "all" ? Array.from(failingRules) : rulesList.filter((r) => failingRules.has(r)); + const rulesToSwitch = + rulesList === "all" + ? Array.from(failingRules) + : rulesList.filter(r => failingRules.has(r)); for (const ruleToSwitch of rulesToSwitch) { switchRuleState(ruleToSwitch, isEnabled, switchRange.pos, switchRange.end); } @@ -74,7 +87,12 @@ function getDisableMap(sourceFile: ts.SourceFile, failingRules: Set): Re return map; - function switchRuleState(ruleName: string, isEnable: boolean, start: number, end: number): void { + function switchRuleState( + ruleName: string, + isEnable: boolean, + start: number, + end: number, + ): void { const disableRanges = map.get(ruleName); if (isEnable) { @@ -88,7 +106,8 @@ function getDisableMap(sourceFile: ts.SourceFile, failingRules: Set): Re } } } - } else { // disable + } else { + // disable if (disableRanges === undefined) { map.set(ruleName, [{ pos: start, end }]); } else if (disableRanges[disableRanges.length - 1].end !== -1) { @@ -99,7 +118,11 @@ function getDisableMap(sourceFile: ts.SourceFile, failingRules: Set): Re } /** End will be -1 to indicate no end. */ -function getSwitchRange(modifier: Modifier, range: ts.TextRange, sourceFile: ts.SourceFile): ts.TextRange | undefined { +function getSwitchRange( + modifier: Modifier, + range: ts.TextRange, + sourceFile: ts.SourceFile, +): ts.TextRange | undefined { const lineStarts = sourceFile.getLineStarts(); switch (modifier) { @@ -133,7 +156,9 @@ function getSwitchRange(modifier: Modifier, range: ts.TextRange, sourceFile: ts. } type Modifier = "line" | "next-line" | undefined; -function parseComment(commentText: string): { rulesList: string[] | "all"; isEnabled: boolean; modifier: Modifier } | undefined { +function parseComment( + commentText: string, +): { rulesList: string[] | "all"; isEnabled: boolean; modifier: Modifier } | undefined { const match = ENABLE_DISABLE_REGEX.exec(commentText); if (match === null) { return undefined; @@ -147,8 +172,7 @@ function parseComment(commentText: string): { rulesList: string[] | "all"; isEna // nothing to do here: an explicit separator was specified but no rules to switch return undefined; } - if (rulesList.length === 0 || - rulesList.indexOf("all") !== -1) { + if (rulesList.length === 0 || rulesList.indexOf("all") !== -1) { // if list is empty we default to all enabled rules // if `all` is specified we ignore the other rules and take all enabled rules rulesList = "all"; @@ -158,5 +182,5 @@ function parseComment(commentText: string): { rulesList: string[] | "all"; isEna } function splitOnSpaces(str: string): string[] { - return str.split(/\s+/).filter((s) => s !== ""); + return str.split(/\s+/).filter(s => s !== ""); } diff --git a/src/formatterLoader.ts b/src/formatterLoader.ts index 635d0507fcc..c6aa24a3bcd 100644 --- a/src/formatterLoader.ts +++ b/src/formatterLoader.ts @@ -23,7 +23,10 @@ import { camelize } from "./utils"; const CORE_FORMATTERS_DIRECTORY = path.resolve(__dirname, "formatters"); -export function findFormatter(name: string | FormatterConstructor, formattersDirectory?: string): FormatterConstructor | undefined { +export function findFormatter( + name: string | FormatterConstructor, + formattersDirectory?: string, +): FormatterConstructor | undefined { if (typeof name === "function") { return name; } else if (typeof name === "string") { @@ -52,7 +55,11 @@ export function findFormatter(name: string | FormatterConstructor, formattersDir } } -function loadFormatter(directory: string, name: string, isCore?: boolean): FormatterConstructor | undefined { +function loadFormatter( + directory: string, + name: string, + isCore?: boolean, +): FormatterConstructor | undefined { const formatterPath = path.resolve(path.join(directory, name)); let fullPath: string; if (isCore) { @@ -75,7 +82,7 @@ function loadFormatterModule(name: string): FormatterConstructor | undefined { let src: string; try { // first try to find a module in the dependencies of the currently linted project - src = resolve.sync(name, {basedir: process.cwd()}); + src = resolve.sync(name, { basedir: process.cwd() }); } catch { try { // if there is no local module, try relative to the installation of TSLint (might be global) diff --git a/src/formatters/proseFormatter.ts b/src/formatters/proseFormatter.ts index 6a66289919d..ec54d20f8fa 100644 --- a/src/formatters/proseFormatter.ts +++ b/src/formatters/proseFormatter.ts @@ -46,7 +46,7 @@ export class Formatter extends AbstractFormatter { perFileFixes.forEach((fixCount, fixedFile) => { fixLines.push(`Fixed ${fixCount} error(s) in ${fixedFile}`); }); - fixLines.push(""); // add a blank line between fixes and failures + fixLines.push(""); // add a blank line between fixes and failures } const errorLines = failures.map((failure: RuleFailure) => { @@ -54,9 +54,11 @@ export class Formatter extends AbstractFormatter { const failureString = failure.getFailure(); const lineAndCharacter = failure.getStartPosition().getLineAndCharacter(); - const positionTuple = `[${lineAndCharacter.line + 1}, ${lineAndCharacter.character + 1}]`; + const positionTuple = `${lineAndCharacter.line + 1}:${lineAndCharacter.character + 1}`; - return `${failure.getRuleSeverity().toUpperCase()}: ${fileName}${positionTuple}: ${failureString}`; + return `${failure + .getRuleSeverity() + .toUpperCase()}: ${fileName}:${positionTuple} - ${failureString}`; }); return `${fixLines.concat(errorLines).join("\n")}\n`; diff --git a/src/formatters/stylishFormatter.ts b/src/formatters/stylishFormatter.ts index 3b927327de6..bf35ba40748 100644 --- a/src/formatters/stylishFormatter.ts +++ b/src/formatters/stylishFormatter.ts @@ -33,7 +33,7 @@ export class Formatter extends AbstractFormatter { Its readability is enhanced through spacing and colouring.`, sample: Utils.dedent` myFile.ts - 1:14 semicolon Missing semicolon`, + Error: 1:14 semicolon Missing semicolon`, consumer: "human", }; /* tslint:enable:object-literal-sort-keys */ diff --git a/src/linter.ts b/src/linter.ts index df7329dbc55..e836dae216a 100644 --- a/src/linter.ts +++ b/src/linter.ts @@ -26,6 +26,7 @@ import { findConfigurationPath, getRulesDirectories, IConfigurationFile, + isFileExcluded, loadConfigurationFromPath, } from "./configuration"; import { removeDisabledFailures } from "./enableDisableRules"; @@ -54,31 +55,45 @@ export class Linter { /** * Creates a TypeScript program object from a tsconfig.json file path and optional project directory. */ - public static createProgram(configFile: string, projectDirectory: string = path.dirname(configFile)): ts.Program { + public static createProgram( + configFile: string, + projectDirectory: string = path.dirname(configFile), + ): ts.Program { const config = ts.readConfigFile(configFile, ts.sys.readFile); if (config.error !== undefined) { - throw new FatalError(ts.formatDiagnostics([config.error], { - getCanonicalFileName: (f) => f, - getCurrentDirectory: process.cwd, - getNewLine: () => "\n", - })); + throw new FatalError( + ts.formatDiagnostics([config.error], { + getCanonicalFileName: f => f, + getCurrentDirectory: process.cwd, + getNewLine: () => "\n", + }), + ); } const parseConfigHost: ts.ParseConfigHost = { fileExists: fs.existsSync, readDirectory: ts.sys.readDirectory, - readFile: (file) => fs.readFileSync(file, "utf8"), + readFile: file => fs.readFileSync(file, "utf8"), useCaseSensitiveFileNames: true, }; - const parsed = ts.parseJsonConfigFileContent(config.config, parseConfigHost, path.resolve(projectDirectory), {noEmit: true}); + const parsed = ts.parseJsonConfigFileContent( + config.config, + parseConfigHost, + path.resolve(projectDirectory), + { noEmit: true }, + ); if (parsed.errors !== undefined) { // ignore warnings and 'TS18003: No inputs were found in config file ...' - const errors = parsed.errors.filter((d) => d.category === ts.DiagnosticCategory.Error && d.code !== 18003); + const errors = parsed.errors.filter( + d => d.category === ts.DiagnosticCategory.Error && d.code !== 18003, + ); if (errors.length !== 0) { - throw new FatalError(ts.formatDiagnostics(errors, { - getCanonicalFileName: (f) => f, - getCurrentDirectory: process.cwd, - getNewLine: () => "\n", - })); + throw new FatalError( + ts.formatDiagnostics(errors, { + getCanonicalFileName: f => f, + getCurrentDirectory: process.cwd, + getNewLine: () => "\n", + }), + ); } } const host = ts.createCompilerHost(parsed.options, true); @@ -94,7 +109,7 @@ export class Linter { public static getFileNames(program: ts.Program): string[] { return mapDefined( program.getSourceFiles(), - (file) => + file => file.fileName.endsWith(".d.ts") || program.isSourceFileFromExternalLibrary(file) ? undefined : file.fileName, @@ -106,12 +121,21 @@ export class Linter { throw new Error(`Unknown Linter options type: ${typeof options}`); } if ((options as any).configuration != undefined) { - throw new Error("ILinterOptions does not contain the property `configuration` as of version 4. " + - "Did you mean to pass the `IConfigurationFile` object to lint() ? "); + throw new Error( + "ILinterOptions does not contain the property `configuration` as of version 4. " + + "Did you mean to pass the `IConfigurationFile` object to lint() ? ", + ); } } - public lint(fileName: string, source: string, configuration: IConfigurationFile = DEFAULT_CONFIG): void { + public lint( + fileName: string, + source: string, + configuration: IConfigurationFile = DEFAULT_CONFIG, + ): void { + if (isFileExcluded(fileName, configuration)) { + return; + } const sourceFile = this.getSourceFile(fileName, source); const isJs = /\.jsx?$/i.test(fileName); const enabledRules = this.getEnabledRules(configuration, isJs); @@ -122,13 +146,19 @@ export class Linter { return; } - if (this.options.fix && fileFailures.some((f) => f.hasFix())) { + if (this.options.fix && fileFailures.some(f => f.hasFix())) { fileFailures = this.applyAllFixes(enabledRules, fileFailures, sourceFile, fileName); } // add rule severity to failures - const ruleSeverityMap = new Map(enabledRules.map( - (rule): [string, RuleSeverity] => [rule.getOptions().ruleName, rule.getOptions().ruleSeverity])); + const ruleSeverityMap = new Map( + enabledRules.map( + (rule): [string, RuleSeverity] => [ + rule.getOptions().ruleName, + rule.getOptions().ruleSeverity, + ], + ), + ); for (const failure of fileFailures) { const severity = ruleSeverityMap.get(failure.getRuleName()); @@ -142,10 +172,11 @@ export class Linter { } public getResult(): LintResult { - const errors = this.failures.filter((failure) => failure.getRuleSeverity() === "error"); + const errors = this.failures.filter(failure => failure.getRuleSeverity() === "error"); const failures = this.options.quiet ? errors : this.failures; - const formatterName = this.options.formatter !== undefined ? this.options.formatter : "prose"; + const formatterName = + this.options.formatter !== undefined ? this.options.formatter : "prose"; const Formatter = findFormatter(formatterName, this.options.formattersDirectory); if (Formatter === undefined) { throw new Error(`formatter '${formatterName}' not found`); @@ -166,22 +197,31 @@ export class Linter { } private getAllFailures(sourceFile: ts.SourceFile, enabledRules: IRule[]): RuleFailure[] { - const failures = flatMap(enabledRules, (rule) => this.applyRule(rule, sourceFile)); + const failures = flatMap(enabledRules, rule => this.applyRule(rule, sourceFile)); return removeDisabledFailures(sourceFile, failures); } private applyAllFixes( - enabledRules: IRule[], fileFailures: RuleFailure[], sourceFile: ts.SourceFile, sourceFileName: string): RuleFailure[] { + enabledRules: IRule[], + fileFailures: RuleFailure[], + sourceFile: ts.SourceFile, + sourceFileName: string, + ): RuleFailure[] { // When fixing, we need to be careful as a fix in one rule may affect other rules. // So fix each rule separately. let source: string = sourceFile.text; for (const rule of enabledRules) { - const hasFixes = fileFailures.some((f) => f.hasFix() && f.getRuleName() === rule.getOptions().ruleName); + const hasFixes = fileFailures.some( + f => f.hasFix() && f.getRuleName() === rule.getOptions().ruleName, + ); if (hasFixes) { // Get new failures in case the file changed. - const updatedFailures = removeDisabledFailures(sourceFile, this.applyRule(rule, sourceFile)); - const fixableFailures = updatedFailures.filter((f) => f.hasFix()); + const updatedFailures = removeDisabledFailures( + sourceFile, + this.applyRule(rule, sourceFile), + ); + const fixableFailures = updatedFailures.filter(f => f.hasFix()); this.fixes = this.fixes.concat(fixableFailures); source = this.applyFixes(sourceFileName, source, fixableFailures); sourceFile = this.getSourceFile(sourceFileName, source); @@ -194,8 +234,12 @@ export class Linter { // Only "protected" because a test directly accesses it. // tslint:disable-next-line member-ordering - protected applyFixes(sourceFilePath: string, source: string, fixableFailures: RuleFailure[]): string { - const fixesByFile = createMultiMap(fixableFailures, (f) => [f.getFileName(), f.getFix()!]); + protected applyFixes( + sourceFilePath: string, + source: string, + fixableFailures: RuleFailure[], + ): string { + const fixesByFile = createMultiMap(fixableFailures, f => [f.getFileName(), f.getFix()!]); fixesByFile.forEach((fileFixes, filePath) => { let fileNewSource: string; if (path.resolve(filePath) === path.resolve(sourceFilePath)) { @@ -213,9 +257,17 @@ export class Linter { } private updateProgram(sourceFilePath: string) { - if (this.program !== undefined && this.program.getSourceFile(sourceFilePath) !== undefined) { + if ( + this.program !== undefined && + this.program.getSourceFile(sourceFilePath) !== undefined + ) { const options = this.program.getCompilerOptions(); - this.program = ts.createProgram(this.program.getRootFileNames(), options, ts.createCompilerHost(options, true), this.program); + this.program = ts.createProgram( + this.program.getRootFileNames(), + options, + ts.createCompilerHost(options, true), + this.program, + ); } } @@ -230,16 +282,26 @@ export class Linter { if (isError(error) && error.stack !== undefined) { showRuleCrashWarning(error.stack, rule.getOptions().ruleName, sourceFile.fileName); } else { - showRuleCrashWarning(String(error), rule.getOptions().ruleName, sourceFile.fileName); + showRuleCrashWarning( + String(error), + rule.getOptions().ruleName, + sourceFile.fileName, + ); } return []; } } - private getEnabledRules(configuration: IConfigurationFile = DEFAULT_CONFIG, isJs: boolean): IRule[] { - const ruleOptionsList = convertRuleOptions(isJs ? configuration.jsRules : configuration.rules); - const rulesDirectories = arrayify(this.options.rulesDirectory) - .concat(arrayify(configuration.rulesDirectory)); + private getEnabledRules( + configuration: IConfigurationFile = DEFAULT_CONFIG, + isJs: boolean, + ): IRule[] { + const ruleOptionsList = convertRuleOptions( + isJs ? configuration.jsRules : configuration.rules, + ); + const rulesDirectories = arrayify(this.options.rulesDirectory).concat( + arrayify(configuration.rulesDirectory), + ); return loadRules(ruleOptionsList, rulesDirectories, isJs); } @@ -259,7 +321,10 @@ export class Linter { } } -function createMultiMap(inputs: T[], getPair: (input: T) => [K, V] | undefined): Map { +function createMultiMap( + inputs: T[], + getPair: (input: T) => [K, V] | undefined, +): Map { const map = new Map(); for (const input of inputs) { const pair = getPair(input); diff --git a/src/ruleLoader.ts b/src/ruleLoader.ts index ccd3d3b78cf..92ae0ce69dc 100644 --- a/src/ruleLoader.ts +++ b/src/ruleLoader.ts @@ -25,9 +25,11 @@ import { arrayify, camelize, dedent, find } from "./utils"; const CORE_RULES_DIRECTORY = path.resolve(__dirname, "rules"); const cachedRules = new Map(); -export function loadRules(ruleOptionsList: IOptions[], - rulesDirectories?: string | string[], - isJs = false): IRule[] { +export function loadRules( + ruleOptionsList: IOptions[], + rulesDirectories?: string | string[], + isJs = false, +): IRule[] { const rules: IRule[] = []; const notFoundRules: string[] = []; const notAllowedInJsRules: string[] = []; @@ -51,7 +53,9 @@ export function loadRules(ruleOptionsList: IOptions[], } if (Rule.metadata !== undefined && Boolean(Rule.metadata.deprecationMessage)) { - showWarningOnce(`${Rule.metadata.ruleName} is deprecated. ${Rule.metadata.deprecationMessage}`); + showWarningOnce( + `${Rule.metadata.ruleName} is deprecated. ${Rule.metadata.deprecationMessage}`, + ); } } } @@ -83,13 +87,17 @@ export function loadRules(ruleOptionsList: IOptions[], } /** @internal private API */ -export function findRule(name: string, rulesDirectories?: string | string[]): RuleConstructor | undefined { +export function findRule( + name: string, + rulesDirectories?: string | string[], +): RuleConstructor | undefined { const camelizedName = transformName(name); // first check for core rules const Rule = loadCachedRule(CORE_RULES_DIRECTORY, camelizedName); - return Rule !== undefined ? Rule : - // then check for rules within the first level of rulesDirectory - find(arrayify(rulesDirectories), (dir) => loadCachedRule(dir, camelizedName, true)); + return Rule !== undefined + ? Rule + : // then check for rules within the first level of rulesDirectory + find(arrayify(rulesDirectories), dir => loadCachedRule(dir, camelizedName, true)); } function transformName(name: string): string { @@ -117,7 +125,11 @@ function loadRule(directory: string, ruleName: string): RuleConstructor | "not-f return (require(ruleFullPath) as { Rule: RuleConstructor }).Rule; } -function loadCachedRule(directory: string, ruleName: string, isCustomPath?: boolean): RuleConstructor | undefined { +function loadCachedRule( + directory: string, + ruleName: string, + isCustomPath?: boolean, +): RuleConstructor | undefined { // use cached value if available const fullPath = path.join(directory, ruleName); const cachedRule = cachedRules.get(fullPath); diff --git a/src/rules/alignRule.ts b/src/rules/alignRule.ts index d9f4f364614..65bb6c837f7 100644 --- a/src/rules/alignRule.ts +++ b/src/rules/alignRule.ts @@ -53,7 +53,7 @@ export class Rule extends Lint.Rules.AbstractRule { * \`"${OPTION_STATEMENTS}"\` checks alignment of statements. * \`"${OPTION_MEMBERS}"\` checks alignment of members of classes, interfaces, type literal, object literals and object destructuring. - * \`"${OPTION_ELEMENTS}"\` checks alignment of elements of array iterals, array destructuring and tuple types.`, + * \`"${OPTION_ELEMENTS}"\` checks alignment of elements of array literals, array destructuring and tuple types.`, options: { type: "array", items: { diff --git a/src/rules/banRule.ts b/src/rules/banRule.ts index c73b484ac89..d4874a9bb9c 100644 --- a/src/rules/banRule.ts +++ b/src/rules/banRule.ts @@ -50,7 +50,7 @@ export class Rule extends Lint.Rules.AbstractRule { * the name of the function in an array with one element: \`["functionName"]\` * an object in the following format: \`{"name": "functionName", "message": "optional explanation message"}\` * banning methods: - * an array with the object name, method name and optional message: \`["functionName", "methodName", "optional message"]\` + * an array with the object name, method name and optional message: \`["objectName", "methodName", "optional message"]\` * an object in the following format: \`{"name": ["objectName", "methodName"], "message": "optional message"}\` * you can also ban deeply nested methods: \`{"name": ["foo", "bar", "baz"]}\` bans \`foo.bar.baz()\` * the first element can contain a wildcard (\`*\`) that matches everything. \`{"name": ["*", "forEach"]}\` bans\ @@ -61,52 +61,56 @@ export class Rule extends Lint.Rules.AbstractRule { listType: { anyOf: [ { - type: "string", + type: "string" }, { type: "array", - items: {type: "string"}, + items: { type: "string" }, minLength: 1, - maxLength: 3, + maxLength: 3 }, { type: "object", properties: { name: { anyOf: [ - {type: "string"}, - {type: "array", items: {type: "string"}, minLength: 1}, - ], + { type: "string" }, + { type: "array", items: { type: "string" }, minLength: 1 } + ] }, - message: {type: "string"}, + message: { type: "string" } }, - required: ["name"], - }, - ], - }, + required: ["name"] + } + ] + } }, optionExamples: [ [ true, "eval", - {name: "$", message: "please don't"}, + { name: "$", message: "please don't" }, ["describe", "only"], - {name: ["it", "only"], message: "don't focus tests"}, - {name: ["chai", "assert", "equal"], message: "Use 'strictEqual' instead."}, - {name: ["*", "forEach"], message: "Use a regular for loop instead."}, - ], + { name: ["it", "only"], message: "don't focus tests" }, + { name: ["chai", "assert", "equal"], message: "Use 'strictEqual' instead." }, + { name: ["*", "forEach"], message: "Use a regular for loop instead." } + ] ], type: "functionality", - typescriptOnly: false, + typescriptOnly: false }; /* tslint:enable:object-literal-sort-keys */ public static FAILURE_STRING_FACTORY(expression: string, messageAddition?: string) { - return `Calls to '${expression}' are not allowed.${messageAddition !== undefined ? ` ${messageAddition}` : ""}`; + return `Calls to '${expression}' are not allowed.${ + messageAddition !== undefined ? ` ${messageAddition}` : "" + }`; } public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { - return this.applyWithWalker(new BanFunctionWalker(sourceFile, this.ruleName, parseOptions(this.ruleArguments))); + return this.applyWithWalker( + new BanFunctionWalker(sourceFile, this.ruleName, parseOptions(this.ruleArguments)) + ); } } @@ -115,16 +119,16 @@ function parseOptions(args: Array): Options { const methods: MethodBan[] = []; for (const arg of args) { if (typeof arg === "string") { - functions.push({name: arg}); + functions.push({ name: arg }); } else if (Array.isArray(arg)) { switch (arg.length) { case 0: break; case 1: - functions.push({name: arg[0]}); + functions.push({ name: arg[0] }); break; default: - methods.push({object: [arg[0]], name: arg[1], message: arg[2]}); + methods.push({ object: [arg[0]], name: arg[1], message: arg[2] }); } } else if (!Array.isArray(arg.name)) { functions.push(arg as FunctionBan); @@ -133,10 +137,14 @@ function parseOptions(args: Array): Options { case 0: break; case 1: - functions.push({name: arg.name[0], message: arg.message}); + functions.push({ name: arg.name[0], message: arg.message }); break; default: - methods.push({name: arg.name[arg.name.length - 1], object: arg.name.slice(0, -1), message: arg.message}); + methods.push({ + message: arg.message, + name: arg.name[arg.name.length - 1], + object: arg.name.slice(0, -1) + }); } } } @@ -160,22 +168,31 @@ class BanFunctionWalker extends Lint.AbstractWalker { private checkForObjectMethodBan(expression: ts.PropertyAccessExpression) { for (const ban of this.options.methods) { - if (expression.name.text !== ban.name) { continue; } + if (expression.name.text !== ban.name) { + continue; + } let current = expression.expression; for (let i = ban.object.length - 1; i > 0; --i) { - if (!isPropertyAccessExpression(current) || current.name.text !== ban.object[i]) { continue; } + if (!isPropertyAccessExpression(current) || current.name.text !== ban.object[i]) { + continue; + } current = current.expression; } - if (ban.object[0] === "*" || - isIdentifier(current) && current.text === ban.object[0]) { - this.addFailureAtNode(expression, Rule.FAILURE_STRING_FACTORY(`${ban.object.join(".")}.${ban.name}`, ban.message)); + if ( + ban.object[0] === "*" || + (isIdentifier(current) && current.text === ban.object[0]) + ) { + this.addFailureAtNode( + expression, + Rule.FAILURE_STRING_FACTORY(`${ban.object.join(".")}.${ban.name}`, ban.message) + ); break; } } } private checkFunctionBan(name: ts.Identifier) { - const {text} = name; + const { text } = name; for (const ban of this.options.functions) { if (ban.name === text) { this.addFailureAtNode(name, Rule.FAILURE_STRING_FACTORY(text, ban.message)); diff --git a/src/rules/banTsIgnoreRule.ts b/src/rules/banTsIgnoreRule.ts new file mode 100644 index 00000000000..ee236013e0a --- /dev/null +++ b/src/rules/banTsIgnoreRule.ts @@ -0,0 +1,52 @@ +/** + * @license + * Copyright 2018 Palantir Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { forEachComment } from "tsutils"; +import * as ts from "typescript"; +import * as Lint from "../index"; +import { codeExamples } from "./code-examples/banTsIgnore.examples"; + +export class Rule extends Lint.Rules.AbstractRule { + /* tslint:disable:object-literal-sort-keys */ + public static metadata: Lint.IRuleMetadata = { + ruleName: "ban-ts-ignore", + description: 'Bans "// @ts-ignore" comments from being used.', + optionsDescription: "Not configurable.", + options: null, + optionExamples: [true], + type: "typescript", + typescriptOnly: true, + codeExamples, + }; + /* tslint:disable:object-literal-sort-keys */ + + public static FAILURE_STRING = 'Do not use "// @ts-ignore" comments because they suppress compilation errors.'; + + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithFunction(sourceFile, walk); + } +} + +function walk(ctx: Lint.WalkContext) { + const ignoreDiagnosticCommentRegEx = /^\s*\/\/\/?\s*@ts-ignore/; + forEachComment(ctx.sourceFile, (fullText, comment) => { + const commentText = fullText.slice(comment.pos, comment.end); + if (Boolean(commentText.match(ignoreDiagnosticCommentRegEx))) { + ctx.addFailure(comment.pos, comment.end, Rule.FAILURE_STRING); + } + }); +} diff --git a/src/rules/code-examples/banTsIgnore.examples.ts b/src/rules/code-examples/banTsIgnore.examples.ts new file mode 100644 index 00000000000..9dc5278936e --- /dev/null +++ b/src/rules/code-examples/banTsIgnore.examples.ts @@ -0,0 +1,40 @@ +/** + * @license + * Copyright 2018 Palantir Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as Lint from "../../index"; + +// tslint:disable: object-literal-sort-keys +export const codeExamples = [ + { + description: 'Disallows the use of "@ts-ignore"', + config: Lint.Utils.dedent` + "rules": { "ban-ts-ignore": true } + `, + pass: Lint.Utils.dedent` + if (false) { + // Compiler warns about unreachable code error + console.log("hello"); + } + `, + fail: Lint.Utils.dedent` + if (false) { + // @ts-ignore: Unreachable code error + console.log("hello"); + } + `, + }, +]; diff --git a/src/rules/code-examples/curly.examples.ts b/src/rules/code-examples/curly.examples.ts index d2af09a11f5..795bf3c38bc 100644 --- a/src/rules/code-examples/curly.examples.ts +++ b/src/rules/code-examples/curly.examples.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright 2018 Palantir Technologies, Inc. + * Copyright 2013 Palantir Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/rules/completed-docs/tagExclusion.ts b/src/rules/completed-docs/tagExclusion.ts index a394724b163..1c4fc47ad5a 100644 --- a/src/rules/completed-docs/tagExclusion.ts +++ b/src/rules/completed-docs/tagExclusion.ts @@ -75,7 +75,7 @@ export class TagExclusion extends Exclusion { return []; } - const docMatches = nodeText.match((/\/\*\*\s*\n([^\*]*(\*[^\/])?)*\*\//)); + const docMatches = nodeText.match((/\/\*\*\s*\n?([^\*]*(\*[^\/])?)*\*\//)); if (docMatches === null || docMatches.length === 0) { return []; } diff --git a/src/rules/completedDocsRule.ts b/src/rules/completedDocsRule.ts index 16c4e1cfd95..ceb9176d021 100644 --- a/src/rules/completedDocsRule.ts +++ b/src/rules/completedDocsRule.ts @@ -340,6 +340,10 @@ function walk(context: Lint.WalkContext, typeChecker: ts.TypeChec checkNode(node as ts.InterfaceDeclaration, ARGUMENT_INTERFACES); break; + case ts.SyntaxKind.MethodSignature: + checkNode(node as ts.MethodSignature, ARGUMENT_METHODS); + break; + case ts.SyntaxKind.MethodDeclaration: if (node.parent!.kind !== ts.SyntaxKind.ObjectLiteralExpression) { checkNode(node as ts.MethodDeclaration, ARGUMENT_METHODS); @@ -350,6 +354,10 @@ function walk(context: Lint.WalkContext, typeChecker: ts.TypeChec checkNode(node as ts.ModuleDeclaration, ARGUMENT_NAMESPACES); break; + case ts.SyntaxKind.PropertySignature: + checkNode(node as ts.PropertySignature, ARGUMENT_PROPERTIES); + break; + case ts.SyntaxKind.PropertyDeclaration: checkNode(node as ts.PropertyDeclaration, ARGUMENT_PROPERTIES); break; diff --git a/src/rules/fileHeaderRule.ts b/src/rules/fileHeaderRule.ts index fa45656d261..699b540ba98 100644 --- a/src/rules/fileHeaderRule.ts +++ b/src/rules/fileHeaderRule.ts @@ -18,50 +18,60 @@ import * as ts from "typescript"; import * as Lint from "../index"; +const ENFORCE_TRAILING_NEWLINE = "enforce-trailing-newline"; + export class Rule extends Lint.Rules.AbstractRule { /* tslint:disable:object-literal-sort-keys */ public static metadata: Lint.IRuleMetadata = { ruleName: "file-header", - description: "Enforces a certain header comment for all files, matched by a regular expression.", + description: + "Enforces a certain header comment for all files, matched by a regular expression.", optionsDescription: Lint.Utils.dedent` The first option, which is mandatory, is a regular expression that all headers should match. The second argument, which is optional, is a string that should be inserted as a header comment - if fixing is enabled and no header that matches the first argument is found.`, + if fixing is enabled and no header that matches the first argument is found. + The third argument, which is optional, is a string that denotes whether or not a newline should + exist on the header.`, options: { type: "array", items: [ { - type: "string", + type: "string" }, { - type: "string", + type: "string" }, + { + type: "string" + } ], additionalItems: false, minLength: 1, - maxLength: 2, + maxLength: 3 }, - optionExamples: [[true, "Copyright \\d{4}", "Copyright 2017"]], + optionExamples: [[true, "Copyright \\d{4}", "Copyright 2018", ENFORCE_TRAILING_NEWLINE]], hasFix: true, type: "style", - typescriptOnly: false, + typescriptOnly: false }; /* tslint:enable:object-literal-sort-keys */ - public static FAILURE_STRING = "missing file header"; + public static MISSING_HEADER_FAILURE_STRING = "missing file header"; + public static MISSING_NEW_LINE_FAILURE_STRING = "missing new line following the file header"; public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { const { text } = sourceFile; const headerFormat = new RegExp(this.ruleArguments[0] as string); const textToInsert = this.ruleArguments[1] as string | undefined; + const enforceExtraTrailingLine = + this.ruleArguments.indexOf(ENFORCE_TRAILING_NEWLINE) !== -1; // ignore shebang if it exists let offset = text.startsWith("#!") ? text.indexOf("\n") : 0; // returns the text of the first comment or undefined - const commentText = ts.forEachLeadingCommentRange( - text, - offset, - (pos, end, kind) => text.substring(pos + 2, kind === ts.SyntaxKind.SingleLineCommentTrivia ? end : end - 2)); + const commentText = ts.forEachLeadingCommentRange(text, offset, (pos, end, kind) => + text.substring(pos + 2, kind === ts.SyntaxKind.SingleLineCommentTrivia ? end : end - 2) + ); if (commentText === undefined || !headerFormat.test(commentText)) { const isErrorAtStart = offset === 0; @@ -71,24 +81,94 @@ export class Rule extends Lint.Rules.AbstractRule { const leadingNewlines = isErrorAtStart ? 0 : 1; const trailingNewlines = isErrorAtStart ? 2 : 1; - const fix = textToInsert !== undefined - ? Lint.Replacement.appendText(offset, this.createComment(sourceFile, textToInsert, leadingNewlines, trailingNewlines)) - : undefined; - return [new Lint.RuleFailure(sourceFile, offset, offset, Rule.FAILURE_STRING, this.ruleName, fix)]; + const fix = + textToInsert !== undefined + ? Lint.Replacement.appendText( + offset, + this.createComment( + sourceFile, + textToInsert, + leadingNewlines, + trailingNewlines + ) + ) + : undefined; + return [ + new Lint.RuleFailure( + sourceFile, + offset, + offset, + Rule.MISSING_HEADER_FAILURE_STRING, + this.ruleName, + fix + ) + ]; + } + + const trailingNewLineViolation = + enforceExtraTrailingLine && + headerFormat.test(commentText) && + this.doesNewLineEndingViolationExist(text, offset); + + if (trailingNewLineViolation) { + const trailingCommentRanges = ts.getTrailingCommentRanges(text, offset); + const endOfComment = trailingCommentRanges![0].end; + const lineEnding = this.generateLineEnding(sourceFile); + const fix = + textToInsert !== undefined + ? Lint.Replacement.appendText(endOfComment, lineEnding) + : undefined; + + return [ + new Lint.RuleFailure( + sourceFile, + offset, + offset, + Rule.MISSING_NEW_LINE_FAILURE_STRING, + this.ruleName, + fix + ) + ]; } + return []; } - private createComment(sourceFile: ts.SourceFile, commentText: string, leadingNewlines = 1, trailingNewlines = 1) { - const maybeCarriageReturn = sourceFile.text[sourceFile.getLineEndOfPosition(0)] === "\r" ? "\r" : ""; - const lineEnding = `${maybeCarriageReturn}\n`; - return lineEnding.repeat(leadingNewlines) + [ - "/*!", - // split on both types of line endings in case users just typed "\n" in their configs - // but are working in files with \r\n line endings - // Trim trailing spaces to play nice with `no-trailing-whitespace` rule - ...commentText.split(/\r?\n/g).map((line) => ` * ${line}`.replace(/\s+$/, "")), - " */", - ].join(lineEnding) + lineEnding.repeat(trailingNewlines); + private createComment( + sourceFile: ts.SourceFile, + commentText: string, + leadingNewlines = 1, + trailingNewlines = 1 + ) { + const lineEnding = this.generateLineEnding(sourceFile); + return ( + lineEnding.repeat(leadingNewlines) + + [ + "/*!", + // split on both types of line endings in case users just typed "\n" in their configs + // but are working in files with \r\n line endings + // Trim trailing spaces to play nice with `no-trailing-whitespace` rule + ...commentText.split(/\r?\n/g).map(line => ` * ${line}`.replace(/\s+$/, "")), + " */" + ].join(lineEnding) + + lineEnding.repeat(trailingNewlines) + ); + } + + private generateLineEnding(sourceFile: ts.SourceFile) { + const maybeCarriageReturn = + sourceFile.text[sourceFile.getLineEndOfPosition(0)] === "\r" ? "\r" : ""; + return `${maybeCarriageReturn}\n`; + } + + private doesNewLineEndingViolationExist(text: string, offset: number): boolean { + const entireComment = ts.forEachLeadingCommentRange(text, offset, (pos, end) => + text.substring(pos, end + 2) + ); + + const NEW_LINE_FOLLOWING_HEADER = /^.*((\r)?\n){2,}$/gm; + return ( + entireComment !== undefined && NEW_LINE_FOLLOWING_HEADER.test(entireComment) !== null + ); } } diff --git a/src/rules/fileNameCasingRule.ts b/src/rules/fileNameCasingRule.ts index ea837f3e7bc..fcd7bdc5a17 100644 --- a/src/rules/fileNameCasingRule.ts +++ b/src/rules/fileNameCasingRule.ts @@ -19,12 +19,13 @@ import * as path from "path"; import * as ts from "typescript"; import * as Lint from "../index"; -import { isCamelCased, isKebabCased, isPascalCased } from "../utils"; +import { isCamelCased, isKebabCased, isPascalCased, isSnakeCased } from "../utils"; enum Casing { CamelCase = "camel-case", PascalCase = "pascal-case", KebabCase = "kebab-case", + SnakeCase = "snake-case", } export class Rule extends Lint.Rules.AbstractRule { @@ -38,13 +39,14 @@ export class Rule extends Lint.Rules.AbstractRule { * \`${Casing.CamelCase}\`: File names must be camel-cased: \`fileName.ts\`. * \`${Casing.PascalCase}\`: File names must be Pascal-cased: \`FileName.ts\`. - * \`${Casing.KebabCase}\`: File names must be kebab-cased: \`file-name.ts\`.`, + * \`${Casing.KebabCase}\`: File names must be kebab-cased: \`file-name.ts\`. + * \`${Casing.SnakeCase}\`: File names must be snake-cased: \`file_name.ts\`.`, options: { type: "array", items: [ { type: "string", - enum: [Casing.CamelCase, Casing.PascalCase, Casing.KebabCase], + enum: [Casing.CamelCase, Casing.PascalCase, Casing.KebabCase, Casing.SnakeCase], }, ], }, @@ -52,6 +54,7 @@ export class Rule extends Lint.Rules.AbstractRule { [true, Casing.CamelCase], [true, Casing.PascalCase], [true, Casing.KebabCase], + [true, Casing.SnakeCase], ], hasFix: false, type: "style", @@ -71,6 +74,8 @@ export class Rule extends Lint.Rules.AbstractRule { return "PascalCase"; case Casing.KebabCase: return "kebab-case"; + case Casing.SnakeCase: + return "snake_case"; } } @@ -82,6 +87,8 @@ export class Rule extends Lint.Rules.AbstractRule { return isPascalCased(fileName); case Casing.KebabCase: return isKebabCased(fileName); + case Casing.SnakeCase: + return isSnakeCased(fileName); } } diff --git a/src/rules/incrementDecrementRule.ts b/src/rules/incrementDecrementRule.ts new file mode 100644 index 00000000000..1baed03122e --- /dev/null +++ b/src/rules/incrementDecrementRule.ts @@ -0,0 +1,117 @@ +/** + * @license + * Copyright 2013 Palantir Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as tsutils from "tsutils"; +import * as ts from "typescript"; + +import * as Lint from "../index"; + +interface Options { + allowPost: boolean; +} + +const OPTION_ALLOW_POST = "allow-post"; + +export class Rule extends Lint.Rules.AbstractRule { + public static metadata: Lint.IRuleMetadata = { + description: "Enforces using explicit += 1 or -= 1 operators.", + optionExamples: [ + true, + [true, OPTION_ALLOW_POST], + ], + options: { + items: { + enum: [OPTION_ALLOW_POST], + type: "string", + }, + maxLength: 1, + minLength: 0, + type: "array", + }, + optionsDescription: Lint.Utils.dedent` + If no arguments are provided, both pre- and post-unary operators are banned. + If \`"${OPTION_ALLOW_POST}"\` is provided, post-unary operators will be allowed. + `, + rationale: Lint.Utils.dedent` + It's easy to type +i or -i instead of --i or ++i, and won't always result in invalid code. + Prefer standardizing small arithmetic operations with the explicit += and -= operators. + `, + ruleName: "increment-decrement", + type: "style", + typescriptOnly: false, + }; + + public static FAILURE_STRING_FACTORY = (newOperatorText: string) => + `Use an explicit ${newOperatorText} operator.` + + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + const options: Options = { + allowPost: this.ruleArguments.indexOf(OPTION_ALLOW_POST) !== -1, + }; + + return this.applyWithFunction(sourceFile, walk, options); + } +} + +function walk(context: Lint.WalkContext) { + function createReplacement(node: ts.PostfixUnaryExpression | ts.PrefixUnaryExpression, newOperatorText: string): Lint.Replacement { + let text = `${node.operand.getText(context.sourceFile)} ${newOperatorText}`; + + if (node.parent !== undefined && tsutils.isBinaryExpression(node.parent)) { + text = `(${text})`; + } + + return Lint.Replacement.replaceNode(node, text); + } + + function complainOnNode(node: ts.PostfixUnaryExpression | ts.PrefixUnaryExpression) { + const newOperatorText = node.operator === ts.SyntaxKind.PlusPlusToken + ? "+= 1" + : "-= 1"; + const replacement = createReplacement(node, newOperatorText); + + const failure = Rule.FAILURE_STRING_FACTORY(newOperatorText); + + context.addFailureAtNode(node, failure, replacement); + } + + function checkPostfixUnaryExpression(node: ts.PostfixUnaryExpression): void { + if (!context.options.allowPost && isIncrementOrDecrementOperator(node.operator)) { + complainOnNode(node); + } + } + + function checkPrefixUnaryExpression(node: ts.PrefixUnaryExpression): void { + if (isIncrementOrDecrementOperator(node.operator)) { + complainOnNode(node); + } + } + + return ts.forEachChild(context.sourceFile, function callback(node: ts.Node): void { + if (tsutils.isPostfixUnaryExpression(node)) { + checkPostfixUnaryExpression(node); + } else if (tsutils.isPrefixUnaryExpression(node)) { + checkPrefixUnaryExpression(node); + } + + return ts.forEachChild(node, callback); + }); +} + +function isIncrementOrDecrementOperator(operator: ts.PostfixUnaryOperator | ts.PrefixUnaryOperator) { + return operator === ts.SyntaxKind.PlusPlusToken || operator === ts.SyntaxKind.MinusMinusToken; +} diff --git a/src/rules/whitespaceRule.ts b/src/rules/whitespaceRule.ts index 6febb31df4b..b633e529714 100644 --- a/src/rules/whitespaceRule.ts +++ b/src/rules/whitespaceRule.ts @@ -32,6 +32,7 @@ const OPTION_TYPE = "check-type"; const OPTION_TYPECAST = "check-typecast"; const OPTION_TYPE_OPERATOR = "check-type-operator"; const OPTION_PREBLOCK = "check-preblock"; +const OPTION_POSTBRACE = "check-postbrace"; export class Rule extends Lint.Rules.AbstractRule { public static metadata: Lint.IRuleMetadata = { @@ -50,18 +51,28 @@ export class Rule extends Lint.Rules.AbstractRule { * \`"check-type"\` checks for whitespace before a variable type specification. * \`"check-typecast"\` checks for whitespace between a typecast and its target. * \`"check-type-operator"\` checks for whitespace between type operators \`|\` and \`&\`. - * \`"check-preblock"\` checks for whitespace before the opening brace of a block`, + * \`"check-preblock"\` checks for whitespace before the opening brace of a block. + * \`"check-postbrace"\` checks for whitespace after an opening brace.`, options: { type: "array", items: { type: "string", enum: [ - "check-branch", "check-decl", "check-operator", "check-module", "check-separator", - "check-rest-spread", "check-type", "check-typecast", "check-type-operator", "check-preblock", + "check-branch", + "check-decl", + "check-operator", + "check-module", + "check-separator", + "check-rest-spread", + "check-type", + "check-typecast", + "check-type-operator", + "check-preblock", + "check-postbrace", ], }, minLength: 0, - maxLength: 10, + maxLength: 11, }, optionExamples: [[true, "check-branch", "check-operator", "check-typecast"]], type: "style", @@ -78,8 +89,19 @@ export class Rule extends Lint.Rules.AbstractRule { } type Options = Record< - "branch" | "decl" | "operator" | "module" | "separator" | "restSpread" | "type" | "typecast" | "typeOperator" | "preblock", - boolean>; + | "branch" + | "decl" + | "operator" + | "module" + | "separator" + | "restSpread" + | "type" + | "typecast" + | "typeOperator" + | "preblock" + | "postbrace", + boolean +>; function parseOptions(ruleArguments: string[]): Options { return { @@ -93,6 +115,7 @@ function parseOptions(ruleArguments: string[]): Options { typecast: has(OPTION_TYPECAST), typeOperator: has(OPTION_TYPE_OPERATOR), preblock: has(OPTION_PREBLOCK), + postbrace: has(OPTION_POSTBRACE), }; function has(option: string): boolean { @@ -168,7 +191,7 @@ function walk(ctx: Lint.WalkContext) { checkForTrailingWhitespace(token.getFullStart()); } if (idx === 0) { - const startPos = internalName.getStart() - 1; + const startPos = element.getStart() - 1; checkForTrailingWhitespace(startPos, startPos + 1); } } @@ -244,10 +267,11 @@ function walk(ctx: Lint.WalkContext) { let prevTokenShouldBeFollowedByWhitespace = false; utils.forEachTokenWithTrivia(sourceFile, (_text, tokenKind, range, parent) => { - if (tokenKind === ts.SyntaxKind.WhitespaceTrivia || + if ( + tokenKind === ts.SyntaxKind.WhitespaceTrivia || tokenKind === ts.SyntaxKind.NewLineTrivia || - tokenKind === ts.SyntaxKind.EndOfFileToken) { - + tokenKind === ts.SyntaxKind.EndOfFileToken + ) { prevTokenShouldBeFollowedByWhitespace = false; return; } else if (prevTokenShouldBeFollowedByWhitespace) { @@ -277,9 +301,11 @@ function walk(ctx: Lint.WalkContext) { } const nextPosition = range.pos + 1; - const semicolonInTrivialFor = parent.kind === ts.SyntaxKind.ForStatement && + const semicolonInTrivialFor = + parent.kind === ts.SyntaxKind.ForStatement && nextPosition !== sourceFile.end && - (sourceFile.text[nextPosition] === ";" || sourceFile.text[nextPosition] === ")"); + (sourceFile.text[nextPosition] === ";" || + sourceFile.text[nextPosition] === ")"); if (!semicolonInTrivialFor) { prevTokenShouldBeFollowedByWhitespace = true; @@ -295,9 +321,23 @@ function walk(ctx: Lint.WalkContext) { prevTokenShouldBeFollowedByWhitespace = true; } break; + case ts.SyntaxKind.OpenBraceToken: + const nextPos = range.pos + 1; + if ( + options.postbrace && + (sourceFile.text[nextPos] !== " " && + sourceFile.text[nextPos] !== "\r" && + sourceFile.text[nextPos] !== "\t" && + sourceFile.text[nextPos] !== "\n") + ) { + addMissingWhitespaceErrorAt(nextPos); + } + break; case ts.SyntaxKind.ImportKeyword: - if (parent.kind === ts.SyntaxKind.CallExpression && - (parent as ts.CallExpression).expression.kind === ts.SyntaxKind.ImportKeyword) { + if ( + parent.kind === ts.SyntaxKind.CallExpression && + (parent as ts.CallExpression).expression.kind === ts.SyntaxKind.ImportKeyword + ) { return; // Don't check ImportCall } // falls through @@ -314,7 +354,11 @@ function walk(ctx: Lint.WalkContext) { return; } - const equalsGreaterThanToken = utils.getChildOfKind(node, ts.SyntaxKind.EqualsGreaterThanToken, sourceFile); + const equalsGreaterThanToken = utils.getChildOfKind( + node, + ts.SyntaxKind.EqualsGreaterThanToken, + sourceFile, + ); // condition so we don't crash if the arrow is somehow missing if (equalsGreaterThanToken === undefined) { return; @@ -325,14 +369,17 @@ function walk(ctx: Lint.WalkContext) { } function checkForTrailingWhitespace(position: number, whiteSpacePos: number = position): void { - if (position !== sourceFile.end && !Lint.isWhiteSpace(sourceFile.text.charCodeAt(position))) { + if ( + position !== sourceFile.end && + !Lint.isWhiteSpace(sourceFile.text.charCodeAt(position)) + ) { addMissingWhitespaceErrorAt(whiteSpacePos); } } function addMissingWhitespaceErrorAt(position: number): void { // TODO: this rule occasionally adds duplicate failures. - if (ctx.failures.some((f) => f.getStartPosition().getPosition() === position)) { + if (ctx.failures.some(f => f.getStartPosition().getPosition() === position)) { return; } const fix = Lint.Replacement.appendText(position, " "); @@ -340,7 +387,10 @@ function walk(ctx: Lint.WalkContext) { } function checkForExcessiveWhitespace(position: number): void { - if (position !== sourceFile.end && Lint.isWhiteSpace(sourceFile.text.charCodeAt(position))) { + if ( + position !== sourceFile.end && + Lint.isWhiteSpace(sourceFile.text.charCodeAt(position)) + ) { addInvalidWhitespaceErrorAt(position); } } diff --git a/src/runner.ts b/src/runner.ts index 777b39de926..a6f7a63d8e9 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -26,6 +26,7 @@ import * as ts from "typescript"; import { DEFAULT_CONFIG, findConfiguration, + isFileExcluded, JSON_CONFIG_FILENAME, } from "./configuration"; import { FatalError } from "./error"; @@ -146,7 +147,10 @@ async function runWorker(options: Options, logger: Logger): Promise { if (options.test) { const test = await import("./test"); - const results = test.runTests((options.files || []).map(trimSingleQuotes), options.rulesDirectory); + const results = test.runTests( + (options.files || []).map(trimSingleQuotes), + options.rulesDirectory, + ); return test.consoleTestResultsHandler(results, logger) ? Status.Ok : Status.FatalError; } @@ -167,7 +171,9 @@ async function runLinter(options: Options, logger: Logger): Promise if (program && options.typeCheck) { const diagnostics = ts.getPreEmitDiagnostics(program); if (diagnostics.length !== 0) { - const message = diagnostics.map((d) => showDiagnostic(d, program, options.outputAbsolutePaths)).join("\n"); + const message = diagnostics + .map(d => showDiagnostic(d, program, options.outputAbsolutePaths)) + .join("\n"); if (options.force) { logger.error(`${message}\n`); } else { @@ -194,14 +200,14 @@ function resolveFilesAndProgram( throw new FatalError(`Invalid option for project: ${project}`); } - exclude = exclude.map((pattern) => path.resolve(pattern)); + exclude = exclude.map(pattern => path.resolve(pattern)); const program = Linter.createProgram(projectPath); let filesFound: string[]; if (files.length === 0) { filesFound = filterFiles(Linter.getFileNames(program), exclude, false); } else { - files = files.map((f) => path.resolve(f)); - filesFound = filterFiles(program.getSourceFiles().map((f) => f.fileName), files, true); + files = files.map(f => path.resolve(f)); + filesFound = filterFiles(program.getSourceFiles().map(f => f.fileName), files, true); filesFound = filterFiles(filesFound, exclude, false); // find non-glob files that have no matching file in the project and are not excluded by any exclude pattern @@ -221,14 +227,18 @@ function filterFiles(files: string[], patterns: string[], include: boolean): str if (patterns.length === 0) { return include ? [] : files; } - const matcher = patterns.map((pattern) => new Minimatch(pattern, {dot: !include})); // `glob` always enables `dot` for ignore patterns - return files.filter((file) => include === matcher.some((pattern) => pattern.match(file))); + const matcher = patterns.map(pattern => new Minimatch(pattern, { dot: !include })); // `glob` always enables `dot` for ignore patterns + return files.filter(file => include === matcher.some(pattern => pattern.match(file))); } -function resolveGlobs(files: string[], ignore: string[], outputAbsolutePaths: boolean | undefined, logger: Logger): string[] { - const results = flatMap( - files, - (file) => glob.sync(trimSingleQuotes(file), { ignore, nodir: true }), +function resolveGlobs( + files: string[], + ignore: string[], + outputAbsolutePaths: boolean | undefined, + logger: Logger, +): string[] { + const results = flatMap(files, file => + glob.sync(trimSingleQuotes(file), { ignore, nodir: true }), ); // warn if `files` contains non-existent files, that are not patters and not excluded by any of the exclude patterns for (const file of filterFiles(files, ignore, false)) { @@ -237,14 +247,32 @@ function resolveGlobs(files: string[], ignore: string[], outputAbsolutePaths: bo } } const cwd = process.cwd(); - return results.map((file) => outputAbsolutePaths ? path.resolve(cwd, file) : path.relative(cwd, file)); + return results.map( + file => (outputAbsolutePaths ? path.resolve(cwd, file) : path.relative(cwd, file)), + ); } -async function doLinting(options: Options, files: string[], program: ts.Program | undefined, logger: Logger): Promise { +async function doLinting( + options: Options, + files: string[], + program: ts.Program | undefined, + logger: Logger, +): Promise { + let configFile = + options.config !== undefined ? findConfiguration(options.config).results : undefined; + + let formatter = options.format; + if (formatter === undefined) { + formatter = + configFile && configFile.linterOptions && configFile.linterOptions.format + ? configFile.linterOptions.format + : "prose"; + } + const linter = new Linter( { fix: !!options.fix, - formatter: options.format, + formatter, formattersDirectory: options.formattersDirectory, quiet: !!options.quiet, rulesDirectory: options.rulesDirectory, @@ -253,7 +281,6 @@ async function doLinting(options: Options, files: string[], program: ts.Program ); let lastFolder: string | undefined; - let configFile = options.config !== undefined ? findConfiguration(options.config).results : undefined; for (const file of files) { if (options.config === undefined) { @@ -263,7 +290,7 @@ async function doLinting(options: Options, files: string[], program: ts.Program lastFolder = folder; } } - if (isFileExcluded(file)) { + if (isFileExcluded(file, configFile)) { continue; } @@ -283,14 +310,6 @@ async function doLinting(options: Options, files: string[], program: ts.Program } return linter.getResult(); - - function isFileExcluded(filepath: string) { - if (configFile === undefined || configFile.linterOptions == undefined || configFile.linterOptions.exclude == undefined) { - return false; - } - const fullPath = path.resolve(filepath); - return configFile.linterOptions.exclude.some((pattern) => new Minimatch(pattern).match(fullPath)); - } } /** Read a file, but return undefined if it is an MPEG '.ts' file. */ @@ -316,10 +335,14 @@ async function tryReadFile(filename: string, logger: Logger): Promise runTest(path.dirname(directory), rulesDirectory)); + return files.map( + (directory: string): TestResult => runTest(path.dirname(directory), rulesDirectory), + ); } export function runTest(testDirectory: string, rulesDirectory?: string | string[]): TestResult { const filesToLint = glob.sync(path.join(testDirectory, `**/*${MARKUP_FILE_EXTENSION}`)); - const tslintConfig = Linter.findConfiguration(path.join(testDirectory, "tslint.json"), "").results; + const tslintConfig = Linter.findConfiguration(path.join(testDirectory, "tslint.json"), "") + .results; const tsConfig = path.join(testDirectory, "tsconfig.json"); let compilerOptions: ts.CompilerOptions = { allowJs: true }; const hasConfig = fs.existsSync(tsConfig); if (hasConfig) { - const {config, error} = ts.readConfigFile(tsConfig, ts.sys.readFile); + const { config, error } = ts.readConfigFile(tsConfig, ts.sys.readFile); if (error !== undefined) { throw new Error(ts.formatDiagnostics([error], ts.createCompilerHost({}))); } @@ -84,7 +87,8 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ readFile: (file: string) => fs.readFileSync(file, "utf8"), useCaseSensitiveFileNames: true, }; - compilerOptions = ts.parseJsonConfigFileContent(config, parseConfigHost, testDirectory).options; + compilerOptions = ts.parseJsonConfigFileContent(config, parseConfigHost, testDirectory) + .options; } const results: TestResult = { directory: testDirectory, results: {} }; @@ -92,7 +96,9 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ const isEncodingRule = path.basename(testDirectory) === "encoding"; const fileCompileName = denormalizeWinPath(path.resolve(fileToLint.replace(/\.lint$/, ""))); - let fileText = isEncodingRule ? readBufferWithDetectedEncoding(fs.readFileSync(fileToLint)) : fs.readFileSync(fileToLint, "utf-8"); + let fileText = isEncodingRule + ? readBufferWithDetectedEncoding(fs.readFileSync(fileToLint)) + : fs.readFileSync(fileToLint, "utf-8"); const tsVersionRequirement = parse.getTypescriptVersionRequirement(fileText); if (tsVersionRequirement !== undefined) { // remove prerelease suffix when matching to allow testing with nightly builds @@ -114,24 +120,32 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ let program: ts.Program | undefined; if (hasConfig) { const compilerHost: ts.CompilerHost = { - fileExists: (file) => file === fileCompileName || fs.existsSync(file), - getCanonicalFileName: (filename) => filename, + fileExists: file => file === fileCompileName || fs.existsSync(file), + getCanonicalFileName: filename => filename, getCurrentDirectory: () => process.cwd(), getDefaultLibFileName: () => ts.getDefaultLibFileName(compilerOptions), - getDirectories: (dir) => fs.readdirSync(dir), + getDirectories: dir => fs.readdirSync(dir), getNewLine: () => "\n", getSourceFile(filenameToGet, target) { if (denormalizeWinPath(filenameToGet) === fileCompileName) { - return ts.createSourceFile(filenameToGet, fileTextWithoutMarkup, target, true); + return ts.createSourceFile( + filenameToGet, + fileTextWithoutMarkup, + target, + true, + ); } if (path.basename(filenameToGet) === filenameToGet) { // resolve path of lib.xxx.d.ts - filenameToGet = path.join(path.dirname(ts.getDefaultLibFilePath(compilerOptions)), filenameToGet); + filenameToGet = path.join( + path.dirname(ts.getDefaultLibFilePath(compilerOptions)), + filenameToGet, + ); } const text = fs.readFileSync(filenameToGet, "utf8"); return ts.createSourceFile(filenameToGet, text, target, true); }, - readFile: (x) => x, + readFile: x => x, useCaseSensitiveFileNames: () => true, writeFile: () => null, }; @@ -147,9 +161,13 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ }; const linter = new Linter(lintOptions, program); // Need to use the true path (ending in '.lint') for "encoding" rule so that it can read the file. - linter.lint(isEncodingRule ? fileToLint : fileCompileName, fileTextWithoutMarkup, tslintConfig); + linter.lint( + isEncodingRule ? fileToLint : fileCompileName, + fileTextWithoutMarkup, + tslintConfig, + ); const failures = linter.getResult().failures; - const errorsFromLinter: LintError[] = failures.map((failure) => { + const errorsFromLinter: LintError[] = failures.map(failure => { const startLineAndCharacter = failure.getStartPosition().getLineAndCharacter(); const endLineAndCharacter = failure.getEndPosition().getLineAndCharacter(); @@ -174,7 +192,7 @@ export function runTest(testDirectory: string, rulesDirectory?: string | string[ const stat = fs.statSync(fixedFile); if (stat.isFile()) { fixedFileText = fs.readFileSync(fixedFile, "utf8"); - const fixes = mapDefined(failures, (f) => f.getFix()); + const fixes = mapDefined(failures, f => f.getFix()); newFileText = Replacement.applyFixes(fileTextWithoutMarkup, fixes); } } catch (e) { @@ -221,10 +239,20 @@ export function consoleTestResultHandler(testResult: TestResult, logger: Logger) if (results.skipped) { logger.log(chalk.yellow(` Skipped, requires typescript ${results.requirement}\n`)); } else { - const markupDiffResults = diff.diffLines(results.markupFromMarkup, results.markupFromLinter); - const fixesDiffResults = diff.diffLines(results.fixesFromLinter, results.fixesFromMarkup); - const didMarkupTestPass = !markupDiffResults.some((hunk) => hunk.added === true || hunk.removed === true); - const didFixesTestPass = !fixesDiffResults.some((hunk) => hunk.added === true || hunk.removed === true); + const markupDiffResults = diff.diffLines( + results.markupFromMarkup, + results.markupFromLinter, + ); + const fixesDiffResults = diff.diffLines( + results.fixesFromLinter, + results.fixesFromMarkup, + ); + const didMarkupTestPass = !markupDiffResults.some( + hunk => hunk.added === true || hunk.removed === true, + ); + const didFixesTestPass = !fixesDiffResults.some( + hunk => hunk.added === true || hunk.removed === true, + ); if (didMarkupTestPass && didFixesTestPass) { logger.log(chalk.green(" Passed\n")); @@ -258,9 +286,18 @@ function displayDiffResults(diffResults: diff.IDiffResult[], extension: string, color = chalk.red.underline; prefix = "- "; } - logger.log(color(diffResult.value.split(/\r\n|\r|\n/) - // strings end on a newline which we do not want to include the prefix. - // tslint:disable-next-line:prefer-template - .map((line, index, array) => index === array.length - 1 ? line : prefix + line + "\n").join(""))); + logger.log( + color( + diffResult.value + .split(/\r\n|\r|\n/) + // strings end on a newline which we do not want to include the prefix. + // tslint:disable-next-line:prefer-template + .map( + (line, index, array) => + index === array.length - 1 ? line : `${prefix}${line}\n`, + ) + .join(""), + ), + ); } } diff --git a/src/tslintCli.ts b/src/tslintCli.ts index 6d22b3cf0ac..179c09cbf96 100644 --- a/src/tslintCli.ts +++ b/src/tslintCli.ts @@ -122,7 +122,7 @@ const options: Option[] = [ { short: "r", name: "rules-dir", - type: "string", + type: "array", describe: "rules directory", description: dedent` An additional rules directory, for user-created rules. @@ -148,7 +148,8 @@ const options: Option[] = [ short: "t", name: "format", type: "string", - describe: "output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist, codeFrame)", + describe: + "output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist, codeFrame)", description: dedent` The formatter to use to format the results of the linter before outputting it to stdout or the file passed in --out. The core @@ -227,9 +228,21 @@ for (const option of options) { commander.on("--help", () => { const indent = "\n "; - const optionDetails = options.concat(builtinOptions).map((o) => - `${optionUsageTag(o)}:${o.description.startsWith("\n") ? o.description.replace(/\n/g, indent) : indent + o.description}`); - console.log(`tslint accepts the following commandline options:\n\n ${optionDetails.join("\n\n ")}\n\n`); + const optionDetails = options + .concat(builtinOptions) + .map( + o => + `${optionUsageTag(o)}:${ + o.description.startsWith("\n") + ? o.description.replace(/\n/g, indent) + : indent + o.description + }`, + ); + console.log( + `tslint accepts the following commandline options:\n\n ${optionDetails.join( + "\n\n ", + )}\n\n`, + ); }); // Hack to get unknown option errors to work. https://github.com/visionmedia/commander.js/pull/121 @@ -238,24 +251,34 @@ commander.args = parsed.args; if (parsed.unknown.length !== 0) { (commander.parseArgs as (args: string[], unknown: string[]) => void)([], parsed.unknown); } -const argv = commander.opts() as any as Argv; +const argv = (commander.opts() as any) as Argv; -if (!(argv.init || argv.test !== undefined || argv.project !== undefined || commander.args.length > 0)) { +if ( + !( + argv.init || + argv.test !== undefined || + argv.project !== undefined || + commander.args.length > 0 + ) +) { console.error("No files specified. Use --project to lint a project folder."); process.exit(1); } if (argv.typeCheck) { - console.warn("--type-check is deprecated. You only need --project to enable rules which need type information."); + console.warn( + "--type-check is deprecated. You only need --project to enable rules which need type information.", + ); if (argv.project === undefined) { console.error("--project must be specified in order to enable type checking."); process.exit(1); } } -const outputStream: NodeJS.WritableStream = argv.out === undefined - ? process.stdout - : fs.createWriteStream(argv.out, {flags: "w+", mode: 420}); +const outputStream: NodeJS.WritableStream = + argv.out === undefined + ? process.stdout + : fs.createWriteStream(argv.out, { flags: "w+", mode: 420 }); run( { @@ -264,7 +287,7 @@ run( files: arrayify(commander.args), fix: argv.fix, force: argv.force, - format: argv.format === undefined ? "prose" : argv.format, + format: argv.format, formattersDirectory: argv.formattersDir, init: argv.init, out: argv.out, @@ -280,17 +303,19 @@ run( outputStream.write(m); }, error(m) { - process.stdout.write(m); + process.stderr.write(m); }, - }) - .then((rc) => { + }, +) + .then(rc => { process.exitCode = rc; - }).catch((e) => { + }) + .catch(e => { console.error(e); process.exitCode = 1; }); -function optionUsageTag({short, name}: Option) { +function optionUsageTag({ short, name }: Option) { return short !== undefined ? `-${short}, --${name}` : `--${name}`; } diff --git a/src/utils.ts b/src/utils.ts index 46e55eece35..c5bfbb08b5f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -49,7 +49,9 @@ export function hasOwnProperty(arg: {}, key: string): boolean { * E.g. "foo-bar" -> "fooBar" */ export function camelize(stringWithHyphens: string): string { - return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => (nextLetter as string).toUpperCase()); + return stringWithHyphens.replace(/-(.)/g, (_, nextLetter) => + (nextLetter as string).toUpperCase(), + ); } export function isUpperCase(str: string): boolean { @@ -65,7 +67,8 @@ export function isLowerCase(str: string): boolean { */ export function dedent(strings: TemplateStringsArray, ...values: any[]) { let fullString = strings.reduce( - (accumulator, str, i) => `${accumulator}${values[i - 1]}${str}`); + (accumulator, str, i) => `${accumulator}${values[i - 1]}${str}`, + ); // match all leading spaces/tabs at the start of each line const match = fullString.match(/^[ \t]*(?=\S)/gm); @@ -75,7 +78,7 @@ export function dedent(strings: TemplateStringsArray, ...values: any[]) { } // find the smallest indent, we don't want to remove all leading whitespace - const indent = Math.min(...match.map((el) => el.length)); + const indent = Math.min(...match.map(el => el.length)); const regexp = new RegExp(`^[ \\t]{${indent}}`, "gm"); fullString = indent > 0 ? fullString.replace(regexp, "") : fullString; return fullString; @@ -92,24 +95,27 @@ export function stripComments(content: string): string { * Fourth matches line comments */ const regexp: RegExp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; - const result = content.replace(regexp, (match: string, _m1: string, _m2: string, m3: string, m4: string) => { - // Only one of m1, m2, m3, m4 matches - if (m3 !== undefined) { - // A block comment. Replace with nothing - return ""; - } else if (m4 !== undefined) { - // A line comment. If it ends in \r?\n then keep it. - const length = m4.length; - if (length > 2 && m4[length - 1] === "\n") { - return m4[length - 2] === "\r" ? "\r\n" : "\n"; - } else { + const result = content.replace( + regexp, + (match: string, _m1: string, _m2: string, m3: string, m4: string) => { + // Only one of m1, m2, m3, m4 matches + if (m3 !== undefined) { + // A block comment. Replace with nothing return ""; + } else if (m4 !== undefined) { + // A line comment. If it ends in \r?\n then keep it. + const length = m4.length; + if (length > 2 && m4[length - 1] === "\n") { + return m4[length - 2] === "\r" ? "\r\n" : "\n"; + } else { + return ""; + } + } else { + // We match a string + return match; } - } else { - // We match a string - return match; - } - }); + }, + ); return result; } @@ -123,8 +129,18 @@ export function escapeRegExp(re: string): string { /** Return true if both parameters are equal. */ export type Equal = (a: T, b: T) => boolean; -export function arraysAreEqual(a: ReadonlyArray | undefined, b: ReadonlyArray | undefined, eq: Equal): boolean { - return a === b || a !== undefined && b !== undefined && a.length === b.length && a.every((x, idx) => eq(x, b[idx])); +export function arraysAreEqual( + a: ReadonlyArray | undefined, + b: ReadonlyArray | undefined, + eq: Equal, +): boolean { + return ( + a === b || + (a !== undefined && + b !== undefined && + a.length === b.length && + a.every((x, idx) => eq(x, b[idx]))) + ); } /** Returns the first non-`undefined` result. */ @@ -139,7 +155,10 @@ export function find(inputs: T[], getResult: (t: T) => U | undefined): U | } /** Returns an array that is the concatenation of all output arrays. */ -export function flatMap(inputs: ReadonlyArray, getOutputs: (input: T, index: number) => ReadonlyArray): U[] { +export function flatMap( + inputs: ReadonlyArray, + getOutputs: (input: T, index: number) => ReadonlyArray, +): U[] { const out = []; for (let i = 0; i < inputs.length; i++) { out.push(...getOutputs(inputs[i], i)); @@ -148,7 +167,10 @@ export function flatMap(inputs: ReadonlyArray, getOutputs: (input: T, i } /** Returns an array of all outputs that are not `undefined`. */ -export function mapDefined(inputs: ReadonlyArray, getOutput: (input: T) => U | undefined): U[] { +export function mapDefined( + inputs: ReadonlyArray, + getOutput: (input: T) => U | undefined, +): U[] { const out = []; for (const input of inputs) { const output = getOutput(input); @@ -188,20 +210,20 @@ export function detectBufferEncoding(buffer: Buffer, length = buffer.length): En } switch (buffer[0]) { - case 0xEF: - if (buffer[1] === 0xBB && length >= 3 && buffer[2] === 0xBF) { + case 0xef: + if (buffer[1] === 0xbb && length >= 3 && buffer[2] === 0xbf) { return "utf8-bom"; } break; - case 0xFE: - if (buffer[1] === 0xFF) { + case 0xfe: + if (buffer[1] === 0xff) { return "utf16be"; } break; - case 0xFF: - if (buffer[1] === 0xFE) { + case 0xff: + if (buffer[1] === 0xfe) { return "utf16le"; } } @@ -222,12 +244,20 @@ export function isCamelCased(name: string): boolean { return isLowerCase(name[0]) && !name.includes("_") && !name.includes("-"); } -export function isKebabCased(name: string): boolean { +function isSeparatorCased(name: string, disallowedSeparator: string): boolean { for (let i = 0; i < name.length; i++) { const c = name.charAt(i); - if (c === "_" || !isLowerCase(c)) { + if (c === disallowedSeparator || !isLowerCase(c)) { return false; } } return true; } + +export function isKebabCased(name: string): boolean { + return isSeparatorCased(name, "_"); +} + +export function isSnakeCased(name: string): boolean { + return isSeparatorCased(name, "-"); +} diff --git a/test/config/tslint-custom-rules-with-dir-and-format.json b/test/config/tslint-custom-rules-with-dir-and-format.json new file mode 100644 index 00000000000..d94a8029a35 --- /dev/null +++ b/test/config/tslint-custom-rules-with-dir-and-format.json @@ -0,0 +1,16 @@ +{ + "rulesDirectory": "../files/custom-rules/", + "jsRules": { + "always-fail": { + "severity": "error" + } + }, + "rules": { + "always-fail": { + "severity": "error" + } + }, + "linterOptions": { + "format": "tslint-test-custom-formatter" + } +} diff --git a/test/configurationTests.ts b/test/configurationTests.ts index 3d98ef68609..e2d0db5616d 100644 --- a/test/configurationTests.ts +++ b/test/configurationTests.ts @@ -33,8 +33,7 @@ import { createTempFile } from "./utils"; describe("Configuration", () => { describe("parseConfigFile", () => { it("parses empty config", () => { - const rawConfig = { - }; + const rawConfig = {}; const expected = getEmptyConfig(); assertConfigEquals(parseConfigFile(rawConfig), expected); }); @@ -57,10 +56,10 @@ describe("Configuration", () => { d: [false], e: [true, 1], f: [false, 2, 3], - g: { severity: "off"}, - h: { severity: "warn"}, - i: { severity: "warning"}, - j: { severity: "error"}, + g: { severity: "off" }, + h: { severity: "warn" }, + i: { severity: "warning" }, + j: { severity: "error" }, k: { severity: "none" }, l: { options: 1 }, m: { options: [2] }, @@ -112,12 +111,56 @@ describe("Configuration", () => { exclude: ["foo.ts", "**/*.d.ts"], }, }; - assert.deepEqual( - parseConfigFile(config, "/path").linterOptions, - { - exclude: [path.resolve("/path", "foo.ts"), path.resolve("/path", "**/*.d.ts")], + assert.deepEqual(parseConfigFile(config, "/path").linterOptions, { + exclude: [path.resolve("/path", "foo.ts"), path.resolve("/path", "**/*.d.ts")], + }); + }); + + it("parses jsRules when jsRules is a config", () => { + const rawConfig: RawConfigFile = { + jsRules: { + a: true, }, - ); + }; + + const expected = getEmptyConfig(); + expected.jsRules.set("a", { ruleArguments: [], ruleSeverity: "error" }); + assertConfigEquals(parseConfigFile(rawConfig), expected); + }); + + it("copies valid rules to jsRules when jsRules is a boolean", () => { + let rawConfig: RawConfigFile = { + jsRules: true, + rules: {}, + }; + + const expected = getEmptyConfig(); + assertConfigEquals(parseConfigFile(rawConfig), expected); + + rawConfig = { + jsRules: true, + rules: { + eofline: true, + }, + }; + + let { rules, jsRules } = parseConfigFile(rawConfig); + assert.deepEqual(demap(rules), demap(jsRules)); + + rawConfig = { + jsRules: true, + rules: { + eofline: true, + typedef: true, + }, + }; + + ({ rules, jsRules } = parseConfigFile(rawConfig)); + assert(jsRules.has("eofline")); + assert(!jsRules.has("typedef")); + + rules.delete("typedef"); + assert.deepEqual(demap(rules), demap(jsRules)); }); }); @@ -162,11 +205,11 @@ describe("Configuration", () => { const config = getEmptyConfig(); config.jsRules.set("row", { ruleArguments: ["oar", "column"] }); config.rules.set("foo", { ruleSeverity: "off" }); - config.linterOptions = { }; + config.linterOptions = {}; assertConfigEquals(extendConfigurationFile(EMPTY_CONFIG, config), config); }); - it ("unions values", () => { + it("unions values", () => { const baseConfig = getEmptyConfig(); baseConfig.rules.set("foo", { ruleArguments: ["bar"], ruleSeverity: "off" }); baseConfig.jsRules.set("row", { ruleArguments: ["oar", "column"] }); @@ -174,21 +217,27 @@ describe("Configuration", () => { const extendingConfig = getEmptyConfig(); extendingConfig.rules.set("flow", { ruleArguments: ["river"] }); - extendingConfig.jsRules.set("good", { ruleArguments: ["does"], ruleSeverity: "warning" }); + extendingConfig.jsRules.set("good", { + ruleArguments: ["does"], + ruleSeverity: "warning", + }); extendingConfig.rulesDirectory = ["baz"]; const expectedConfig = getEmptyConfig(); expectedConfig.rules.set("foo", { ruleArguments: ["bar"], ruleSeverity: "off" }); expectedConfig.rules.set("flow", { ruleArguments: ["river"] }); expectedConfig.jsRules.set("row", { ruleArguments: ["oar", "column"] }); - expectedConfig.jsRules.set("good", { ruleArguments: ["does"], ruleSeverity: "warning" }); + expectedConfig.jsRules.set("good", { + ruleArguments: ["does"], + ruleSeverity: "warning", + }); expectedConfig.rulesDirectory = ["foo", "baz"]; const actualConfig = extendConfigurationFile(baseConfig, extendingConfig); assertConfigEquals(actualConfig, expectedConfig); }); - it ("overrides values", () => { + it("overrides values", () => { const baseConfig = getEmptyConfig(); baseConfig.rules.set("foo", { ruleArguments: ["bar"], ruleSeverity: "off" }); baseConfig.jsRules.set("row", { ruleArguments: ["oar", "column"] }); @@ -216,18 +265,12 @@ describe("Configuration", () => { const extendingConfig = getEmptyConfig(); extendingConfig.linterOptions = { - exclude: [ - "lib", - "bin", - ], + exclude: ["lib", "bin"], }; const expectedConfig = getEmptyConfig(); expectedConfig.linterOptions = { - exclude: [ - "lib", - "bin", - ], + exclude: ["lib", "bin"], }; const actualConfig = extendConfigurationFile(baseConfig, extendingConfig); @@ -253,59 +296,76 @@ describe("Configuration", () => { }); it("overrides defaultSeverity of base configs", () => { - const config = loadConfigurationFromPath("./test/config/tslint-extends-default-severity.json"); + const config = loadConfigurationFromPath( + "./test/config/tslint-extends-default-severity.json", + ); assert.equal( config.rules.get("default-severity-unspecified")!.ruleSeverity, "warning", - "should apply defaultSeverity to base config with no defaultSeverity"); + "should apply defaultSeverity to base config with no defaultSeverity", + ); assert.equal( config.rules.get("default-severity-error")!.ruleSeverity, "warning", - "should override defaultSeverity defined in base config"); + "should override defaultSeverity defined in base config", + ); assert.equal( config.rules.get("default-severity-warning")!.ruleSeverity, "warning", - "should apply defaultSeverity to extending config"); + "should apply defaultSeverity to extending config", + ); }); it("inherits defaultSeverity from base config if not specified", () => { - const config = loadConfigurationFromPath("./test/config/tslint-extends-default-severity-only-in-extended.json"); + const config = loadConfigurationFromPath( + "./test/config/tslint-extends-default-severity-only-in-extended.json", + ); assert.equal( config.rules.get("default-severity-unspecified")!.ruleSeverity, "warning", - "should apply defaultSeverity to base config with no defaultSeverity"); + "should apply defaultSeverity to base config with no defaultSeverity", + ); assert.equal( config.rules.get("default-severity-error")!.ruleSeverity, "warning", - "should override defaultSeverity defined in base config"); + "should override defaultSeverity defined in base config", + ); assert.equal( config.rules.get("default-severity-warning")!.ruleSeverity, "warning", - "should apply defaultSeverity to extending config"); + "should apply defaultSeverity to extending config", + ); assert.equal( config.rules.get("default-severity-only-in-extended")!.ruleSeverity, "warning", - "should inherit defaultSeverity from base configs"); + "should inherit defaultSeverity from base configs", + ); }); it("applies defaultSeverity to preceding base configs", () => { - const config = loadConfigurationFromPath("./test/config/tslint-extends-default-severity-precedence.json"); + const config = loadConfigurationFromPath( + "./test/config/tslint-extends-default-severity-precedence.json", + ); assert.equal( config.rules.get("default-severity-unspecified")!.ruleSeverity, "off", - "should apply defaultSeverity to base config with no defaultSeverity"); + "should apply defaultSeverity to base config with no defaultSeverity", + ); assert.equal( config.rules.get("default-severity-error")!.ruleSeverity, "off", - "should override defaultSeverity defined in preceding base config"); + "should override defaultSeverity defined in preceding base config", + ); assert.equal( config.rules.get("default-severity-warning")!.ruleSeverity, "off", - "should override defaultSeverity defined in preceding base config"); + "should override defaultSeverity defined in preceding base config", + ); assert.equal( config.rules.get("default-severity-off")!.ruleSeverity, "off", - "should not override last declared defaultSeverity"); + "should not override last declared defaultSeverity", + ); }); }); @@ -349,13 +409,21 @@ describe("Configuration", () => { assert.equal( "error", config.rules.get("no-fail")!.ruleSeverity, - "should pick up 'no-fail' in base config"); + "should pick up 'no-fail' in base config", + ); assert.equal( "off", config.rules.get("always-fail")!.ruleSeverity, - "should set 'always-fail' in top config"); - assert.equal("error", config.jsRules.get("no-fail")!.ruleSeverity); - assert.equal("off", config.jsRules.get("always-fail")!.ruleSeverity); + "should set 'always-fail' in top config", + ); + assert.equal( + "error", + config.jsRules.get("no-fail")!.ruleSeverity, + ); + assert.equal( + "off", + config.jsRules.get("always-fail")!.ruleSeverity, + ); }); it("extends with package", () => { @@ -370,7 +438,9 @@ describe("Configuration", () => { }); it("extends with package - boolean configuration", () => { - const config = loadConfigurationFromPath("./test/config/tslint-extends-package-boolean.json"); + const config = loadConfigurationFromPath( + "./test/config/tslint-extends-package-boolean.json", + ); const expectedConfig = getEmptyConfig(); expectedConfig.rules.set("rule-one", { ruleSeverity: "error" }); expectedConfig.rules.set("rule-two", { ruleSeverity: "error" }); @@ -381,17 +451,24 @@ describe("Configuration", () => { }); it("extends only severity or only arguments", () => { - const config = loadConfigurationFromPath("./test/config/tslint-extends-package-partial.json"); + const config = loadConfigurationFromPath( + "./test/config/tslint-extends-package-partial.json", + ); const expectedConfig = getEmptyConfig(); expectedConfig.rules.set("always-fail", { ruleSeverity: "error", ruleArguments: [2] }); - expectedConfig.jsRules.set("always-fail", { ruleSeverity: "warning", ruleArguments: [1] }); + expectedConfig.jsRules.set("always-fail", { + ruleArguments: [1], + ruleSeverity: "warning", + }); assertConfigEquals(config.jsRules, expectedConfig.jsRules); assertConfigEquals(config.rules, expectedConfig.rules); }); it("extends with package without customization", () => { - const config = loadConfigurationFromPath("./test/config/tslint-extends-package-no-mod.json"); + const config = loadConfigurationFromPath( + "./test/config/tslint-extends-package-no-mod.json", + ); const expectedConfig = getEmptyConfig(); expectedConfig.rules.set("rule-one", { ruleSeverity: "error" }); expectedConfig.rules.set("rule-two", { ruleSeverity: "off" }); @@ -403,19 +480,36 @@ describe("Configuration", () => { it("extends with builtin", () => { const config = loadConfigurationFromPath("./test/config/tslint-extends-builtin.json"); assert.isUndefined(config.jsRules.get("no-var-keyword")); - assert.equal("off", config.jsRules.get("no-eval")!.ruleSeverity); - assert.equal("error", config.rules.get("no-var-keyword")!.ruleSeverity); - assert.equal("off", config.rules.get("no-eval")!.ruleSeverity); + assert.equal( + "off", + config.jsRules.get("no-eval")!.ruleSeverity, + ); + assert.equal( + "error", + config.rules.get("no-var-keyword")!.ruleSeverity, + ); + assert.equal( + "off", + config.rules.get("no-eval")!.ruleSeverity, + ); }); it("resolve rule directory from package", () => { - const config = loadConfigurationFromPath("./test/config/tslint-custom-rules-with-package.json"); - assert.deepEqual(config.rulesDirectory, [path.join(process.cwd(), "test/config/node_modules/tslint-test-custom-rules/rules")]); + const config = loadConfigurationFromPath( + "./test/config/tslint-custom-rules-with-package.json", + ); + assert.deepEqual(config.rulesDirectory, [ + path.join(process.cwd(), "test/config/node_modules/tslint-test-custom-rules/rules"), + ]); }); it("resolve rule directory from package fallback", () => { - const config = loadConfigurationFromPath("./test/config/tslint-custom-rules-with-package-fallback.json"); - assert.deepEqual(config.rulesDirectory, [path.join(process.cwd(), "test/config/relative-rules-directory")]); + const config = loadConfigurationFromPath( + "./test/config/tslint-custom-rules-with-package-fallback.json", + ); + assert.deepEqual(config.rulesDirectory, [ + path.join(process.cwd(), "test/config/relative-rules-directory"), + ]); }); describe("with config not relative to tslint", () => { @@ -432,7 +526,10 @@ describe("Configuration", () => { }); it("extends with package installed relative to tslint", () => { - fs.writeFileSync(tmpfile!, JSON.stringify({ extends: "tslint-test-config-non-relative" })); + fs.writeFileSync( + tmpfile!, + JSON.stringify({ extends: "tslint-test-config-non-relative" }), + ); const config = loadConfigurationFromPath(tmpfile!); const expectedConfig = getEmptyConfig(); @@ -442,7 +539,9 @@ describe("Configuration", () => { }); it("extends with package two levels (and relative path in rulesDirectory)", () => { - const config = loadConfigurationFromPath("./test/config/tslint-extends-package-two-levels.json"); + const config = loadConfigurationFromPath( + "./test/config/tslint-extends-package-two-levels.json", + ); assert.lengthOf(config.rulesDirectory, 2); assert.isTrue(fs.existsSync(config.rulesDirectory[0])); @@ -459,7 +558,9 @@ describe("Configuration", () => { }); it("extends with array", () => { - const config = loadConfigurationFromPath("./test/config/tslint-extends-package-array.json"); + const config = loadConfigurationFromPath( + "./test/config/tslint-extends-package-array.json", + ); const expectedConfig = getEmptyConfig(); expectedConfig.rules.set("always-fail", { ruleSeverity: "off" }); @@ -476,15 +577,23 @@ describe("Configuration", () => { const expectedConfig = getEmptyConfig(); expectedConfig.rules.set("rule-two", { ruleSeverity: "error" }); - expectedConfig.rules.set("rule-three", { ruleSeverity: "error", ruleArguments: ["//not a comment"] }); - expectedConfig.rules.set("rule-four", { ruleSeverity: "error", ruleArguments: ["/*also not a comment*/"] }); + expectedConfig.rules.set("rule-three", { + ruleArguments: ["//not a comment"], + ruleSeverity: "error", + }); + expectedConfig.rules.set("rule-four", { + ruleArguments: ["/*also not a comment*/"], + ruleSeverity: "error", + }); assertConfigEquals(config.rules, expectedConfig.rules); assertConfigEquals(config.jsRules, expectedConfig.rules); }); it("can load .json files with BOM", () => { - assert.doesNotThrow(() => loadConfigurationFromPath("./test/config/tslint-with-bom.json")); + assert.doesNotThrow(() => + loadConfigurationFromPath("./test/config/tslint-with-bom.json"), + ); }); it("can load .yaml files with comments", () => { @@ -492,7 +601,10 @@ describe("Configuration", () => { const expectedConfig = getEmptyConfig(); expectedConfig.rules.set("rule-two", { ruleSeverity: "error" }); - expectedConfig.rules.set("rule-three", { ruleSeverity: "error", ruleArguments: ["#not a comment"] }); + expectedConfig.rules.set("rule-three", { + ruleArguments: ["#not a comment"], + ruleSeverity: "error", + }); assertConfigEquals(config.rules, expectedConfig.rules); assertConfigEquals(config.jsRules, expectedConfig.rules); @@ -500,8 +612,14 @@ describe("Configuration", () => { it("can load a built-in configuration", () => { const config = loadConfigurationFromPath("tslint:recommended"); - assert.strictEqual("error", config.jsRules.get("no-eval")!.ruleSeverity); - assert.strictEqual("error", config.rules.get("no-eval")!.ruleSeverity); + assert.strictEqual( + "error", + config.jsRules.get("no-eval")!.ruleSeverity, + ); + assert.strictEqual( + "error", + config.rules.get("no-eval")!.ruleSeverity, + ); }); it("throws on an invalid built-in configuration path", () => { diff --git a/test/executable/executableTests.ts b/test/executable/executableTests.ts index a5affd2b29f..8eaa263790d 100644 --- a/test/executable/executableTests.ts +++ b/test/executable/executableTests.ts @@ -134,18 +134,40 @@ describe("Executable", function(this: Mocha.ISuiteCallbackContext) { }); describe("Custom formatters", () => { - it("can be loaded from node_modules", (done) => { + const createFormatVerifier = (done: MochaDone): ExecFileCallback => (err, stdout) => { + assert.isNotNull(err, "process should exit with error"); + assert.strictEqual(err.code, 2, "error code should be 2"); + assert.include( + stdout, + "hello from custom formatter", + "stdout should contain output of custom formatter" + ); + done(); + }; + + it("can be loaded from node_modules", done => { execCli( - ["-c", "tslint-custom-rules-with-dir.json", "../../src/test.ts", "-t", "tslint-test-custom-formatter"], + [ + "-c", + "tslint-custom-rules-with-dir.json", + "../../src/test.ts", + "-t", + "tslint-test-custom-formatter" + ], { - cwd: "./test/config", + cwd: "./test/config" }, - (err, stdout) => { - assert.isNotNull(err, "process should exit with error"); - assert.strictEqual(err.code, 2, "error code should be 2"); - assert.include(stdout, "hello from custom formatter", "stdout should contain output of custom formatter"); - done(); + createFormatVerifier(done) + ); + }); + + it("can be specified from config", done => { + execCli( + ["-c", "tslint-custom-rules-with-dir-and-format.json", "../../src/test.ts"], + { + cwd: "./test/config" }, + createFormatVerifier(done) ); }); }); diff --git a/test/formatters/proseFormatterTests.ts b/test/formatters/proseFormatterTests.ts index dba8545012f..e111f94c70b 100644 --- a/test/formatters/proseFormatterTests.ts +++ b/test/formatters/proseFormatterTests.ts @@ -38,7 +38,15 @@ describe("Prose Formatter", () => { const failures = [ createFailure(sourceFile, 0, 1, "first failure", "first-name", undefined, "error"), createFailure(sourceFile, 32, 36, "mid failure", "mid-name", undefined, "error"), - createFailure(sourceFile, maxPosition - 1, maxPosition, "last failure", "last-name", undefined, "warning"), + createFailure( + sourceFile, + maxPosition - 1, + maxPosition, + "last failure", + "last-name", + undefined, + "warning", + ), ]; const expectedResult = dedent` @@ -55,7 +63,7 @@ describe("Prose Formatter", () => { createFailure(sourceFile, 0, 1, "first failure", "first-name", undefined, "error"), ]; - const mockFix = { getFileName: () => "file2" } as any as RuleFailure; // tslint:disable-line no-object-literal-type-assertion + const mockFix = ({ getFileName: () => "file2" } as any) as RuleFailure; // tslint:disable-line no-object-literal-type-assertion const fixes = [ createFailure(sourceFile, 0, 1, "first failure", "first-name", undefined, "error"), @@ -79,6 +87,6 @@ describe("Prose Formatter", () => { }); function getPositionString(line: number, character: number) { - return `[${line}, ${character}]: `; + return `:${line}:${character} - `; } }); diff --git a/test/lint.ts b/test/lint.ts index b3336b4473d..fb167f455e2 100644 --- a/test/lint.ts +++ b/test/lint.ts @@ -19,4 +19,4 @@ export * from "../src/index"; import * as TestUtils from "./utils"; -export {TestUtils}; +export { TestUtils }; diff --git a/test/linterTests.ts b/test/linterTests.ts index 73a040f899c..05a50f95707 100644 --- a/test/linterTests.ts +++ b/test/linterTests.ts @@ -30,7 +30,7 @@ class TestLinter extends Linter { } const componentDeclaration = (templateUrl: string) => -`import { Component } from '@angular/component'; + `import { Component } from '@angular/component'; @Component({ selector: 'foo-bar', @@ -39,32 +39,39 @@ const componentDeclaration = (templateUrl: string) => class SampleComponent {} `; -const templateDeclaration = -` +const templateDeclaration = `
{{ foo }}
`; -const templateDeclarationFixed = -` +const templateDeclarationFixed = `
`; -const withWarningDeclaration = -` +const withWarningDeclaration = ` console.log("This line will not pass linting with the default rule set"); `; describe("Linter", () => { - it("apply fixes to correct files", () => { const linter = new TestLinter({ fix: true }); const componentFile = createTempFile("ts"); const templateFile = createTempFile("ts"); fs.writeFileSync(componentFile, componentDeclaration(templateFile)); fs.writeFileSync(templateFile, templateDeclaration); - const sourceFile = createSourceFile(templateFile, `${templateDeclaration}`, ScriptTarget.ES2015); + const sourceFile = createSourceFile( + templateFile, + `${templateDeclaration}`, + ScriptTarget.ES2015, + ); const replacement = new Replacement(6, 9, ""); - const failure = new RuleFailure(sourceFile, 6, 15, "Declaration doesn't exist", "foo-bar", replacement); + const failure = new RuleFailure( + sourceFile, + 6, + 15, + "Declaration doesn't exist", + "foo-bar", + replacement, + ); linter.applyFixesHelper(componentFile, componentDeclaration(templateFile), [failure]); assert.equal(fs.readFileSync(templateFile, "utf-8"), templateDeclarationFixed); }); diff --git a/test/ruleLoaderTests.ts b/test/ruleLoaderTests.ts index 3d101b65c67..a780290e816 100644 --- a/test/ruleLoaderTests.ts +++ b/test/ruleLoaderTests.ts @@ -30,11 +30,31 @@ const testRulesDir = "test/rules"; describe("Rule Loader", () => { it("loads core rules", () => { const validConfiguration: IOptions[] = [ - { ruleName: "class-name", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "eofline", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "class-name", + ruleSeverity: "error", + }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "eofline", + ruleSeverity: "error", + }, { ruleName: "forin", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "no-debugger", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "quotemark", ruleArguments: ["double"], ruleSeverity: "error", disabledIntervals: [] }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "no-debugger", + ruleSeverity: "error", + }, + { + disabledIntervals: [], + ruleArguments: ["double"], + ruleName: "quotemark", + ruleSeverity: "error", + }, ]; const rules = loadRules(validConfiguration, builtRulesDir); @@ -51,9 +71,24 @@ describe("Rule Loader", () => { it("ignores invalid rules", () => { const invalidConfiguration: IOptions[] = [ - { ruleName: "class-name", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "invalidConfig1", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "invalidConfig2", ruleArguments: [], ruleSeverity: "off", disabledIntervals: [] }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "class-name", + ruleSeverity: "error", + }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "invalidConfig1", + ruleSeverity: "error", + }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "invalidConfig2", + ruleSeverity: "off", + }, ]; const rules = loadRules(invalidConfiguration, [builtRulesDir]); @@ -62,8 +97,18 @@ describe("Rule Loader", () => { it("properly sets rule severity with options", () => { const withOptions: IOptions[] = [ - { ruleName: "callable-types", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "max-line-length", ruleArguments: [140], ruleSeverity: "warning", disabledIntervals: [] }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "callable-types", + ruleSeverity: "error", + }, + { + disabledIntervals: [], + ruleArguments: [140], + ruleName: "max-line-length", + ruleSeverity: "warning", + }, ]; const rules = loadRules(withOptions, [builtRulesDir]); @@ -74,11 +119,31 @@ describe("Rule Loader", () => { it("works with rulesDirectory argument as an Array", () => { const validConfiguration: IOptions[] = [ - { ruleName: "class-name", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "eofline", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "class-name", + ruleSeverity: "error", + }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "eofline", + ruleSeverity: "error", + }, { ruleName: "forin", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "no-debugger", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "quotemark", ruleArguments: ["double"], ruleSeverity: "error", disabledIntervals: [] }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "no-debugger", + ruleSeverity: "error", + }, + { + disabledIntervals: [], + ruleArguments: ["double"], + ruleName: "quotemark", + ruleSeverity: "error", + }, ]; const rules = loadRules(validConfiguration, [builtRulesDir]); @@ -87,8 +152,18 @@ describe("Rule Loader", () => { it("loads rules for JS files, excluding typescript-only ones", () => { const validConfiguration: IOptions[] = [ - { ruleName: "class-name", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, - { ruleName: "await-promise", ruleArguments: [], ruleSeverity: "error", disabledIntervals: [] }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "class-name", + ruleSeverity: "error", + }, + { + disabledIntervals: [], + ruleArguments: [], + ruleName: "await-promise", + ruleSeverity: "error", + }, ]; const rules = loadRules(validConfiguration, builtRulesDir, true); @@ -96,17 +171,25 @@ describe("Rule Loader", () => { }); it("tests exist for every rule", () => { - const tests = fs.readdirSync(testRulesDir) - .filter((file) => !file.startsWith("_") && fs.statSync(path.join(testRulesDir, file)).isDirectory()) + const tests = fs + .readdirSync(testRulesDir) + .filter( + file => + !file.startsWith("_") && + fs.statSync(path.join(testRulesDir, file)).isDirectory(), + ) .map(camelize) .sort(); assert.deepEqual(everyRule(), tests, "List of rules doesn't match list of tests"); }); it("includes every rule in 'tslint:all'", () => { - const expectedAllRules = everyRule().filter((ruleName) => - RULES_EXCLUDED_FROM_ALL_CONFIG.indexOf(ruleName) === -1); - const tslintAllRules = Object.keys(allRules).map(camelize).sort(); + const expectedAllRules = everyRule().filter( + ruleName => RULES_EXCLUDED_FROM_ALL_CONFIG.indexOf(ruleName) === -1, + ); + const tslintAllRules = Object.keys(allRules) + .map(camelize) + .sort(); assert.deepEqual(expectedAllRules, tslintAllRules, "rule is missing in tslint:all"); }); @@ -134,8 +217,9 @@ describe("Rule Loader", () => { }); function everyRule(): string[] { - return fs.readdirSync(srcRulesDir) - .filter((file) => /Rule.ts$/.test(file)) - .map((file) => file.substr(0, file.length - "Rule.ts".length)) + return fs + .readdirSync(srcRulesDir) + .filter(file => /Rule.ts$/.test(file)) + .map(file => file.substr(0, file.length - "Rule.ts".length)) .sort(); } diff --git a/test/rules/ban-ts-ignore/test.ts.lint b/test/rules/ban-ts-ignore/test.ts.lint new file mode 100644 index 00000000000..b093491e3b0 --- /dev/null +++ b/test/rules/ban-ts-ignore/test.ts.lint @@ -0,0 +1,33 @@ +if (false) { + // @ts-ignore: Unreachable code error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Do not use "// @ts-ignore" comments because they suppress compilation errors.] + console.log("hello"); // Random comments. +} + +var x = 0; + +/// @ts-ignore Triple-slash +~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Do not use "// @ts-ignore" comments because they suppress compilation errors.] +x(); + +/// @ts-ignore +~~~~~~~~~~~~~~ [Do not use "// @ts-ignore" comments because they suppress compilation errors.] +x( + 2, + 3); + +// come comment + +// @ts-ignore Multiple comments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Do not use "// @ts-ignore" comments because they suppress compilation errors.] + +// some other comment + +// @anohter + +x(); + +x( // @ts-ignore inline + ~~~~~~~~~~~~~~~~~~~~ [Do not use "// @ts-ignore" comments because they suppress compilation errors.] + 2, + 3); diff --git a/test/rules/ban-ts-ignore/tslint.json b/test/rules/ban-ts-ignore/tslint.json new file mode 100644 index 00000000000..103785c3dda --- /dev/null +++ b/test/rules/ban-ts-ignore/tslint.json @@ -0,0 +1,6 @@ +{ + "rules": { + "ban-ts-ignore": true + } + } + \ No newline at end of file diff --git a/test/rules/completed-docs/interface-members/test.ts.lint b/test/rules/completed-docs/interface-members/test.ts.lint new file mode 100644 index 00000000000..eb726b03d05 --- /dev/null +++ b/test/rules/completed-docs/interface-members/test.ts.lint @@ -0,0 +1,39 @@ +/** + * ... + */ +interface BadInterfaceMembers { + prop: number; + ~~~~~~~~~~~~~ [Documentation must exist for properties.] + method(): number; + ~~~~~~~~~~~~~~~~~ [Documentation must exist for methods.] +} + +/** + * ... + */ +interface EmptyInterfaceMembers { + /** + * + */ + prop: number; + ~~~~~~~~~~~~~ [Documentation must exist for properties.] + /** + * + */ + method(): number; + ~~~~~~~~~~~~~~~~~ [Documentation must exist for methods.] +} + +/** + * ... + */ +interface GoodInterfaceMembers { + /** + * ... + */ + prop: number; + /** + * ... + */ + method(): number; +} diff --git a/test/rules/completed-docs/interface-members/tsconfig.json b/test/rules/completed-docs/interface-members/tsconfig.json new file mode 100644 index 00000000000..744a66c893a --- /dev/null +++ b/test/rules/completed-docs/interface-members/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "module": "commonjs" + } +} diff --git a/test/rules/completed-docs/interface-members/tslint.json b/test/rules/completed-docs/interface-members/tslint.json new file mode 100644 index 00000000000..f54a6179aa8 --- /dev/null +++ b/test/rules/completed-docs/interface-members/tslint.json @@ -0,0 +1,10 @@ +{ + "rules": { + "completed-docs": [ + true, + "interfaces", + "methods", + "properties" + ] + } +} diff --git a/test/rules/completed-docs/tags/content/test.ts.lint b/test/rules/completed-docs/tags/content/test.ts.lint index 4d381365478..d0bbbc68cc3 100644 --- a/test/rules/completed-docs/tags/content/test.ts.lint +++ b/test/rules/completed-docs/tags/content/test.ts.lint @@ -7,24 +7,42 @@ const CompletelyEmptyVariable = 0; const ContentEmptyVariable = 1; ~~~~~~~~~~~~~~~~~~~~~~~~ [Documentation must exist for variables.] +/** */ +const ContentSingleLineEmptyVariable = 1; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Documentation must exist for variables.] + /** * @see */ const ContentMissingVariable = 2; ~~~~~~~~~~~~~~~~~~~~~~~~~~ [Documentation must exist for variables.] +/** @see */ +const ContentSingleLineMissingVariable = 2; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Documentation must exist for variables.] + /** * @see wat */ const ContentInvalidVariable = 3; ~~~~~~~~~~~~~~~~~~~~~~~~~~ [Documentation must exist for variables.] +/** @see wat */ +const ContentSingleLineInvalidVariable = 3; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Documentation must exist for variables.] + /** * @see #123 */ const ContentValidVariable = 4; +/** @see #123 */ +const ContentSingleLineValidVariable = 4; + /** * ... */ const CommentBodyVariableRofl = 5; + +/** ... */ +const CommentBodyVariableRofl = 5; diff --git a/test/rules/completed-docs/tags/existence/test.ts.lint b/test/rules/completed-docs/tags/existence/test.ts.lint index 924bd17fc4d..2fed3a242b2 100644 --- a/test/rules/completed-docs/tags/existence/test.ts.lint +++ b/test/rules/completed-docs/tags/existence/test.ts.lint @@ -7,17 +7,30 @@ const CompletelyEmptyVariable = 0; const ContentEmptyVariable = 1; ~~~~~~~~~~~~~~~~~~~~~~~~ [Documentation must exist for variables.] +/** */ +const ContentSingleLineEmptyVariable = 1; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [Documentation must exist for variables.] + /** * @deprecated */ const ContentMissingVariable = 2; +/** @deprecated */ +const ContentSingleLineMissingVariable = 2; + /** * @deprecated Do not use! */ const ContentValidVariable = 4; +/** @deprecated Do not use! */ +const ContentSingleLineValidVariable = 4; + /** * ... */ const CommentBodyVariable = 5; + +/** ... */ +const CommentSingleLineBodyVariable = 5; diff --git a/test/rules/completed-docs/types/test.ts.lint b/test/rules/completed-docs/types/test.ts.lint index 3a112afb1f0..00acde02843 100644 --- a/test/rules/completed-docs/types/test.ts.lint +++ b/test/rules/completed-docs/types/test.ts.lint @@ -291,6 +291,46 @@ interface EmptyInterface { } */ interface GoodInterface { } +/** + * ... + */ +interface BadInterfaceMembers { + prop: number; + ~~~~~~~~~~~~~ [Documentation must exist for properties.] + method(): number; + ~~~~~~~~~~~~~~~~~ [Documentation must exist for methods.] +} + +/** + * ... + */ +interface EmptyInterfaceMembers { + /** + * + */ + prop: number; + ~~~~~~~~~~~~~ [Documentation must exist for properties.] + /** + * + */ + method(): number; + ~~~~~~~~~~~~~~~~~ [Documentation must exist for methods.] +} + +/** + * ... + */ +interface GoodInterfaceMembers { + /** + * ... + */ + prop: number; + /** + * ... + */ + method(): number; +} + namespace BadNamespace { } ~~~~~~~~~~~~~~~~~~~~~~~~~~ [Documentation must exist for namespaces.] diff --git a/test/rules/file-header/bad-newline/test.ts.fix b/test/rules/file-header/bad-newline/test.ts.fix new file mode 100644 index 00000000000..c5133e19990 --- /dev/null +++ b/test/rules/file-header/bad-newline/test.ts.fix @@ -0,0 +1,11 @@ +/*! + * Good header 2 + */ + +export class A { + public x = 1; + + public B() { + return 2; + } +} diff --git a/test/rules/file-header/bad-newline/test.ts.lint b/test/rules/file-header/bad-newline/test.ts.lint new file mode 100644 index 00000000000..eb415cdf751 --- /dev/null +++ b/test/rules/file-header/bad-newline/test.ts.lint @@ -0,0 +1,11 @@ +/*! +~nil [missing new line following the file header] + * Good header 2 + */ +export class A { + public x = 1; + + public B() { + return 2; + } +} diff --git a/test/rules/file-header/bad-newline/tslint.json b/test/rules/file-header/bad-newline/tslint.json new file mode 100644 index 00000000000..888444210f1 --- /dev/null +++ b/test/rules/file-header/bad-newline/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "file-header": [true, "Good header \\d", "Good header 2", "enforce-trailing-newline"] + } +} diff --git a/test/rules/file-header/bad-single-newline/test.ts.fix b/test/rules/file-header/bad-single-newline/test.ts.fix new file mode 100644 index 00000000000..ae4d4867777 --- /dev/null +++ b/test/rules/file-header/bad-single-newline/test.ts.fix @@ -0,0 +1,12 @@ +/*! + * Good header 2 + */ + +// Bad header +export class A { + public x = 1; + + public B() { + return 2; + } +} diff --git a/test/rules/file-header/bad-single-newline/test.ts.lint b/test/rules/file-header/bad-single-newline/test.ts.lint new file mode 100644 index 00000000000..1ededeaf0ba --- /dev/null +++ b/test/rules/file-header/bad-single-newline/test.ts.lint @@ -0,0 +1,9 @@ +// Bad header +~nil [missing file header] +export class A { + public x = 1; + + public B() { + return 2; + } +} diff --git a/test/rules/file-header/bad-single-newline/tslint.json b/test/rules/file-header/bad-single-newline/tslint.json new file mode 100644 index 00000000000..888444210f1 --- /dev/null +++ b/test/rules/file-header/bad-single-newline/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "file-header": [true, "Good header \\d", "Good header 2", "enforce-trailing-newline"] + } +} diff --git a/test/rules/file-name-casing/snake-case/NoPascalCase.lint b/test/rules/file-name-casing/snake-case/NoPascalCase.lint new file mode 100644 index 00000000000..d37aa03d910 --- /dev/null +++ b/test/rules/file-name-casing/snake-case/NoPascalCase.lint @@ -0,0 +1,2 @@ + +~nil [File name must be snake_case] diff --git a/test/rules/file-name-casing/snake-case/no-camel-case.ts.lint b/test/rules/file-name-casing/snake-case/no-camel-case.ts.lint new file mode 100644 index 00000000000..d37aa03d910 --- /dev/null +++ b/test/rules/file-name-casing/snake-case/no-camel-case.ts.lint @@ -0,0 +1,2 @@ + +~nil [File name must be snake_case] diff --git a/test/rules/file-name-casing/snake-case/snake_case.ts.lint b/test/rules/file-name-casing/snake-case/snake_case.ts.lint new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/rules/file-name-casing/snake-case/tslint.json b/test/rules/file-name-casing/snake-case/tslint.json new file mode 100644 index 00000000000..a08000df93c --- /dev/null +++ b/test/rules/file-name-casing/snake-case/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "file-name-casing": [true, "snake-case"] + } +} diff --git a/test/rules/increment-decrement/allow-post/test.ts.fix b/test/rules/increment-decrement/allow-post/test.ts.fix new file mode 100644 index 00000000000..ebac59985d4 --- /dev/null +++ b/test/rules/increment-decrement/allow-post/test.ts.fix @@ -0,0 +1,20 @@ +let x = 7; + +x += 1; +x++; + +x -= 1; +x--; + ++x; +-x; +x + 1; +x - 1; +1 + x; +1 - x; + +x + (x += 1); +x + x++; + +x - (x -= 1); +x - x--; diff --git a/test/rules/increment-decrement/allow-post/test.ts.lint b/test/rules/increment-decrement/allow-post/test.ts.lint new file mode 100644 index 00000000000..c27629a2cdb --- /dev/null +++ b/test/rules/increment-decrement/allow-post/test.ts.lint @@ -0,0 +1,26 @@ +let x = 7; + +++x; +~~~ [plus] +x++; + +--x; +~~~ [minus] +x--; + ++x; +-x; +x + 1; +x - 1; +1 + x; +1 - x; + +x + ++x; + ~~~ [plus] +x + x++; + +x - --x; + ~~~ [minus] +x - x--; +[plus]: Use an explicit += 1 operator. +[minus]: Use an explicit -= 1 operator. diff --git a/test/rules/increment-decrement/allow-post/tslint.json b/test/rules/increment-decrement/allow-post/tslint.json new file mode 100644 index 00000000000..b0964670126 --- /dev/null +++ b/test/rules/increment-decrement/allow-post/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "increment-decrement": [true, "allow-post"] + } +} diff --git a/test/rules/increment-decrement/default/test.ts.fix b/test/rules/increment-decrement/default/test.ts.fix new file mode 100644 index 00000000000..f69f47c9056 --- /dev/null +++ b/test/rules/increment-decrement/default/test.ts.fix @@ -0,0 +1,26 @@ +let x = 7; + +x += 1; +x += 1; + +x -= 1; +x -= 1; + ++x; +-x; +x + 1; +x - 1; +1 + x; +1 - x; + +x + (x += 1); +x + (x += 1); + +x - (x -= 1); +x - (x -= 1); + +(x += 1) + x; +(x += 1) + x; + +(x -= 1) - x; +(x -= 1) - x; diff --git a/test/rules/increment-decrement/default/test.ts.lint b/test/rules/increment-decrement/default/test.ts.lint new file mode 100644 index 00000000000..203f22a705f --- /dev/null +++ b/test/rules/increment-decrement/default/test.ts.lint @@ -0,0 +1,40 @@ +let x = 7; + +++x; +~~~ [plus] +x++; +~~~ [plus] + +--x; +~~~ [minus] +x--; +~~~ [minus] + ++x; +-x; +x + 1; +x - 1; +1 + x; +1 - x; + +x + ++x; + ~~~ [plus] +x + x++; + ~~~ [plus] + +x - --x; + ~~~ [minus] +x - x--; + ~~~ [minus] + +++x + x; +~~~ [plus] +x++ + x; +~~~ [plus] + +--x - x; +~~~ [minus] +x-- - x; +~~~ [minus] +[plus]: Use an explicit += 1 operator. +[minus]: Use an explicit -= 1 operator. diff --git a/test/rules/increment-decrement/default/tslint.json b/test/rules/increment-decrement/default/tslint.json new file mode 100644 index 00000000000..42c70f0b7ab --- /dev/null +++ b/test/rules/increment-decrement/default/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "increment-decrement": true + } +} diff --git a/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.fix b/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.fix index dae2424b032..b15e40fea09 100644 --- a/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.fix +++ b/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.fix @@ -25,7 +25,6 @@ const q = { }; const t = { hello: 123, - bye-bye: 45, nested: { bird: 2, egg: 3, diff --git a/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint b/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint index b6fd76c8043..f05f6777157 100644 --- a/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint +++ b/test/rules/object-literal-key-quotes/consistent-as-needed/test.ts.lint @@ -31,7 +31,6 @@ const q = { }; const t = { hello: 123, - bye-bye: 45, nested: { "bird": 2, ~~~~~~ [Unnecessarily quoted property 'bird' found.] diff --git a/test/rules/object-literal-key-quotes/consistent/test.ts.lint b/test/rules/object-literal-key-quotes/consistent/test.ts.lint index a2ee53079b5..d6404cc432e 100644 --- a/test/rules/object-literal-key-quotes/consistent/test.ts.lint +++ b/test/rules/object-literal-key-quotes/consistent/test.ts.lint @@ -27,7 +27,6 @@ const q = { }; const t = { hello: 123, - bye-bye: 45, nested: { ~ [All property names in this object literal must be consistently quoted or unquoted.] "bird": 2, diff --git a/test/rules/whitespace/all/test.ts.fix b/test/rules/whitespace/all/test.ts.fix index 3d62a2c17f4..d0f66104ac0 100644 --- a/test/rules/whitespace/all/test.ts.fix +++ b/test/rules/whitespace/all/test.ts.fix @@ -67,6 +67,8 @@ import { importB } from "libB"; import { importC } from "libC"; import moduleD, { importD } from "libD"; import { importD, importE } from "libD"; +import { importF as F } from "libF"; +import { importF as F, importG as G } from "libF"; import { importA, diff --git a/test/rules/whitespace/all/test.ts.lint b/test/rules/whitespace/all/test.ts.lint index f75d77afdb7..e28ba491892 100644 --- a/test/rules/whitespace/all/test.ts.lint +++ b/test/rules/whitespace/all/test.ts.lint @@ -120,6 +120,13 @@ import moduleD, {importD}from "libD"; import {importD, importE} from "libD"; ~ [missing whitespace] ~ [missing whitespace] +import {importF as F} from "libF"; + ~ [missing whitespace] + ~ [missing whitespace] +import {importF as F,importG as G} from "libF"; + ~ [missing whitespace] + ~ [missing whitespace] + ~ [missing whitespace] import { importA, diff --git a/test/rules/whitespace/check-postbrace/test.ts.fix b/test/rules/whitespace/check-postbrace/test.ts.fix new file mode 100644 index 00000000000..e445dc1d501 --- /dev/null +++ b/test/rules/whitespace/check-postbrace/test.ts.fix @@ -0,0 +1,5 @@ +function() { return 5;} + +function() { + const something: number = 5; +} diff --git a/test/rules/whitespace/check-postbrace/test.ts.lint b/test/rules/whitespace/check-postbrace/test.ts.lint new file mode 100644 index 00000000000..a314f760626 --- /dev/null +++ b/test/rules/whitespace/check-postbrace/test.ts.lint @@ -0,0 +1,6 @@ +function() {return 5;} + ~ [missing whitespace] + +function() { + const something: number = 5; +} diff --git a/test/rules/whitespace/check-postbrace/tslint.json b/test/rules/whitespace/check-postbrace/tslint.json new file mode 100644 index 00000000000..456fb9756ad --- /dev/null +++ b/test/rules/whitespace/check-postbrace/tslint.json @@ -0,0 +1,5 @@ +{ + "rules": { + "whitespace": [true, "check-postbrace"] + } +} diff --git a/test/tsconfig.json b/test/tsconfig.json index 772bb2cb5d8..fa15117ef1e 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -14,12 +14,6 @@ "lib": ["es6"], "outDir": "../build" }, - "include": [ - "../src/**/*", - "**/*" - ], - "exclude": [ - "./files", - "./rules" - ] + "include": ["../src/**/*", "**/*"], + "exclude": ["./files", "./rules"] } diff --git a/test/utils.ts b/test/utils.ts index 14a3c74ef6c..33bf58f94dc 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -35,7 +35,10 @@ export function getFormatter(formatterName: string): Lint.FormatterConstructor { export function createTempFile(extension: string) { for (let i = 0; i < 5; i++) { - const attempt = path.join(os.tmpdir(), `tslint.test${Math.round(Date.now() * Math.random())}.${extension}`); + const attempt = path.join( + os.tmpdir(), + `tslint.test${Math.round(Date.now() * Math.random())}.${extension}`, + ); if (!fs.existsSync(attempt)) { return attempt; } diff --git a/test/utilsTests.ts b/test/utilsTests.ts index c04ae038332..e1ce48f1b89 100644 --- a/test/utilsTests.ts +++ b/test/utilsTests.ts @@ -24,7 +24,7 @@ describe("Utils", () => { assert.deepEqual(arrayify([]), []); assert.deepEqual(arrayify("foo"), ["foo"]); assert.deepEqual(arrayify(1), [1]); - assert.deepEqual(arrayify({foo: 2}), [{foo: 2}]); + assert.deepEqual(arrayify({ foo: 2 }), [{ foo: 2 }]); assert.deepEqual(arrayify([1, 2]), [1, 2]); assert.deepEqual(arrayify(["foo"]), ["foo"]); }); @@ -34,7 +34,8 @@ describe("Utils", () => { dedent` foo bar`, - "\nfoo\nbar"); + "\nfoo\nbar", + ); assert.equal(dedent` one-line`, "one-line"); diff --git a/tslint.json b/tslint.json index 59d34f6574c..3b2ce4e7f04 100644 --- a/tslint.json +++ b/tslint.json @@ -6,6 +6,7 @@ "rules": { // Don't want these "cyclomatic-complexity": false, + "increment-decrement": false, "newline-before-return": false, "no-parameter-properties": false, "no-parameter-reassignment": false, diff --git a/yarn.lock b/yarn.lock index 7a0a882de0b..22dcf39145a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,18 +5,22 @@ "@types/babel-code-frame@^6.20.0": version "6.20.1" resolved "https://registry.yarnpkg.com/@types/babel-code-frame/-/babel-code-frame-6.20.1.tgz#e79a40ea81435034df7b46b5e32e8ed638aea4dd" + integrity sha1-55pA6oFDUDTfe0a14y6O1jiupN0= "@types/chai@^3.5.0": version "3.5.2" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-3.5.2.tgz#c11cd2817d3a401b7ba0f5a420f35c56139b1c1e" + integrity sha1-wRzSgX06QBt7oPWkIPNcVhObHB4= "@types/diff@^3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@types/diff/-/diff-3.2.0.tgz#2cf019a98b4cca072102cb48af5675502b5a831f" + integrity sha1-LPAZqYtMygchAstIr1Z1UCtagx8= "@types/glob@*": version "5.0.32" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.32.tgz#aec5cfe987c72f099fdb1184452986aa506d5e8f" + integrity sha512-DMcj5b67Alb/e4KhpzyvphC5nVDHn1oCOGZao3oBddZVMH5vgI/cvdp+O/kcxZGZaPqs0ZLAsK4YrjbtZHO05g== dependencies: "@types/minimatch" "*" "@types/node" "*" @@ -24,6 +28,7 @@ "@types/glob@^5.0.30": version "5.0.30" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.30.tgz#1026409c5625a8689074602808d082b2867b8a51" + integrity sha1-ECZAnFYlqGiQdGAoCNCCsoZ7ilE= dependencies: "@types/minimatch" "*" "@types/node" "*" @@ -31,28 +36,34 @@ "@types/js-yaml@^3.5.31": version "3.5.31" resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.5.31.tgz#54aeb8bcaaf94a7b1a64311bc318dbfe601a593a" + integrity sha512-tDsBKuC7nlShdRbR+rCe6qrs9Fqodi7WUxyeysCwKG0kWFWsisyZ8FhmYhCF6+lt3XhIwSExaD1MxidYtRW15w== "@types/minimatch@*", "@types/minimatch@^2.0.29": version "2.0.29" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-2.0.29.tgz#5002e14f75e2d71e564281df0431c8c1b4a2a36a" + integrity sha1-UALhT3Xi1x5WQoHfBDHIwbSio2o= "@types/mocha@^2.2.35": version "2.2.41" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.41.tgz#e27cf0817153eb9f2713b2d3f6c68f1e1c3ca608" + integrity sha1-4nzwgXFT658nE7LT9saPHhw8pgg= "@types/node@*", "@types/node@^7.0.29": version "7.0.29" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.29.tgz#ccfcec5b7135c7caf6c4ffb8c7f33102340d99df" + integrity sha512-+8JrLZny/uR+d/jLK9eaV63buRM7X/gNzQk57q76NS4KNKLSKOmxJYFIlwuP2zDvA7wqZj05POPhSd9Z1hYQpQ== "@types/resolve@^0.0.4": version "0.0.4" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.4.tgz#9b586d65a947dea88c4bc24da0b905fe9520a0d5" + integrity sha1-m1htZalH3qiMS8JNoLkF/pUgoNU= dependencies: "@types/node" "*" "@types/rimraf@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e" + integrity sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ== dependencies: "@types/glob" "*" "@types/node" "*" @@ -60,10 +71,12 @@ "@types/semver@^5.3.30": version "5.3.31" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.3.31.tgz#b999d7d935f43f5207b01b00d3de20852f4ca75f" + integrity sha1-uZnX2TX0P1IHsBsA094ghS9Mp18= agent-base@2: version "2.1.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" + integrity sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc= dependencies: extend "~3.0.0" semver "~5.0.1" @@ -71,6 +84,7 @@ agent-base@2: align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -79,78 +93,95 @@ align-text@^0.1.1, align-text@^0.1.3: amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= ansi-styles@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + integrity sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug== dependencies: color-convert "^1.9.0" append-transform@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + integrity sha1-126/jKlNJ24keja61EpLdKthGZE= dependencies: default-require-extensions "^1.0.0" archy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= argparse@^1.0.7: version "1.0.9" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + integrity sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY= dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= dependencies: arr-flatten "^1.0.1" arr-flatten@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" + integrity sha1-onTthawIhJtr14R8RYB0XcUa37E= array-filter@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + integrity sha1-fajPLiZijtcygDWB/SH2fKzS7uw= array-map@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" + integrity sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI= array-reduce@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys= array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= assertion-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" + integrity sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw= async@^1.4.0: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= babel-code-frame@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" + integrity sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ= dependencies: chalk "^1.1.0" esutils "^2.0.2" @@ -159,6 +190,7 @@ babel-code-frame@^6.22.0: babel-generator@^6.18.0: version "6.25.0" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.25.0.tgz#33a1af70d5f2890aeb465a4a7793c1df6a9ea9fc" + integrity sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw= dependencies: babel-messages "^6.23.0" babel-runtime "^6.22.0" @@ -172,12 +204,14 @@ babel-generator@^6.18.0: babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= dependencies: babel-runtime "^6.22.0" babel-runtime@^6.22.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" + integrity sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs= dependencies: core-js "^2.4.0" regenerator-runtime "^0.10.0" @@ -185,6 +219,7 @@ babel-runtime@^6.22.0: babel-template@^6.16.0: version "6.25.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.25.0.tgz#665241166b7c2aa4c619d71e192969552b10c071" + integrity sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE= dependencies: babel-runtime "^6.22.0" babel-traverse "^6.25.0" @@ -195,6 +230,7 @@ babel-template@^6.16.0: babel-traverse@^6.18.0, babel-traverse@^6.25.0: version "6.25.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.25.0.tgz#2257497e2fcd19b89edc13c4c91381f9512496f1" + integrity sha1-IldJfi/NGbie3BPEyROB+VEklvE= dependencies: babel-code-frame "^6.22.0" babel-messages "^6.23.0" @@ -209,6 +245,7 @@ babel-traverse@^6.18.0, babel-traverse@^6.25.0: babel-types@^6.18.0, babel-types@^6.25.0: version "6.25.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.25.0.tgz#70afb248d5660e5d18f811d91c8303b54134a18e" + integrity sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4= dependencies: babel-runtime "^6.22.0" esutils "^2.0.2" @@ -218,14 +255,17 @@ babel-types@^6.18.0, babel-types@^6.25.0: babylon@^6.13.0, babylon@^6.17.2: version "6.17.3" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.3.tgz#1327d709950b558f204e5352587fd0290f8d8e48" + integrity sha512-mq0x3HCAGGmQyZXviOVe5TRsw37Ijy3D43jCqt/9WVf+onx2dUgW3PosnqCbScAFhRO9DGs8nxoMzU0iiosMqQ== balanced-match@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + integrity sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg= brace-expansion@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" + integrity sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k= dependencies: balanced-match "^0.4.1" concat-map "0.0.1" @@ -233,6 +273,7 @@ brace-expansion@^1.1.7: braces@^1.8.2: version "1.8.5" resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -241,14 +282,17 @@ braces@^1.8.2: browser-stdout@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" + integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8= builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= caching-transform@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-1.0.1.tgz#6dbdb2f20f8d8fbce79f3e94e9d1742dcdf5c0a1" + integrity sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE= dependencies: md5-hex "^1.2.0" mkdirp "^0.5.1" @@ -257,14 +301,17 @@ caching-transform@^1.0.0: camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" @@ -272,6 +319,7 @@ center-align@^0.1.1: chai@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + integrity sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc= dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" @@ -280,6 +328,7 @@ chai@^3.5.0: chalk@^1.1.0, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -290,6 +339,7 @@ chalk@^1.1.0, chalk@^1.1.3: chalk@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" + integrity sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ== dependencies: ansi-styles "^3.1.0" escape-string-regexp "^1.0.5" @@ -298,6 +348,7 @@ chalk@^2.0.0: chalk@^2.1.0, chalk@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" + integrity sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q== dependencies: ansi-styles "^3.1.0" escape-string-regexp "^1.0.5" @@ -306,10 +357,12 @@ chalk@^2.1.0, chalk@^2.3.0: ci-info@^1.0.0: version "1.1.3" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" + integrity sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg== cliui@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -318,6 +371,7 @@ cliui@^2.1.0: cliui@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -326,46 +380,56 @@ cliui@^3.2.0: code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= color-convert@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + integrity sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o= dependencies: color-name "^1.1.1" color-name@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= commander@2.9.0, commander@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + integrity sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q= dependencies: graceful-readlink ">= 1.0.0" commander@^2.12.1: version "2.12.2" resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" + integrity sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA== commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= convert-source-map@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + integrity sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU= core-js@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + integrity sha1-TekR5mew6ukSTjQlS1OupvxhjT4= cross-spawn@^4: version "4.0.2" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" + integrity sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE= dependencies: lru-cache "^4.0.1" which "^1.2.9" @@ -373,6 +437,7 @@ cross-spawn@^4: cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -381,38 +446,45 @@ cross-spawn@^5.0.1: debug-log@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" + integrity sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8= debug@2, debug@2.6.0, debug@^2.2.0: version "2.6.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" + integrity sha1-vFlryr52F/Edn6FTYe3tVgi4SZs= dependencies: ms "0.7.2" debug@^2.6.3: version "2.6.8" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" + integrity sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw= dependencies: ms "2.0.0" decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= deep-eql@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + integrity sha1-71WKyrjeJSBs1xOQbXTlaTDrafI= dependencies: type-detect "0.1.1" default-require-extensions@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + integrity sha1-836hXT4T/9m0N9M+GnW1+5eHTLg= dependencies: strip-bom "^2.0.0" define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + integrity sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ= dependencies: foreach "^2.0.5" object-keys "^1.0.8" @@ -420,30 +492,36 @@ define-properties@^1.1.2: detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= dependencies: repeating "^2.0.0" diff@3.2.0, diff@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" + integrity sha1-yc45Okt8vQsFinJck98pkCeGj/k= diff@^3.1.0: version "3.3.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.0.tgz#056695150d7aa93237ca7e378ac3b1682b7963b9" + integrity sha512-w0XZubFWn0Adlsapj9EAWX0FqWdO4tz8kc3RiYdWLh4k/V8PTb6i0SMgXt0vRM3zyKnT8tKO7mUlieRQHIjMNg== duplexer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= error-ex@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + integrity sha1-+FWobOYa3E6GIcPNoh56dhLDqNw= dependencies: is-arrayish "^0.2.1" es-abstract@^1.4.3: version "1.7.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c" + integrity sha1-363ndOAb/Nl/lhgCmMRJyGI/uUw= dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.0" @@ -453,6 +531,7 @@ es-abstract@^1.4.3: es-to-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + integrity sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0= dependencies: is-callable "^1.1.1" is-date-object "^1.0.1" @@ -461,18 +540,22 @@ es-to-primitive@^1.1.1: escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= esprima@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= event-stream@~3.3.0: version "3.3.4" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= dependencies: duplexer "~0.1.1" from "~0" @@ -485,6 +568,7 @@ event-stream@~3.3.0: execa@^0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" + integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo= dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -497,32 +581,38 @@ execa@^0.8.0: expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= dependencies: is-posix-bracket "^0.1.0" expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= dependencies: fill-range "^2.1.0" extend@3, extend@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ= extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= dependencies: is-extglob "^1.0.0" filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= fill-range@^2.1.0: version "2.2.3" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + integrity sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM= dependencies: is-number "^2.1.0" isobject "^2.0.0" @@ -533,6 +623,7 @@ fill-range@^2.1.0: find-cache-dir@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + integrity sha1-yN765XyKUqinhPnjHFfHQumToLk= dependencies: commondir "^1.0.1" mkdirp "^0.5.1" @@ -541,6 +632,7 @@ find-cache-dir@^0.1.1: find-up@^1.0.0, find-up@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -548,12 +640,14 @@ find-up@^1.0.0, find-up@^1.1.2: find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= dependencies: locate-path "^2.0.0" follow-redirects@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" + integrity sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk= dependencies: debug "^2.2.0" stream-consume "^0.1.0" @@ -561,20 +655,24 @@ follow-redirects@0.0.7: for-in@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= for-own@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= dependencies: for-in "^1.0.1" foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= foreground-child@^1.3.3, foreground-child@^1.5.3: version "1.5.6" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" + integrity sha1-T9ca0t/elnibmApcCilZN8svXOk= dependencies: cross-spawn "^4" signal-exit "^3.0.0" @@ -582,26 +680,32 @@ foreground-child@^1.3.3, foreground-child@^1.5.3: from@~0: version "0.1.7" resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= function-bind@^1.0.2, function-bind@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" + integrity sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E= get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + integrity sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U= get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= github@^8.2.1: version "8.2.1" resolved "https://registry.yarnpkg.com/github/-/github-8.2.1.tgz#616b2211fbcd1cc8631669aed67653e62eb53816" + integrity sha1-YWsiEfvNHMhjFmmu1nZT5i61OBY= dependencies: follow-redirects "0.0.7" https-proxy-agent "^1.0.0" @@ -611,6 +715,7 @@ github@^8.2.1: glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" @@ -618,12 +723,14 @@ glob-base@^0.3.0: glob-parent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= dependencies: is-glob "^2.0.0" glob@7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + integrity sha1-gFIR3wT6rxxjo2ADBs31reULLsg= dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -635,6 +742,7 @@ glob@7.1.1: glob@^7.0.5, glob@^7.0.6, glob@^7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -646,22 +754,27 @@ glob@^7.0.5, glob@^7.0.6, glob@^7.1.1: globals@^9.0.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= growl@1.9.2: version "1.9.2" resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" + integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= handlebars@^4.0.3: version "4.0.10" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" + integrity sha1-PTDHGLCaPZbyPqTMH0A8TTup/08= dependencies: async "^1.4.0" optimist "^0.6.1" @@ -672,30 +785,36 @@ handlebars@^4.0.3: has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= dependencies: ansi-regex "^2.0.0" has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= has@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + integrity sha1-hGFzP1OLCDfJNh45qauelwTcLyg= dependencies: function-bind "^1.0.2" hosted-git-info@^2.1.4: version "2.4.2" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" + integrity sha1-AHa59GonBQbduq6lZJaJdGBhKmc= https-proxy-agent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" + integrity sha1-NffabEjOTdv6JkiRrFk+5f+GceY= dependencies: agent-base "2" debug "2" @@ -704,6 +823,7 @@ https-proxy-agent@^1.0.0: husky@^0.14.3: version "0.14.3" resolved "https://registry.yarnpkg.com/husky/-/husky-0.14.3.tgz#c69ed74e2d2779769a17ba8399b54ce0b63c12c3" + integrity sha512-e21wivqHpstpoiWA/Yi8eFti8E+sQDSS53cpJsPptPs295QTOQR0ZwnHo2TXy1XOpZFD9rPOd3NpmqTK6uMLJA== dependencies: is-ci "^1.0.10" normalize-path "^1.0.0" @@ -712,14 +832,17 @@ husky@^0.14.3: ignore@^3.3.7: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" @@ -727,146 +850,176 @@ inflight@^1.0.4: inherits@2: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= invariant@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + integrity sha1-nh9WrArNtr8wMwbzOL47IErmA2A= dependencies: loose-envify "^1.0.0" invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-buffer@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + integrity sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw= is-builtin-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= dependencies: builtin-modules "^1.0.0" is-callable@^1.1.1, is-callable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + integrity sha1-hut1OSgF3cM69xySoO7fdO52BLI= is-ci@^1.0.10: version "1.1.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" + integrity sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg== dependencies: ci-info "^1.0.0" is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= is-equal-shallow@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= dependencies: is-primitive "^2.0.0" is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= is-finite@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= dependencies: is-extglob "^1.0.0" is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= dependencies: kind-of "^3.0.2" is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= is-regex@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= dependencies: has "^1.0.1" is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + integrity sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI= is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= isarray@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" istanbul-lib-coverage@^1.1.0, istanbul-lib-coverage@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz#73bfb998885299415c93d38a3e9adf784a77a9da" + integrity sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q== istanbul-lib-hook@^1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz#dd6607f03076578fe7d6f2a630cf143b49bacddc" + integrity sha512-3U2HB9y1ZV9UmFlE12Fx+nPtFqIymzrqCksrXujm3NVbAZIJg/RfYgO1XiIa0mbmxTjWpVEVlkIZJ25xVIAfkQ== dependencies: append-transform "^0.4.0" istanbul-lib-instrument@^1.7.1: version "1.7.2" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.2.tgz#6014b03d3470fb77638d5802508c255c06312e56" + integrity sha512-lPgUY+Pa5dlq2/l0qs1PJZ54QPSfo+s4+UZdkb2d0hbOyrEIAbUJphBLFjEyXBdeCONgGRADFzs3ojfFtmuwFA== dependencies: babel-generator "^6.18.0" babel-template "^6.16.0" @@ -879,6 +1032,7 @@ istanbul-lib-instrument@^1.7.1: istanbul-lib-report@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#f0e55f56655ffa34222080b7a0cd4760e1405fc9" + integrity sha512-tvF+YmCmH4thnez6JFX06ujIA19WPa9YUiwjc1uALF2cv5dmE3It8b5I8Ob7FHJ70H9Y5yF+TDkVa/mcADuw1Q== dependencies: istanbul-lib-coverage "^1.1.1" mkdirp "^0.5.1" @@ -888,6 +1042,7 @@ istanbul-lib-report@^1.1.0: istanbul-lib-source-maps@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz#a6fe1acba8ce08eebc638e572e294d267008aa0c" + integrity sha512-mukVvSXCn9JQvdJl8wP/iPhqig0MRtuWuD4ZNKo6vB2Ik//AmhAKe3QnPN02dmkRe3lTudFk3rzoHhwU4hb94w== dependencies: debug "^2.6.3" istanbul-lib-coverage "^1.1.1" @@ -898,16 +1053,19 @@ istanbul-lib-source-maps@^1.2.0: istanbul-reports@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.1.tgz#042be5c89e175bc3f86523caab29c014e77fee4e" + integrity sha512-P8G873A0kW24XRlxHVGhMJBhQ8gWAec+dae7ZxOBzxT4w+a9ATSPvRVK3LB1RAJ9S8bg2tOyWHAGW40Zd2dKfw== dependencies: handlebars "^4.0.3" js-tokens@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + integrity sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc= js-yaml@^3.7.0: version "3.8.4" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" + integrity sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY= dependencies: argparse "^1.0.7" esprima "^3.1.1" @@ -915,44 +1073,53 @@ js-yaml@^3.7.0: jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= json-stringify-pretty-compact@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/json-stringify-pretty-compact/-/json-stringify-pretty-compact-1.0.4.tgz#d5161131be27fd9748391360597fcca250c6c5ce" + integrity sha1-1RYRMb4n/ZdIORNgWX/MolDGxc4= json3@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= kind-of@^3.0.2: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= dependencies: invert-kv "^1.0.0" load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -963,6 +1130,7 @@ load-json-file@^1.0.0: load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -972,6 +1140,7 @@ load-json-file@^2.0.0: locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -979,6 +1148,7 @@ locate-path@^2.0.0: lodash._baseassign@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + integrity sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4= dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" @@ -986,22 +1156,27 @@ lodash._baseassign@^3.0.0: lodash._basecopy@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= lodash._basecreate@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" + integrity sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE= lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= lodash._isiterateecall@^3.0.0: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= lodash.create@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" + integrity sha1-1/KEnw29p+BGgruM1yqwIkYd6+c= dependencies: lodash._baseassign "^3.0.0" lodash._basecreate "^3.0.0" @@ -1010,14 +1185,17 @@ lodash.create@3.1.1: lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -1026,20 +1204,24 @@ lodash.keys@^3.0.0: lodash@^4.2.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + integrity sha1-eCA6TRwyiuHYbcpkYONptX9AVa4= longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= loose-envify@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + integrity sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg= dependencies: js-tokens "^3.0.0" lru-cache@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" + integrity sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew== dependencies: pseudomap "^1.0.2" yallist "^2.1.2" @@ -1047,30 +1229,36 @@ lru-cache@^4.0.1: make-error@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.0.tgz#52ad3a339ccf10ce62b4040b708fe707244b8b96" + integrity sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y= map-stream@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= md5-hex@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" + integrity sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ= dependencies: md5-o-matic "^0.1.1" md5-o-matic@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + integrity sha1-givM1l4RfFFPqxdrJZRdVBAKA8M= merge-source-map@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.3.tgz#da1415f2722a5119db07b14c4f973410863a2abf" + integrity sha1-2hQV8nIqURnbB7FMT5c0EIY6Kr8= dependencies: source-map "^0.5.3" micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -1089,30 +1277,36 @@ micromatch@^2.3.11: mime@^1.2.11: version "1.3.6" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" + integrity sha1-WR2E02U6awtKO5343lqoEI5y5eA= minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" mocha@^3.2.0: version "3.4.2" resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.4.2.tgz#d0ef4d332126dbf18d0d640c9b382dd48be97594" + integrity sha1-0O9NMyEm2/GNDWQMmzgt1IvpdZQ= dependencies: browser-stdout "1.3.0" commander "2.9.0" @@ -1129,22 +1323,27 @@ mocha@^3.2.0: mri@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.1.tgz#85aa26d3daeeeedf80dc5984af95cc5ca5cad9f1" + integrity sha1-haom09ru7t+A3FmEr5XMXKXK2fE= ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + integrity sha1-riXPJRKziFodldfwN4aNhDESR2U= ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= netrc@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/netrc/-/netrc-0.1.4.tgz#6be94fcaca8d77ade0a9670dc460914c94472444" + integrity sha1-a+lPysqNd63gqWcNxGCRTJRHJEQ= normalize-package-data@^2.3.2: version "2.3.8" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" + integrity sha1-2Bntoqne29H/pWPqQHHZNngilbs= dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -1154,16 +1353,19 @@ normalize-package-data@^2.3.2: normalize-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" + integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= normalize-path@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" npm-run-all@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.0.2.tgz#a84669348e6db6ccbe052200b4cdb6bfe034a4fe" + integrity sha1-qEZpNI5ttsy+BSIAtM22v+A0pP4= dependencies: chalk "^1.1.3" cross-spawn "^5.0.1" @@ -1176,16 +1378,19 @@ npm-run-all@^4.0.2: npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= nyc@^10.2.0: version "10.3.2" resolved "https://registry.yarnpkg.com/nyc/-/nyc-10.3.2.tgz#f27f4d91f2a9db36c24f574ff5c6efff0233de46" + integrity sha1-8n9NkfKp2zbCT1dP9cbv/wIz3kY= dependencies: archy "^1.0.0" arrify "^1.0.1" @@ -1218,14 +1423,17 @@ nyc@^10.2.0: object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + integrity sha1-xUYBd4rVYPEULODgG8yotW0TQm0= object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= dependencies: for-own "^0.1.4" is-extendable "^0.1.1" @@ -1233,12 +1441,14 @@ object.omit@^2.0.0: once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= dependencies: minimist "~0.0.1" wordwrap "~0.0.2" @@ -1246,36 +1456,43 @@ optimist@^0.6.1: os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= os-locale@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= dependencies: lcid "^1.0.0" p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: p-limit "^1.1.0" p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -1285,34 +1502,41 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= dependencies: error-ex "^1.2.0" path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-key@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + integrity sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME= path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -1321,46 +1545,55 @@ path-type@^1.0.0: path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= dependencies: pify "^2.0.0" pause-stream@0.0.11: version "0.0.11" resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= dependencies: through "~2.3" pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= pkg-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= dependencies: find-up "^1.0.0" preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= -prettier@1.13.7: - version "1.13.7" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281" +prettier@1.14.3: + version "1.14.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" + integrity sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg== pretty-quick@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/pretty-quick/-/pretty-quick-1.6.0.tgz#afc3591eb5c4cf37614a305d489a8a40e57c9258" + integrity sha512-bnCmsPy98ERD7VWBO+0y1OGWLfx/DPUjNFN2ZRVyxuGBiic1BXAGgjHsTKgBIbPISdqpP6KBEmRV0Lir4xu/BA== dependencies: chalk "^2.3.0" execa "^0.8.0" @@ -1371,16 +1604,19 @@ pretty-quick@^1.6.0: ps-tree@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" + integrity sha1-tCGyQUDWID8e08dplrRCewjowBQ= dependencies: event-stream "~3.3.0" pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= randomatic@^1.1.3: version "1.1.7" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + integrity sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how== dependencies: is-number "^3.0.0" kind-of "^4.0.0" @@ -1388,6 +1624,7 @@ randomatic@^1.1.3: read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= dependencies: find-up "^1.0.0" read-pkg "^1.0.0" @@ -1395,6 +1632,7 @@ read-pkg-up@^1.0.1: read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -1403,6 +1641,7 @@ read-pkg@^1.0.0: read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= dependencies: load-json-file "^2.0.0" normalize-package-data "^2.3.2" @@ -1411,10 +1650,12 @@ read-pkg@^2.0.0: regenerator-runtime@^0.10.0: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= regex-cache@^0.4.2: version "0.4.3" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + integrity sha1-mxpsNdTQ3871cRrmUejp09cRQUU= dependencies: is-equal-shallow "^0.1.3" is-primitive "^2.0.0" @@ -1422,76 +1663,92 @@ regex-cache@^0.4.2: remove-trailing-separator@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz#69b062d978727ad14dc6b56ba4ab772fd8d70511" + integrity sha1-abBi2XhyetFNxrVrpKt3L9jXBRE= repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= repeat-string@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= dependencies: is-finite "^1.0.0" require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= resolve-from@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= resolve@^1.3.2: version "1.3.3" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" + integrity sha1-ZVkHw0aahoDcLeOidaj91paR8OU= dependencies: path-parse "^1.0.5" right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= dependencies: align-text "^0.1.1" rimraf@^2.3.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" + integrity sha1-wjOOxkPfeht/5cVPqG9XQopV8z0= dependencies: glob "^7.0.5" "semver@2 || 3 || 4 || 5", semver@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" + integrity sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no= set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= shell-quote@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" + integrity sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c= dependencies: array-filter "~0.0.0" array-map "~0.0.0" @@ -1501,38 +1758,46 @@ shell-quote@^1.6.1: signal-exit@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-2.1.2.tgz#375879b1f92ebc3b334480d038dc546a6d558564" + integrity sha1-N1h5sfkuvDszRIDQONxUam1VhWQ= signal-exit@^3.0.0, signal-exit@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= slide@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= source-map-support@^0.4.0: version "0.4.16" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.16.tgz#16fecf98212467d017d586a2af68d628b9421cd8" + integrity sha512-A6vlydY7H/ljr4L2UOhDSajQdZQ6dMD7cLH0pzwcmwLyc9u8PNI4WGtnfDDzX7uzGL6c/T+ORL97Zlh+S4iOrg== dependencies: source-map "^0.5.6" source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= dependencies: amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.3, source-map@~0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= spawn-wrap@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.2.4.tgz#920eb211a769c093eebfbd5b0e7a5d2e68ab2e40" + integrity sha1-kg6yEadpwJPuv71bDnpdLmirLkA= dependencies: foreground-child "^1.3.3" mkdirp "^0.5.0" @@ -1544,40 +1809,48 @@ spawn-wrap@1.2.4: spdx-correct@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + integrity sha1-SzBz2TP/UfORLwOsVRlJikFQ20A= dependencies: spdx-license-ids "^1.0.2" spdx-expression-parse@~1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + integrity sha1-m98vIOH0DtRH++JzJmGR/O1RYmw= spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + integrity sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc= split@0.3: version "0.3.3" resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8= dependencies: through "2" sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= stream-combiner@~0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ= dependencies: duplexer "~0.1.1" stream-consume@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" + integrity sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8= string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -1586,6 +1859,7 @@ string-width@^1.0.1, string-width@^1.0.2: string.prototype.padend@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0" + integrity sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA= dependencies: define-properties "^1.1.2" es-abstract "^1.4.3" @@ -1594,50 +1868,60 @@ string.prototype.padend@^3.0.0: strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= strip-indent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" + integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= strip-json-comments@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= supports-color@3.1.2, supports-color@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" + integrity sha1-cqJiiU2dQIuVbKBf83su2KbiotU= dependencies: has-flag "^1.0.0" supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= supports-color@^4.0.0: version "4.2.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.1.tgz#65a4bb2631e90e02420dba5554c375a4754bb836" + integrity sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA== dependencies: has-flag "^2.0.0" test-exclude@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.1.tgz#4d84964b0966b0087ecc334a2ce002d3d9341e26" + integrity sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA== dependencies: arrify "^1.0.1" micromatch "^2.3.11" @@ -1648,18 +1932,22 @@ test-exclude@^4.1.0: through@2, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= to-fast-properties@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= ts-node@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-3.3.0.tgz#c13c6a3024e30be1180dd53038fc209289d4bf69" + integrity sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k= dependencies: arrify "^1.0.0" chalk "^2.0.0" @@ -1675,6 +1963,7 @@ ts-node@^3.3.0: tsconfig@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-6.0.0.tgz#6b0e8376003d7af1864f8df8f89dd0059ffcd032" + integrity sha1-aw6DdgA9evGGT434+J3QBZ/80DI= dependencies: strip-bom "^3.0.0" strip-json-comments "^2.0.0" @@ -1682,18 +1971,22 @@ tsconfig@^6.0.0: tslib@^1.7.1: version "1.7.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" + integrity sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw= tslib@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.0.tgz#dc604ebad64bcbf696d613da6c954aa0e7ea1eb6" + integrity sha512-ymKWWZJST0/CkgduC2qkzjMOWr4bouhuURNXCn/inEX0L57BnRG6FhX76o7FOnsjHazCjfU2LKeSrlS2sIKQJg== tslib@^1.8.1: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== tslint-config-prettier@^1.13.0: version "1.13.0" resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.13.0.tgz#189e821931ad89e0364e4e292d5c44a14e90ecd6" + integrity sha512-assE77K7K8Q9j8CVIHiU3d1uoKc8N5v7UPpkQ9IE8BEPWkvSYR37lDuYekDlAMFqR1IpD6CrS+uOJLl6pw7Wdw== "tslint-test-config-non-relative@file:test/external/tslint-test-config-non-relative": version "0.0.1" @@ -1701,6 +1994,7 @@ tslint-config-prettier@^1.13.0: tslint@^5.8.0: version "5.8.0" resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.8.0.tgz#1f49ad5b2e77c76c3af4ddcae552ae4e3612eb13" + integrity sha1-H0mtWy53x2w69N3K5VKuTjYS6xM= dependencies: babel-code-frame "^6.22.0" builtin-modules "^1.1.1" @@ -1717,30 +2011,36 @@ tslint@^5.8.0: tsutils@^2.12.1: version "2.12.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.12.1.tgz#f4d95ce3391c8971e46e54c4cf0edb0a21dd5b24" + integrity sha1-9Nlc4zkciXHkblTEzw7bCiHdWyQ= dependencies: tslib "^1.7.1" tsutils@^2.27.2: version "2.27.2" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7" + integrity sha512-qf6rmT84TFMuxAKez2pIfR8UCai49iQsfB7YWVjV1bKpy/d0PWT5rEOSM6La9PiHZ0k1RRZQiwVdVJfQ3BPHgg== dependencies: tslib "^1.8.1" type-detect@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + integrity sha1-C6XsKohWQORw6k6FBZcZANrFiCI= type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + integrity sha1-diIXzAbbJY7EiQihKY6LlRIejqI= typescript@~2.9.2: version "2.9.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" + integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w== uglify-js@^2.6: version "2.8.28" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.28.tgz#e335032df9bb20dcb918f164589d5af47f38834a" + integrity sha512-WqKNbmNJKzIdIEQu/U2ytgGBbhCy2PVks94GoetczOAJ/zCgVu2CuO7gguI5KPFGPtUtI1dmPQl6h0D4cPzypA== dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -1750,20 +2050,24 @@ uglify-js@^2.6: uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + integrity sha1-K1viOjK2Onyd640PKNSFcko98ZA= v8flags@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.0.0.tgz#4be9604488e0c4123645def705b1848d16b8e01f" + integrity sha512-AGl+C+4qpeSu2g3JxCD/mGFFOs/vVZ3XREkD3ibQXEqr4Y4zgIrPWW124/IKJFHOIVFIoH8miWrLf0o84HYjwA== dependencies: user-home "^1.1.1" validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + integrity sha1-KAS6vnEq0zeUWaz74kdGqywwP7w= dependencies: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" @@ -1771,28 +2075,34 @@ validate-npm-package-license@^3.0.1: which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= which@^1.2.4, which@^1.2.9: version "1.2.14" resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + integrity sha1-mofEN48D6CfOyvGs31bHNsAcFOU= dependencies: isexe "^2.0.0" window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -1800,10 +2110,12 @@ wrap-ansi@^2.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= write-file-atomic@^1.1.4: version "1.3.4" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" + integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8= dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -1812,20 +2124,24 @@ write-file-atomic@^1.1.4: y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= dependencies: camelcase "^3.0.0" yargs@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= dependencies: camelcase "^3.0.0" cliui "^3.2.0" @@ -1844,6 +2160,7 @@ yargs@^7.1.0: yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -1853,3 +2170,4 @@ yargs@~3.10.0: yn@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + integrity sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=