├── .editorconfig ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── circle.yml ├── package.json ├── sample.ts ├── src ├── checker.ts ├── index.ts └── types.ts ├── tests ├── basics │ ├── expected-error.ts │ ├── expected-error.ts.out │ ├── inline-assertion.ts │ ├── inline-assertion.ts.out │ ├── sanity.ts │ ├── sanity.ts.out │ ├── type-assertion-failure.ts │ ├── type-assertion-failure.ts.out │ ├── type-assertion.ts │ ├── type-assertion.ts.out │ ├── unexpected-error.ts │ └── unexpected-error.ts.out ├── doesnt-exist.ts.out ├── multiple.out ├── ramda.ts ├── ramda.ts.out ├── tsconfig.json ├── underscore-any.ts ├── underscore-any.ts.out ├── underscore.ts └── underscore.ts.out ├── tsconfig.json ├── tslint.json ├── update-tests.sh └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | indent_style = space 8 | 9 | [*.{js,jsx,ts,tsx}] 10 | indent_size = 2 11 | 12 | [*.json] 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # editor 40 | .vscode/ 41 | 42 | # Generated JS files 43 | dist/ 44 | 45 | .idea 46 | .DS_Store 47 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # editor 40 | .vscode/ 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This is not maintained! Check out [dtslint](https://github.com/microsoft/dtslint) and [tsd](https://github.com/SamVerschueren/tsd). 2 | 3 | ---- 4 | 5 | # typings-checker [![CircleCI](https://circleci.com/gh/danvk/typings-checker.svg?style=svg)](https://circleci.com/gh/danvk/typings-checker) 6 | 7 | The [tests in DefinitelyTyped][1] verify that correct code type checks. 8 | But this is an easy bar to meet: giving a module an `any` type is sufficient to make 9 | its tests type check. 10 | 11 | It's just as important that _incorrect_ code _not_ typecheck. There isn't any way to 12 | test for this in DT right now. This repo provides a proof of concept for how this could 13 | be added. It's modeleled after the way [FlowTyped][] handles things. 14 | 15 | Here's what a test for `_.find` might look like: 16 | 17 | ```ts 18 | _.find([1, 2, 3], x => x * 1 == 3); // (this is just expected to type check) 19 | // $ExpectError Operator '==' cannot be applied to types 'number' and 'string'. 20 | _.find([1, 2, 3], x => x == 'a'); 21 | // $ExpectType number 22 | _.find([1, 2, 3], 1); 23 | // $ExpectError Property 'y' does not exist on type '{ x: number; }'. 24 | _.find([{x:1}, {x:2}, {x:3}], v => v.y == 3); 25 | // $ExpectType { x: number; } 26 | _.find([{x:1}, {x:2}, {x:3}], v => v.x == 3); 27 | ``` 28 | 29 | Code is expected to type check unless an `$ExpectError` directive is used. In this case, an error is required (lack of an error from TypeScript is a test failure). 30 | 31 | An `$ExpectType` directive tests the type of the expression on the next line. This prevents unexpected `any` or `{}` types from creeping in. 32 | 33 | ## Usage 34 | 35 | npm install -g typings-checker 36 | typings-checker --project tsconfig.json your-test.ts your-second-test.ts 37 | 38 | ## Options 39 | 40 | --project 41 | Path to the relevant tsconfig.json file 42 | 43 | --allow-expect-error 44 | Enables $ExpectError assertions. These can help pin down behavior but they 45 | also prevent tsc from running over your assertions. Disabled by default. 46 | 47 | ## Development 48 | 49 | ``` 50 | $ npm install -g yarn ts-node 51 | $ yarn 52 | $ ts-node src/index.ts sample.ts 53 | Successes: 6 54 | Failures: 0 55 | ``` 56 | 57 | [1]: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0f756aca1642eaf49998565788caf18ef635271e/underscore/underscore-tests.ts 58 | [FlowTyped]: https://github.com/flowtype/flow-typed/blob/a880b140e32d9d562abbe3924b2c10a583b3a6e1/definitions/npm/underscore_v1.x.x/test_underscore-v1.js 59 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | environment: 3 | YARN_VERSION: 0.18.1 4 | PATH: "${PATH}:${HOME}/.yarn/bin:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin" 5 | 6 | dependencies: 7 | pre: 8 | - | 9 | if [[ ! -e ~/.yarn/bin/yarn || $(yarn --version) != "${YARN_VERSION}" ]]; then 10 | echo "Download and install Yarn." 11 | curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version $YARN_VERSION 12 | else 13 | echo "The correct version of Yarn is already installed." 14 | fi 15 | override: 16 | - yarn install 17 | cache_directories: 18 | - ~/.yarn 19 | - ~/.cache/yarn 20 | 21 | test: 22 | override: 23 | - yarn test 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typings-checker", 3 | "version": "2.0.0", 4 | "description": "Positive and negative assertions about TypeScript types and errors", 5 | "main": "dist/index.js", 6 | "bugs": { 7 | "url": "https://github.com/danvk/typings-checker/issues" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git@github.com:danvk/typings-checker.git" 12 | }, 13 | "scripts": { 14 | "prepublish": "tsc", 15 | "lint": "tslint src/*.ts", 16 | "test": "yarn lint && ./update-tests.sh" 17 | }, 18 | "bin": { 19 | "typings-checker": "dist/index.js" 20 | }, 21 | "author": "Dan Vanderkam (danvdk@gmail.com)", 22 | "license": "ISC", 23 | "tags": [ 24 | "typescript", 25 | "typings", 26 | "definitelytyped" 27 | ], 28 | "devDependencies": { 29 | "@types/chai": "^3.4.34", 30 | "@types/lodash": "^4.14.47", 31 | "@types/mocha": "^2.2.36", 32 | "@types/node": "^7.0.0", 33 | "@types/yargs": "^6.5.0", 34 | "chai": "^3.5.0", 35 | "mocha": "^3.2.0", 36 | "ts-node": "^2.0.0", 37 | "tslint": "^4.3.1", 38 | "typescript": "^2.2.1" 39 | }, 40 | "dependencies": { 41 | "lodash": "^4.17.4", 42 | "yargs": "^6.6.0" 43 | }, 44 | "peerDependencies": { 45 | "typescript": "2.x" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /sample.ts: -------------------------------------------------------------------------------- 1 | // Uncomment this to get some errors: 2 | // let _: any; 3 | 4 | // $ExpectType number 5 | _.find([1, 2, 3], x => x * 1 == 3); 6 | // $ExpectError Operator '==' cannot be applied to types 'number' and 'string'. 7 | _.find([1, 2, 3], x => x == 'a'); 8 | // $ExpectType number 9 | _.find([1, 2, 3], 1); 10 | // $ExpectError Property 'y' does not exist on type '{ x: number; }'. 11 | _.find([{x:1}, {x:2}, {x:3}], v => v.y == 3); 12 | // $ExpectType { x: number; } 13 | _.find([{x:1}, {x:2}, {x:3}], v => v.x == 3); 14 | 15 | function f(x: {a: number}) { 16 | // $ExpectError Property 'b' does not exist 17 | return x.b; 18 | } 19 | -------------------------------------------------------------------------------- /src/checker.ts: -------------------------------------------------------------------------------- 1 | import * as _ from 'lodash'; 2 | import * as ts from 'typescript'; 3 | 4 | import { 5 | Assertion, 6 | Failure, 7 | NodedAssertion, 8 | Report, 9 | } from './types'; 10 | 11 | interface Options { 12 | allowExpectError: boolean; 13 | } 14 | 15 | // Extract information about the type/error assertions in a source file. 16 | // The scanner should be positioned at the start of the file. 17 | export function extractAssertions( 18 | scanner: ts.Scanner, 19 | source: ts.SourceFile, 20 | options: Options, 21 | ): Assertion[] { 22 | const assertions = [] as Assertion[]; 23 | 24 | let isFirstTokenOnLine = true; 25 | let lastLine = -1; 26 | 27 | while (scanner.scan() !== ts.SyntaxKind.EndOfFileToken) { 28 | const token = scanner.getToken(); 29 | if (token === ts.SyntaxKind.WhitespaceTrivia) continue; // ignore leading whitespace. 30 | 31 | const pos = scanner.getTokenPos(); 32 | let { line } = source.getLineAndCharacterOfPosition(pos); 33 | 34 | isFirstTokenOnLine = (line !== lastLine); 35 | lastLine = line; 36 | 37 | if (token === ts.SyntaxKind.SingleLineCommentTrivia) { 38 | const commentText = scanner.getTokenText(); 39 | const m = commentText.match(/^\/\/ \$Expect(Type|Error) (.*)/); 40 | if (!m) continue; 41 | 42 | if (isFirstTokenOnLine) { 43 | line++; // the assertion applies to the next line. 44 | } 45 | 46 | const [, kind, text] = m; 47 | 48 | if (kind === 'Error' && !options.allowExpectError) { 49 | throw new Error(`Found $ExpectError assertion at ${source.fileName}:${line 50 | } but --allow-expect-error was not set.`); 51 | } 52 | if (kind === 'Type') { 53 | assertions.push({ kind: 'type', type: text, line }); 54 | } else if (kind === 'Error') { 55 | assertions.push({ kind: 'error', pattern: text, line }); 56 | } 57 | } 58 | } 59 | return assertions; 60 | } 61 | 62 | export function attachNodesToAssertions( 63 | source: ts.SourceFile, 64 | checker: ts.TypeChecker, 65 | assertions: Assertion[], 66 | ): NodedAssertion[] { 67 | const nodedAssertions = [] as NodedAssertion[]; 68 | 69 | // Match assertions to the first node that appears on the line they apply to. 70 | function collectNodes(node: ts.Node) { 71 | if (node.kind !== ts.SyntaxKind.SourceFile) { 72 | const pos = node.getStart(); 73 | const { line } = source.getLineAndCharacterOfPosition(pos); 74 | const assertionIndex = _.findIndex(assertions, {line}); 75 | if (assertionIndex >= 0) { 76 | const assertion = assertions[assertionIndex]; 77 | const type = checker.getTypeAtLocation(node.getChildren()[0]); 78 | nodedAssertions.push({ node, assertion, type }); 79 | assertions.splice(assertionIndex, 1); 80 | } 81 | } 82 | 83 | ts.forEachChild(node, child => { collectNodes(child); }); 84 | return nodedAssertions; 85 | } 86 | 87 | collectNodes(source); 88 | if (assertions.length) { 89 | const prettyAssertions = assertions.map(assertion => { 90 | let msg: string; 91 | if (assertion.kind === 'type') { 92 | msg = `$ExpectType ${assertion.type}`; 93 | } else { 94 | msg = `$ExpectError ${assertion.pattern}`; 95 | } 96 | return `{assertion.line + 1}: ${msg}`; 97 | }); 98 | console.error(JSON.stringify(prettyAssertions, null, '\t')); 99 | throw new Error('Unable to attach nodes to all assertions.'); 100 | } 101 | 102 | return nodedAssertions; 103 | } 104 | 105 | export function generateReport( 106 | checker: ts.TypeChecker, 107 | nodedAssertions: NodedAssertion[], 108 | diagnostics: ts.Diagnostic[], 109 | ): Report { 110 | const failures = [] as Failure[]; 111 | let numSuccesses = 0; 112 | 113 | // Attach errors to nodes; if this isn't possible, then the error was unexpected. 114 | for (const diagnostic of diagnostics) { 115 | const line = diagnostic.file && 116 | diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start).line; 117 | 118 | const nodedAssertion = _.find(nodedAssertions, {assertion: {line}} as any); 119 | if (nodedAssertion) { 120 | nodedAssertion.error = diagnostic; 121 | } else { 122 | const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); 123 | failures.push({ 124 | type: 'UNEXPECTED_ERROR', 125 | line, 126 | message, 127 | }); 128 | } 129 | } 130 | 131 | // Go through and check all the assertions. 132 | for (const noded of nodedAssertions) { 133 | const { assertion, type, error, node } = noded; 134 | const line = assertion.line; 135 | const code = node.getText(); 136 | if (assertion.kind === 'error') { 137 | if (!error) { 138 | failures.push({ 139 | type: 'MISSING_ERROR', 140 | line, 141 | code, 142 | message: assertion.pattern, 143 | }); 144 | } else { 145 | const message = ts.flattenDiagnosticMessageText(error.messageText, '\n'); 146 | if (message.indexOf(assertion.pattern) === -1) { 147 | failures.push({ 148 | type: 'WRONG_ERROR', 149 | line, 150 | code, 151 | expectedMessage: assertion.pattern, 152 | actualMessage: message, 153 | }); 154 | } else { 155 | numSuccesses++; 156 | } 157 | } 158 | } else if (assertion.kind === 'type') { 159 | const actualType = checker.typeToString(type); 160 | if (actualType !== assertion.type) { 161 | failures.push({ 162 | type: 'WRONG_TYPE', 163 | line, 164 | code, 165 | expectedType: assertion.type, 166 | actualType, 167 | }); 168 | } else { 169 | numSuccesses++; 170 | } 171 | } 172 | } 173 | 174 | failures.sort((a, b) => a.line - b.line); 175 | 176 | return { numSuccesses, failures }; 177 | } 178 | 179 | /** 180 | * Check a single TypeScript source file for typings assertions and errors. 181 | * 182 | * The file passes the checks if report.failures.length === 0. 183 | */ 184 | export default function checkFile( 185 | source: ts.SourceFile, 186 | scanner: ts.Scanner, 187 | checker: ts.TypeChecker, 188 | diagnostics: ts.Diagnostic[], 189 | options: Options, 190 | ): Report { 191 | const assertions = extractAssertions(scanner, source, options); 192 | const nodedAssertions = attachNodesToAssertions(source, checker, assertions); 193 | return generateReport(checker, nodedAssertions, diagnostics); 194 | } 195 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /** 3 | * This script reads a TypeScript file and verifies that it produces the expected types and errors. 4 | * 5 | * Usage: 6 | * 7 | * typings-checker yourtsfile.ts 8 | * 9 | * The exit code indicates whether all assertions passed. 10 | */ 11 | 12 | import * as ts from 'typescript'; 13 | import * as yargs from 'yargs'; 14 | 15 | import checkFile from './checker'; 16 | 17 | const argv = yargs 18 | .usage('Usage: [options]') 19 | .alias('p', 'project') 20 | .describe('p', 'Path to the tsconfig.json file for your project') 21 | .boolean('allow-expect-error') 22 | .describe('allow-expect-error', 23 | 'Enable $ExpectError assertions. Setting this option means that ' + 24 | 'it\'s possible for code to be accepted by typings-checker but not ' + 25 | 'tsc.') 26 | .help() 27 | .argv; 28 | 29 | if (argv._.length === 0) { 30 | yargs.showHelp(); 31 | process.exit(-1); 32 | } 33 | 34 | const tsFiles = argv._; 35 | const { project } = argv; 36 | const allowExpectError = argv['allow-expect-error']; 37 | 38 | // read options from a tsconfig.json file. 39 | // TOOD: make this optional, just like tsc. 40 | const unParsedConfig = ts.readConfigFile(project || 'tsconfig.json', ts.sys.readFile).config || {}; 41 | const { options } = ts.parseJsonConfigFileContent(unParsedConfig, ts.sys, process.cwd()); 42 | const host = ts.createCompilerHost(options, true); 43 | let totalNumFailures = 0; 44 | tsFiles.forEach((tsFile: string) => { 45 | 46 | const program = ts.createProgram([tsFile], options, host); 47 | const source = program.getSourceFile(tsFile); 48 | if (!source) { 49 | console.error(`could not load content of ${tsFile}`); 50 | process.exit(1); 51 | } 52 | const languageVersion = options.target || ts.ScriptTarget.ES5; 53 | const scanner = ts.createScanner( 54 | languageVersion, false, source.languageVariant, source.getFullText()); 55 | 56 | const checker = program.getTypeChecker(); 57 | const diagnostics = ts.getPreEmitDiagnostics(program); 58 | 59 | const typingsOptions = { 60 | allowExpectError, 61 | }; 62 | 63 | const report = checkFile(source, scanner, checker, diagnostics, typingsOptions); 64 | for (const failure of report.failures) { 65 | const { line } = failure; 66 | let message: string; 67 | switch (failure.type) { 68 | case 'UNEXPECTED_ERROR': 69 | message = `Unexpected error\n ${failure.message}`; 70 | break; 71 | case 'MISSING_ERROR': 72 | message = `Expected error ${failure.message}`; 73 | break; 74 | case 'WRONG_ERROR': 75 | message = `Expected error\n ${failure.expectedMessage 76 | }\nbut got:\n ${failure.actualMessage}`; 77 | break; 78 | case 'WRONG_TYPE': 79 | message = `Expected type\n ${failure.expectedType}\nbut got:\n ${failure.actualType}`; 80 | break; 81 | } 82 | console.error(`${tsFile}:${line + 1}: ${message}\n`); 83 | } 84 | 85 | const numFailures = report.failures.length; 86 | const numTotal = report.numSuccesses + numFailures; 87 | console.log(`${tsFile}: ${report.numSuccesses} / ${numTotal} checks passed.`); 88 | totalNumFailures = totalNumFailures + numFailures; 89 | }); 90 | process.exit(totalNumFailures); 91 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import * as ts from 'typescript'; 2 | 3 | export interface LineNumber { 4 | line: number; // 0-based 5 | } 6 | 7 | export interface IAssertion extends LineNumber { 8 | kind: string; 9 | } 10 | 11 | export interface TypeAssertion extends IAssertion { 12 | kind: 'type'; 13 | type: string; 14 | } 15 | 16 | export interface ErrorAssertion extends IAssertion { 17 | kind: 'error'; 18 | pattern: string; 19 | } 20 | 21 | export type Assertion = TypeAssertion | ErrorAssertion; 22 | 23 | export interface NodedAssertion { 24 | assertion: Assertion; 25 | node: ts.Node; 26 | type: ts.Type; 27 | error?: ts.Diagnostic; 28 | } 29 | 30 | export interface IFailure extends LineNumber { 31 | code?: string; 32 | type: string; 33 | } 34 | 35 | export interface WrongTypeFailure extends IFailure { 36 | type: 'WRONG_TYPE'; 37 | expectedType: string; 38 | actualType: string; 39 | } 40 | 41 | export interface UnexpectedErrorFailure extends IFailure { 42 | type: 'UNEXPECTED_ERROR'; 43 | message: string; 44 | } 45 | 46 | export interface WrongErrorFailure extends IFailure { 47 | type: 'WRONG_ERROR'; 48 | expectedMessage: string; 49 | actualMessage: string; 50 | } 51 | 52 | export interface MissingErrorFailure extends IFailure { 53 | type: 'MISSING_ERROR'; 54 | message: string; 55 | } 56 | 57 | export type Failure = 58 | WrongTypeFailure | 59 | UnexpectedErrorFailure | 60 | WrongErrorFailure | 61 | MissingErrorFailure; 62 | 63 | export interface Report { 64 | numSuccesses: number; 65 | failures: Failure[]; 66 | } 67 | -------------------------------------------------------------------------------- /tests/basics/expected-error.ts: -------------------------------------------------------------------------------- 1 | // This file contains an error which is expected to be caught. 2 | 3 | const x = {a: 'a', b: 2}; 4 | // $ExpectError Property 'c' does not exist 5 | x.c 6 | -------------------------------------------------------------------------------- /tests/basics/expected-error.ts.out: -------------------------------------------------------------------------------- 1 | tests/basics/expected-error.ts: 1 / 1 checks passed. 2 | -------------------------------------------------------------------------------- /tests/basics/inline-assertion.ts: -------------------------------------------------------------------------------- 1 | // This checks the types of parameters to a callback using inline assertions. 2 | 3 | function mapObject( 4 | o: T, 5 | callback: (val: T[keyof T], key: keyof T, collection: T) => U 6 | ): {[k in keyof T]: U} { 7 | return {} as any; 8 | } 9 | 10 | // $ExpectType { a: string; b: string; } 11 | mapObject({a: 1, b: 2}, ( 12 | val, // $ExpectType number 13 | key, // $ExpectType "a" | "b" 14 | c, // $ExpectType { a: number; b: number; } 15 | ) => '' + val); 16 | -------------------------------------------------------------------------------- /tests/basics/inline-assertion.ts.out: -------------------------------------------------------------------------------- 1 | tests/basics/inline-assertion.ts: 4 / 4 checks passed. 2 | -------------------------------------------------------------------------------- /tests/basics/sanity.ts: -------------------------------------------------------------------------------- 1 | // (this file has no errors and no type/error assertions) 2 | function foo() { 3 | return true; 4 | } 5 | -------------------------------------------------------------------------------- /tests/basics/sanity.ts.out: -------------------------------------------------------------------------------- 1 | tests/basics/sanity.ts: 0 / 0 checks passed. 2 | -------------------------------------------------------------------------------- /tests/basics/type-assertion-failure.ts: -------------------------------------------------------------------------------- 1 | // This contains a type assertion which matches. 2 | 3 | let v: number; 4 | 5 | // $ExpectType string 6 | v 7 | -------------------------------------------------------------------------------- /tests/basics/type-assertion-failure.ts.out: -------------------------------------------------------------------------------- 1 | tests/basics/type-assertion-failure.ts:6: Expected type 2 | string 3 | but got: 4 | number 5 | 6 | tests/basics/type-assertion-failure.ts: 0 / 1 checks passed. 7 | -------------------------------------------------------------------------------- /tests/basics/type-assertion.ts: -------------------------------------------------------------------------------- 1 | // This contains a type assertion which matches. 2 | 3 | let v: number; 4 | 5 | // $ExpectType number 6 | v 7 | -------------------------------------------------------------------------------- /tests/basics/type-assertion.ts.out: -------------------------------------------------------------------------------- 1 | tests/basics/type-assertion.ts: 1 / 1 checks passed. 2 | -------------------------------------------------------------------------------- /tests/basics/unexpected-error.ts: -------------------------------------------------------------------------------- 1 | // This file contains an error which isn't marked. 2 | // It should result in a failure. 3 | 4 | const x = {a: 'a', b: 2}; 5 | x.c 6 | -------------------------------------------------------------------------------- /tests/basics/unexpected-error.ts.out: -------------------------------------------------------------------------------- 1 | tests/basics/unexpected-error.ts:5: Unexpected error 2 | Property 'c' does not exist on type '{ a: string; b: number; }'. 3 | 4 | tests/basics/unexpected-error.ts: 0 / 1 checks passed. 5 | -------------------------------------------------------------------------------- /tests/doesnt-exist.ts.out: -------------------------------------------------------------------------------- 1 | could not load content of doesnt_exist.ts 2 | -------------------------------------------------------------------------------- /tests/multiple.out: -------------------------------------------------------------------------------- 1 | tests/basics/expected-error.ts: 1 / 1 checks passed. 2 | tests/basics/inline-assertion.ts: 4 / 4 checks passed. 3 | tests/basics/sanity.ts: 0 / 0 checks passed. 4 | tests/basics/type-assertion-failure.ts:6: Expected type 5 | string 6 | but got: 7 | number 8 | 9 | tests/basics/type-assertion-failure.ts: 0 / 1 checks passed. 10 | tests/basics/type-assertion.ts: 1 / 1 checks passed. 11 | tests/basics/unexpected-error.ts:5: Unexpected error 12 | Property 'c' does not exist on type '{ a: string; b: number; }'. 13 | 14 | tests/basics/unexpected-error.ts: 0 / 1 checks passed. 15 | tests/ramda.ts: 3 / 3 checks passed. 16 | tests/underscore-any.ts:7: Expected type 17 | number 18 | but got: 19 | any 20 | 21 | tests/underscore-any.ts:9: Expected error Operator '==' cannot be applied to types 'number' and 'string'. 22 | 23 | tests/underscore-any.ts:11: Expected type 24 | number 25 | but got: 26 | any 27 | 28 | tests/underscore-any.ts:13: Expected error Property 'y' does not exist on type '{ x: number; }'. 29 | 30 | tests/underscore-any.ts:15: Expected type 31 | { x: number; } 32 | but got: 33 | any 34 | 35 | tests/underscore-any.ts: 0 / 5 checks passed. 36 | tests/underscore.ts: 5 / 5 checks passed. 37 | -------------------------------------------------------------------------------- /tests/ramda.ts: -------------------------------------------------------------------------------- 1 | const R = { 2 | isArrayLike(x: any) { return true; }, 3 | }; 4 | 5 | () => { 6 | // $ExpectType boolean 7 | R.isArrayLike('a'); 8 | // $ExpectType boolean 9 | R.isArrayLike([1,2,3]); 10 | // $ExpectType boolean 11 | R.isArrayLike([]); 12 | }; 13 | -------------------------------------------------------------------------------- /tests/ramda.ts.out: -------------------------------------------------------------------------------- 1 | tests/ramda.ts: 3 / 3 checks passed. 2 | -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": ".", 4 | "rootDir": ".", 5 | "noEmit": true, 6 | "module": "commonjs", 7 | "target": "es5", 8 | "noImplicitAny": false, 9 | "sourceMap": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/underscore-any.ts: -------------------------------------------------------------------------------- 1 | // This test assigns an opaque type to lodash/underscore. 2 | // This means that it will pass TypeScript's static analysis. 3 | // But it won't pass the typings-checker, which doesn't allow 'any'. 4 | let _: any; 5 | 6 | // $ExpectType number 7 | _.find([1, 2, 3], x => x * 1 == 3); 8 | // $ExpectError Operator '==' cannot be applied to types 'number' and 'string'. 9 | _.find([1, 2, 3], x => x == 'a'); 10 | // $ExpectType number 11 | _.find([1, 2, 3], 1); 12 | // $ExpectError Property 'y' does not exist on type '{ x: number; }'. 13 | _.find([{x:1}, {x:2}, {x:3}], v => v.y == 3); 14 | // $ExpectType { x: number; } 15 | _.find([{x:1}, {x:2}, {x:3}], v => v.x == 3); 16 | -------------------------------------------------------------------------------- /tests/underscore-any.ts.out: -------------------------------------------------------------------------------- 1 | tests/underscore-any.ts:7: Expected type 2 | number 3 | but got: 4 | any 5 | 6 | tests/underscore-any.ts:9: Expected error Operator '==' cannot be applied to types 'number' and 'string'. 7 | 8 | tests/underscore-any.ts:11: Expected type 9 | number 10 | but got: 11 | any 12 | 13 | tests/underscore-any.ts:13: Expected error Property 'y' does not exist on type '{ x: number; }'. 14 | 15 | tests/underscore-any.ts:15: Expected type 16 | { x: number; } 17 | but got: 18 | any 19 | 20 | tests/underscore-any.ts: 0 / 5 checks passed. 21 | -------------------------------------------------------------------------------- /tests/underscore.ts: -------------------------------------------------------------------------------- 1 | // This checks a few properties of the lodash typings. 2 | 3 | // $ExpectType number 4 | _.find([1, 2, 3], x => x * 1 == 3); 5 | // $ExpectError Operator '==' cannot be applied to types 'number' and 'string'. 6 | _.find([1, 2, 3], x => x == 'a'); 7 | // $ExpectType number 8 | _.find([1, 2, 3], 1); 9 | // $ExpectError Property 'y' does not exist on type '{ x: number; }'. 10 | _.find([{x:1}, {x:2}, {x:3}], v => v.y == 3); 11 | // $ExpectType { x: number; } 12 | _.find([{x:1}, {x:2}, {x:3}], v => v.x == 3); 13 | -------------------------------------------------------------------------------- /tests/underscore.ts.out: -------------------------------------------------------------------------------- 1 | tests/underscore.ts: 5 / 5 checks passed. 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "noImplicitAny": true, 6 | "outDir": "dist", 7 | "rootDir": "src", 8 | "sourceMap": false, 9 | "noUnusedLocals": true, 10 | "noEmit": false 11 | }, 12 | "exclude": [ 13 | "sample.ts", 14 | "tests", 15 | "node_modules" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:recommended" 4 | ], 5 | "rules": { 6 | // Rules where we disagree with tslint:recommended 7 | "curly": false, 8 | "quotemark": [true, "single", "jsx-single", "avoid-escape" ], 9 | "indent": [true, "spaces"], 10 | "triple-equals": true, 11 | "max-line-length": [true, 100], 12 | "interface-name": false, 13 | "object-literal-sort-keys": false, 14 | // no parens required around one param lambdas. 15 | "arrow-parens": [true, "ban-single-arg-parens"], 16 | "only-arrow-functions": [ 17 | true, 18 | "allow-named-functions" 19 | ], 20 | "no-console": false, 21 | "switch-default": false, 22 | 23 | // New rules that we add beyond tslint:recommended 24 | "no-angle-bracket-type-assertion": true, 25 | "interface-over-type-literal": true, 26 | "space-before-function-paren": [true, "never"], 27 | "import-spacing": true, 28 | "no-string-throw": true, 29 | "prefer-const": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /update-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o errexit 3 | node_modules/.bin/tsc 4 | set +o errexit 5 | 6 | for test in $(find tests -name '*.ts'); do 7 | echo $test 8 | node dist/index.js --allow-expect-error --project tests/tsconfig.json $test > $test.out 2>&1 9 | done 10 | 11 | echo "testing multiple files" 12 | node dist/index.js --allow-expect-error --project tests/tsconfig.json $(find tests -name '*.ts') > tests/multiple.out 2>&1 13 | 14 | # test wrong file path 15 | node dist/index.js doesnt_exist.ts > tests/doesnt-exist.ts.out 2>&1 16 | 17 | # This shows changes and sets the exit code. 18 | set -o errexit 19 | git --no-pager diff -- tests 20 | 21 | git status 22 | if [ -n "$(git status --porcelain)" ]; then 23 | # this will catch a missing .ts.out file, for example. 24 | echo Unexpected changes 25 | exit 1 26 | fi 27 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/chai@^3.4.34": 6 | version "3.4.34" 7 | resolved "https://registry.yarnpkg.com/@types/chai/-/chai-3.4.34.tgz#d5335792823bb09cddd5e38c3d211b709183854d" 8 | 9 | "@types/lodash@^4.14.47": 10 | version "4.14.50" 11 | resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.50.tgz#2227da4d65fafe249bccd59c7b9396e27674c8f7" 12 | 13 | "@types/mocha@^2.2.36": 14 | version "2.2.37" 15 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.37.tgz#8e0d5327ffa0734999c1010967853de917f3a38e" 16 | 17 | "@types/node@^7.0.0": 18 | version "7.0.0" 19 | resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.0.tgz#c081147b109da5f9c57af70571771be97ce9c0ba" 20 | 21 | "@types/yargs@^6.5.0": 22 | version "6.5.0" 23 | resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-6.5.0.tgz#308b17d5ca469f49ef76460baba793cb75657887" 24 | 25 | ansi-align@^1.1.0: 26 | version "1.1.0" 27 | resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba" 28 | dependencies: 29 | string-width "^1.0.1" 30 | 31 | ansi-regex@^2.0.0: 32 | version "2.0.0" 33 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107" 34 | 35 | ansi-styles@^2.2.1: 36 | version "2.2.1" 37 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 38 | 39 | any-promise@^1.3.0: 40 | version "1.3.0" 41 | resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" 42 | 43 | arrify@^1.0.0: 44 | version "1.0.1" 45 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 46 | 47 | assertion-error@^1.0.1: 48 | version "1.0.2" 49 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" 50 | 51 | babel-code-frame@^6.20.0: 52 | version "6.22.0" 53 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" 54 | dependencies: 55 | chalk "^1.1.0" 56 | esutils "^2.0.2" 57 | js-tokens "^3.0.0" 58 | 59 | balanced-match@^0.4.1: 60 | version "0.4.2" 61 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 62 | 63 | boxen@^0.6.0: 64 | version "0.6.0" 65 | resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.6.0.tgz#8364d4248ac34ff0ef1b2f2bf49a6c60ce0d81b6" 66 | dependencies: 67 | ansi-align "^1.1.0" 68 | camelcase "^2.1.0" 69 | chalk "^1.1.1" 70 | cli-boxes "^1.0.0" 71 | filled-array "^1.0.0" 72 | object-assign "^4.0.1" 73 | repeating "^2.0.0" 74 | string-width "^1.0.1" 75 | widest-line "^1.0.0" 76 | 77 | brace-expansion@^1.0.0: 78 | version "1.1.6" 79 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" 80 | dependencies: 81 | balanced-match "^0.4.1" 82 | concat-map "0.0.1" 83 | 84 | browser-stdout@1.3.0: 85 | version "1.3.0" 86 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" 87 | 88 | buffer-shims@^1.0.0: 89 | version "1.0.0" 90 | resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" 91 | 92 | builtin-modules@^1.0.0: 93 | version "1.1.1" 94 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 95 | 96 | camelcase@^2.1.0: 97 | version "2.1.1" 98 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" 99 | 100 | camelcase@^3.0.0: 101 | version "3.0.0" 102 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" 103 | 104 | capture-stack-trace@^1.0.0: 105 | version "1.0.0" 106 | resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" 107 | 108 | chai@^3.5.0: 109 | version "3.5.0" 110 | resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" 111 | dependencies: 112 | assertion-error "^1.0.1" 113 | deep-eql "^0.1.3" 114 | type-detect "^1.0.0" 115 | 116 | chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1: 117 | version "1.1.3" 118 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 119 | dependencies: 120 | ansi-styles "^2.2.1" 121 | escape-string-regexp "^1.0.2" 122 | has-ansi "^2.0.0" 123 | strip-ansi "^3.0.0" 124 | supports-color "^2.0.0" 125 | 126 | cli-boxes@^1.0.0: 127 | version "1.0.0" 128 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" 129 | 130 | cliui@^3.2.0: 131 | version "3.2.0" 132 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" 133 | dependencies: 134 | string-width "^1.0.1" 135 | strip-ansi "^3.0.1" 136 | wrap-ansi "^2.0.0" 137 | 138 | code-point-at@^1.0.0: 139 | version "1.1.0" 140 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 141 | 142 | colors@^1.1.2: 143 | version "1.1.2" 144 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" 145 | 146 | commander@2.9.0: 147 | version "2.9.0" 148 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" 149 | dependencies: 150 | graceful-readlink ">= 1.0.0" 151 | 152 | concat-map@0.0.1: 153 | version "0.0.1" 154 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 155 | 156 | configstore@^2.0.0: 157 | version "2.1.0" 158 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" 159 | dependencies: 160 | dot-prop "^3.0.0" 161 | graceful-fs "^4.1.2" 162 | mkdirp "^0.5.0" 163 | object-assign "^4.0.1" 164 | os-tmpdir "^1.0.0" 165 | osenv "^0.1.0" 166 | uuid "^2.0.1" 167 | write-file-atomic "^1.1.2" 168 | xdg-basedir "^2.0.0" 169 | 170 | core-util-is@~1.0.0: 171 | version "1.0.2" 172 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 173 | 174 | create-error-class@^3.0.1: 175 | version "3.0.2" 176 | resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" 177 | dependencies: 178 | capture-stack-trace "^1.0.0" 179 | 180 | debug@2.2.0: 181 | version "2.2.0" 182 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" 183 | dependencies: 184 | ms "0.7.1" 185 | 186 | decamelize@^1.1.1: 187 | version "1.2.0" 188 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 189 | 190 | deep-eql@^0.1.3: 191 | version "0.1.3" 192 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" 193 | dependencies: 194 | type-detect "0.1.1" 195 | 196 | deep-extend@~0.4.0: 197 | version "0.4.1" 198 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" 199 | 200 | diff@1.4.0: 201 | version "1.4.0" 202 | resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" 203 | 204 | diff@^3.0.1, diff@^3.1.0: 205 | version "3.2.0" 206 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" 207 | 208 | dot-prop@^3.0.0: 209 | version "3.0.0" 210 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" 211 | dependencies: 212 | is-obj "^1.0.0" 213 | 214 | duplexer2@^0.1.4: 215 | version "0.1.4" 216 | resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" 217 | dependencies: 218 | readable-stream "^2.0.2" 219 | 220 | error-ex@^1.2.0: 221 | version "1.3.0" 222 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" 223 | dependencies: 224 | is-arrayish "^0.2.1" 225 | 226 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2: 227 | version "1.0.5" 228 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 229 | 230 | esutils@^2.0.2: 231 | version "2.0.2" 232 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 233 | 234 | filled-array@^1.0.0: 235 | version "1.1.0" 236 | resolved "https://registry.yarnpkg.com/filled-array/-/filled-array-1.1.0.tgz#c3c4f6c663b923459a9aa29912d2d031f1507f84" 237 | 238 | find-up@^1.0.0: 239 | version "1.1.2" 240 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" 241 | dependencies: 242 | path-exists "^2.0.0" 243 | pinkie-promise "^2.0.0" 244 | 245 | findup-sync@~0.3.0: 246 | version "0.3.0" 247 | resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16" 248 | dependencies: 249 | glob "~5.0.0" 250 | 251 | fs.realpath@^1.0.0: 252 | version "1.0.0" 253 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 254 | 255 | get-caller-file@^1.0.1: 256 | version "1.0.2" 257 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" 258 | 259 | glob@7.0.5: 260 | version "7.0.5" 261 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.5.tgz#b4202a69099bbb4d292a7c1b95b6682b67ebdc95" 262 | dependencies: 263 | fs.realpath "^1.0.0" 264 | inflight "^1.0.4" 265 | inherits "2" 266 | minimatch "^3.0.2" 267 | once "^1.3.0" 268 | path-is-absolute "^1.0.0" 269 | 270 | glob@^7.1.1: 271 | version "7.1.1" 272 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 273 | dependencies: 274 | fs.realpath "^1.0.0" 275 | inflight "^1.0.4" 276 | inherits "2" 277 | minimatch "^3.0.2" 278 | once "^1.3.0" 279 | path-is-absolute "^1.0.0" 280 | 281 | glob@~5.0.0: 282 | version "5.0.15" 283 | resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" 284 | dependencies: 285 | inflight "^1.0.4" 286 | inherits "2" 287 | minimatch "2 || 3" 288 | once "^1.3.0" 289 | path-is-absolute "^1.0.0" 290 | 291 | got@^5.0.0: 292 | version "5.7.1" 293 | resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35" 294 | dependencies: 295 | create-error-class "^3.0.1" 296 | duplexer2 "^0.1.4" 297 | is-redirect "^1.0.0" 298 | is-retry-allowed "^1.0.0" 299 | is-stream "^1.0.0" 300 | lowercase-keys "^1.0.0" 301 | node-status-codes "^1.0.0" 302 | object-assign "^4.0.1" 303 | parse-json "^2.1.0" 304 | pinkie-promise "^2.0.0" 305 | read-all-stream "^3.0.0" 306 | readable-stream "^2.0.5" 307 | timed-out "^3.0.0" 308 | unzip-response "^1.0.2" 309 | url-parse-lax "^1.0.0" 310 | 311 | graceful-fs@^4.1.11, graceful-fs@^4.1.2: 312 | version "4.1.11" 313 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 314 | 315 | "graceful-readlink@>= 1.0.0": 316 | version "1.0.1" 317 | resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" 318 | 319 | growl@1.9.2: 320 | version "1.9.2" 321 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" 322 | 323 | has-ansi@^2.0.0: 324 | version "2.0.0" 325 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 326 | dependencies: 327 | ansi-regex "^2.0.0" 328 | 329 | has-flag@^1.0.0: 330 | version "1.0.0" 331 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 332 | 333 | hosted-git-info@^2.1.4: 334 | version "2.1.5" 335 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" 336 | 337 | imurmurhash@^0.1.4: 338 | version "0.1.4" 339 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 340 | 341 | inflight@^1.0.4: 342 | version "1.0.6" 343 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 344 | dependencies: 345 | once "^1.3.0" 346 | wrappy "1" 347 | 348 | inherits@2, inherits@~2.0.1: 349 | version "2.0.3" 350 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 351 | 352 | ini@~1.3.0: 353 | version "1.3.4" 354 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" 355 | 356 | invert-kv@^1.0.0: 357 | version "1.0.0" 358 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" 359 | 360 | is-arrayish@^0.2.1: 361 | version "0.2.1" 362 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 363 | 364 | is-builtin-module@^1.0.0: 365 | version "1.0.0" 366 | resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" 367 | dependencies: 368 | builtin-modules "^1.0.0" 369 | 370 | is-finite@^1.0.0: 371 | version "1.0.2" 372 | resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" 373 | dependencies: 374 | number-is-nan "^1.0.0" 375 | 376 | is-fullwidth-code-point@^1.0.0: 377 | version "1.0.0" 378 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 379 | dependencies: 380 | number-is-nan "^1.0.0" 381 | 382 | is-npm@^1.0.0: 383 | version "1.0.0" 384 | resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" 385 | 386 | is-obj@^1.0.0: 387 | version "1.0.1" 388 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" 389 | 390 | is-redirect@^1.0.0: 391 | version "1.0.0" 392 | resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" 393 | 394 | is-retry-allowed@^1.0.0: 395 | version "1.1.0" 396 | resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" 397 | 398 | is-stream@^1.0.0: 399 | version "1.1.0" 400 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 401 | 402 | is-utf8@^0.2.0: 403 | version "0.2.1" 404 | resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" 405 | 406 | isarray@~1.0.0: 407 | version "1.0.0" 408 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 409 | 410 | js-tokens@^3.0.0: 411 | version "3.0.0" 412 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.0.tgz#a2f2a969caae142fb3cd56228358c89366957bd1" 413 | 414 | json3@3.3.2: 415 | version "3.3.2" 416 | resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" 417 | 418 | latest-version@^2.0.0: 419 | version "2.0.0" 420 | resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-2.0.0.tgz#56f8d6139620847b8017f8f1f4d78e211324168b" 421 | dependencies: 422 | package-json "^2.0.0" 423 | 424 | lazy-req@^1.1.0: 425 | version "1.1.0" 426 | resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac" 427 | 428 | lcid@^1.0.0: 429 | version "1.0.0" 430 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" 431 | dependencies: 432 | invert-kv "^1.0.0" 433 | 434 | load-json-file@^1.0.0: 435 | version "1.1.0" 436 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" 437 | dependencies: 438 | graceful-fs "^4.1.2" 439 | parse-json "^2.2.0" 440 | pify "^2.0.0" 441 | pinkie-promise "^2.0.0" 442 | strip-bom "^2.0.0" 443 | 444 | lodash._baseassign@^3.0.0: 445 | version "3.2.0" 446 | resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" 447 | dependencies: 448 | lodash._basecopy "^3.0.0" 449 | lodash.keys "^3.0.0" 450 | 451 | lodash._basecopy@^3.0.0: 452 | version "3.0.1" 453 | resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" 454 | 455 | lodash._basecreate@^3.0.0: 456 | version "3.0.3" 457 | resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" 458 | 459 | lodash._getnative@^3.0.0: 460 | version "3.9.1" 461 | resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" 462 | 463 | lodash._isiterateecall@^3.0.0: 464 | version "3.0.9" 465 | resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" 466 | 467 | lodash.create@3.1.1: 468 | version "3.1.1" 469 | resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" 470 | dependencies: 471 | lodash._baseassign "^3.0.0" 472 | lodash._basecreate "^3.0.0" 473 | lodash._isiterateecall "^3.0.0" 474 | 475 | lodash.isarguments@^3.0.0: 476 | version "3.1.0" 477 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" 478 | 479 | lodash.isarray@^3.0.0: 480 | version "3.0.4" 481 | resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" 482 | 483 | lodash.keys@^3.0.0: 484 | version "3.1.2" 485 | resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" 486 | dependencies: 487 | lodash._getnative "^3.0.0" 488 | lodash.isarguments "^3.0.0" 489 | lodash.isarray "^3.0.0" 490 | 491 | lodash@^4.17.4: 492 | version "4.17.4" 493 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 494 | 495 | lowercase-keys@^1.0.0: 496 | version "1.0.0" 497 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" 498 | 499 | make-error@^1.1.1: 500 | version "1.2.1" 501 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.2.1.tgz#9a6dfb4844423b9f145806728d05c6e935670e75" 502 | 503 | "minimatch@2 || 3", minimatch@^3.0.2: 504 | version "3.0.3" 505 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" 506 | dependencies: 507 | brace-expansion "^1.0.0" 508 | 509 | minimist@0.0.8, minimist@~0.0.1: 510 | version "0.0.8" 511 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 512 | 513 | minimist@^1.2.0: 514 | version "1.2.0" 515 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 516 | 517 | mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: 518 | version "0.5.1" 519 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 520 | dependencies: 521 | minimist "0.0.8" 522 | 523 | mocha@^3.2.0: 524 | version "3.2.0" 525 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.2.0.tgz#7dc4f45e5088075171a68896814e6ae9eb7a85e3" 526 | dependencies: 527 | browser-stdout "1.3.0" 528 | commander "2.9.0" 529 | debug "2.2.0" 530 | diff "1.4.0" 531 | escape-string-regexp "1.0.5" 532 | glob "7.0.5" 533 | growl "1.9.2" 534 | json3 "3.3.2" 535 | lodash.create "3.1.1" 536 | mkdirp "0.5.1" 537 | supports-color "3.1.2" 538 | 539 | ms@0.7.1: 540 | version "0.7.1" 541 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" 542 | 543 | node-status-codes@^1.0.0: 544 | version "1.0.0" 545 | resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f" 546 | 547 | normalize-package-data@^2.3.2: 548 | version "2.3.5" 549 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" 550 | dependencies: 551 | hosted-git-info "^2.1.4" 552 | is-builtin-module "^1.0.0" 553 | semver "2 || 3 || 4 || 5" 554 | validate-npm-package-license "^3.0.1" 555 | 556 | number-is-nan@^1.0.0: 557 | version "1.0.1" 558 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 559 | 560 | object-assign@^4.0.1: 561 | version "4.1.1" 562 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 563 | 564 | once@^1.3.0: 565 | version "1.4.0" 566 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 567 | dependencies: 568 | wrappy "1" 569 | 570 | optimist@~0.6.0: 571 | version "0.6.1" 572 | resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" 573 | dependencies: 574 | minimist "~0.0.1" 575 | wordwrap "~0.0.2" 576 | 577 | os-homedir@^1.0.0: 578 | version "1.0.2" 579 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 580 | 581 | os-locale@^1.4.0: 582 | version "1.4.0" 583 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" 584 | dependencies: 585 | lcid "^1.0.0" 586 | 587 | os-tmpdir@^1.0.0: 588 | version "1.0.2" 589 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 590 | 591 | osenv@^0.1.0: 592 | version "0.1.4" 593 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" 594 | dependencies: 595 | os-homedir "^1.0.0" 596 | os-tmpdir "^1.0.0" 597 | 598 | package-json@^2.0.0: 599 | version "2.4.0" 600 | resolved "https://registry.yarnpkg.com/package-json/-/package-json-2.4.0.tgz#0d15bd67d1cbbddbb2ca222ff2edb86bcb31a8bb" 601 | dependencies: 602 | got "^5.0.0" 603 | registry-auth-token "^3.0.1" 604 | registry-url "^3.0.3" 605 | semver "^5.1.0" 606 | 607 | parse-json@^2.1.0, parse-json@^2.2.0: 608 | version "2.2.0" 609 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" 610 | dependencies: 611 | error-ex "^1.2.0" 612 | 613 | path-exists@^2.0.0: 614 | version "2.1.0" 615 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" 616 | dependencies: 617 | pinkie-promise "^2.0.0" 618 | 619 | path-is-absolute@^1.0.0: 620 | version "1.0.1" 621 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 622 | 623 | path-type@^1.0.0: 624 | version "1.1.0" 625 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" 626 | dependencies: 627 | graceful-fs "^4.1.2" 628 | pify "^2.0.0" 629 | pinkie-promise "^2.0.0" 630 | 631 | pify@^2.0.0: 632 | version "2.3.0" 633 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 634 | 635 | pinkie-promise@^2.0.0: 636 | version "2.0.1" 637 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 638 | dependencies: 639 | pinkie "^2.0.0" 640 | 641 | pinkie@^2.0.0, pinkie@^2.0.4: 642 | version "2.0.4" 643 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 644 | 645 | prepend-http@^1.0.1: 646 | version "1.0.4" 647 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" 648 | 649 | process-nextick-args@~1.0.6: 650 | version "1.0.7" 651 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 652 | 653 | rc@^1.0.1, rc@^1.1.6: 654 | version "1.1.6" 655 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" 656 | dependencies: 657 | deep-extend "~0.4.0" 658 | ini "~1.3.0" 659 | minimist "^1.2.0" 660 | strip-json-comments "~1.0.4" 661 | 662 | read-all-stream@^3.0.0: 663 | version "3.1.0" 664 | resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" 665 | dependencies: 666 | pinkie-promise "^2.0.0" 667 | readable-stream "^2.0.0" 668 | 669 | read-pkg-up@^1.0.1: 670 | version "1.0.1" 671 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" 672 | dependencies: 673 | find-up "^1.0.0" 674 | read-pkg "^1.0.0" 675 | 676 | read-pkg@^1.0.0: 677 | version "1.1.0" 678 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" 679 | dependencies: 680 | load-json-file "^1.0.0" 681 | normalize-package-data "^2.3.2" 682 | path-type "^1.0.0" 683 | 684 | readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5: 685 | version "2.2.2" 686 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" 687 | dependencies: 688 | buffer-shims "^1.0.0" 689 | core-util-is "~1.0.0" 690 | inherits "~2.0.1" 691 | isarray "~1.0.0" 692 | process-nextick-args "~1.0.6" 693 | string_decoder "~0.10.x" 694 | util-deprecate "~1.0.1" 695 | 696 | registry-auth-token@^3.0.1: 697 | version "3.1.0" 698 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.1.0.tgz#997c08256e0c7999837b90e944db39d8a790276b" 699 | dependencies: 700 | rc "^1.1.6" 701 | 702 | registry-url@^3.0.3: 703 | version "3.1.0" 704 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" 705 | dependencies: 706 | rc "^1.0.1" 707 | 708 | repeating@^2.0.0: 709 | version "2.0.1" 710 | resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" 711 | dependencies: 712 | is-finite "^1.0.0" 713 | 714 | require-directory@^2.1.1: 715 | version "2.1.1" 716 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 717 | 718 | require-main-filename@^1.0.1: 719 | version "1.0.1" 720 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" 721 | 722 | resolve@^1.1.7: 723 | version "1.2.0" 724 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" 725 | 726 | semver-diff@^2.0.0: 727 | version "2.1.0" 728 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" 729 | dependencies: 730 | semver "^5.0.3" 731 | 732 | "semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0: 733 | version "5.3.0" 734 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" 735 | 736 | set-blocking@^2.0.0: 737 | version "2.0.0" 738 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 739 | 740 | slide@^1.1.5: 741 | version "1.1.6" 742 | resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" 743 | 744 | source-map-support@^0.4.0: 745 | version "0.4.8" 746 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.8.tgz#4871918d8a3af07289182e974e32844327b2e98b" 747 | dependencies: 748 | source-map "^0.5.3" 749 | 750 | source-map@^0.5.3: 751 | version "0.5.6" 752 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" 753 | 754 | spdx-correct@~1.0.0: 755 | version "1.0.2" 756 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" 757 | dependencies: 758 | spdx-license-ids "^1.0.2" 759 | 760 | spdx-expression-parse@~1.0.0: 761 | version "1.0.4" 762 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" 763 | 764 | spdx-license-ids@^1.0.2: 765 | version "1.2.2" 766 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" 767 | 768 | sprintf-js@^1.0.3: 769 | version "1.0.3" 770 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 771 | 772 | string-width@^1.0.1, string-width@^1.0.2: 773 | version "1.0.2" 774 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 775 | dependencies: 776 | code-point-at "^1.0.0" 777 | is-fullwidth-code-point "^1.0.0" 778 | strip-ansi "^3.0.0" 779 | 780 | string_decoder@~0.10.x: 781 | version "0.10.31" 782 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 783 | 784 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 785 | version "3.0.1" 786 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 787 | dependencies: 788 | ansi-regex "^2.0.0" 789 | 790 | strip-bom@^2.0.0: 791 | version "2.0.0" 792 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" 793 | dependencies: 794 | is-utf8 "^0.2.0" 795 | 796 | strip-json-comments@^2.0.0: 797 | version "2.0.1" 798 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 799 | 800 | strip-json-comments@~1.0.4: 801 | version "1.0.4" 802 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" 803 | 804 | supports-color@3.1.2: 805 | version "3.1.2" 806 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" 807 | dependencies: 808 | has-flag "^1.0.0" 809 | 810 | supports-color@^2.0.0: 811 | version "2.0.0" 812 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 813 | 814 | timed-out@^3.0.0: 815 | version "3.1.3" 816 | resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217" 817 | 818 | ts-node@^2.0.0: 819 | version "2.0.0" 820 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-2.0.0.tgz#16e4fecc949088238b4cbf1c39c9582526b66f74" 821 | dependencies: 822 | arrify "^1.0.0" 823 | chalk "^1.1.1" 824 | diff "^3.1.0" 825 | make-error "^1.1.1" 826 | minimist "^1.2.0" 827 | mkdirp "^0.5.1" 828 | pinkie "^2.0.4" 829 | source-map-support "^0.4.0" 830 | tsconfig "^5.0.2" 831 | v8flags "^2.0.11" 832 | xtend "^4.0.0" 833 | yn "^1.2.0" 834 | 835 | tsconfig@^5.0.2: 836 | version "5.0.3" 837 | resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-5.0.3.tgz#5f4278e701800967a8fc383fd19648878f2a6e3a" 838 | dependencies: 839 | any-promise "^1.3.0" 840 | parse-json "^2.2.0" 841 | strip-bom "^2.0.0" 842 | strip-json-comments "^2.0.0" 843 | 844 | tslint@^4.3.1: 845 | version "4.3.1" 846 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-4.3.1.tgz#28f679c53ca4b273688bcb6fcf0dde7ff1bb2169" 847 | dependencies: 848 | babel-code-frame "^6.20.0" 849 | colors "^1.1.2" 850 | diff "^3.0.1" 851 | findup-sync "~0.3.0" 852 | glob "^7.1.1" 853 | optimist "~0.6.0" 854 | resolve "^1.1.7" 855 | underscore.string "^3.3.4" 856 | update-notifier "^1.0.2" 857 | 858 | type-detect@0.1.1: 859 | version "0.1.1" 860 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" 861 | 862 | type-detect@^1.0.0: 863 | version "1.0.0" 864 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" 865 | 866 | typescript@^2.2.1: 867 | version "2.2.1" 868 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.1.tgz#4862b662b988a4c8ff691cc7969622d24db76ae9" 869 | 870 | underscore.string@^3.3.4: 871 | version "3.3.4" 872 | resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" 873 | dependencies: 874 | sprintf-js "^1.0.3" 875 | util-deprecate "^1.0.2" 876 | 877 | unzip-response@^1.0.2: 878 | version "1.0.2" 879 | resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe" 880 | 881 | update-notifier@^1.0.2: 882 | version "1.0.3" 883 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-1.0.3.tgz#8f92c515482bd6831b7c93013e70f87552c7cf5a" 884 | dependencies: 885 | boxen "^0.6.0" 886 | chalk "^1.0.0" 887 | configstore "^2.0.0" 888 | is-npm "^1.0.0" 889 | latest-version "^2.0.0" 890 | lazy-req "^1.1.0" 891 | semver-diff "^2.0.0" 892 | xdg-basedir "^2.0.0" 893 | 894 | url-parse-lax@^1.0.0: 895 | version "1.0.0" 896 | resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" 897 | dependencies: 898 | prepend-http "^1.0.1" 899 | 900 | user-home@^1.1.1: 901 | version "1.1.1" 902 | resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" 903 | 904 | util-deprecate@^1.0.2, util-deprecate@~1.0.1: 905 | version "1.0.2" 906 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 907 | 908 | uuid@^2.0.1: 909 | version "2.0.3" 910 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" 911 | 912 | v8flags@^2.0.11: 913 | version "2.0.11" 914 | resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" 915 | dependencies: 916 | user-home "^1.1.1" 917 | 918 | validate-npm-package-license@^3.0.1: 919 | version "3.0.1" 920 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" 921 | dependencies: 922 | spdx-correct "~1.0.0" 923 | spdx-expression-parse "~1.0.0" 924 | 925 | which-module@^1.0.0: 926 | version "1.0.0" 927 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" 928 | 929 | widest-line@^1.0.0: 930 | version "1.0.0" 931 | resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c" 932 | dependencies: 933 | string-width "^1.0.1" 934 | 935 | wordwrap@~0.0.2: 936 | version "0.0.3" 937 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" 938 | 939 | wrap-ansi@^2.0.0: 940 | version "2.1.0" 941 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" 942 | dependencies: 943 | string-width "^1.0.1" 944 | strip-ansi "^3.0.1" 945 | 946 | wrappy@1: 947 | version "1.0.2" 948 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 949 | 950 | write-file-atomic@^1.1.2: 951 | version "1.3.1" 952 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" 953 | dependencies: 954 | graceful-fs "^4.1.11" 955 | imurmurhash "^0.1.4" 956 | slide "^1.1.5" 957 | 958 | xdg-basedir@^2.0.0: 959 | version "2.0.0" 960 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" 961 | dependencies: 962 | os-homedir "^1.0.0" 963 | 964 | xtend@^4.0.0: 965 | version "4.0.1" 966 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 967 | 968 | y18n@^3.2.1: 969 | version "3.2.1" 970 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" 971 | 972 | yargs-parser@^4.2.0: 973 | version "4.2.1" 974 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" 975 | dependencies: 976 | camelcase "^3.0.0" 977 | 978 | yargs@^6.6.0: 979 | version "6.6.0" 980 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" 981 | dependencies: 982 | camelcase "^3.0.0" 983 | cliui "^3.2.0" 984 | decamelize "^1.1.1" 985 | get-caller-file "^1.0.1" 986 | os-locale "^1.4.0" 987 | read-pkg-up "^1.0.1" 988 | require-directory "^2.1.1" 989 | require-main-filename "^1.0.1" 990 | set-blocking "^2.0.0" 991 | string-width "^1.0.2" 992 | which-module "^1.0.0" 993 | y18n "^3.2.1" 994 | yargs-parser "^4.2.0" 995 | 996 | yn@^1.2.0: 997 | version "1.2.0" 998 | resolved "https://registry.yarnpkg.com/yn/-/yn-1.2.0.tgz#d237a4c533f279b2b89d3acac2db4b8c795e4a63" 999 | --------------------------------------------------------------------------------