diff --git a/integration/language_service_plugin/.gitignore b/integration/language_service_plugin/.gitignore new file mode 100644 index 0000000000000..4c43fe68f6405 --- /dev/null +++ b/integration/language_service_plugin/.gitignore @@ -0,0 +1 @@ +*.js \ No newline at end of file diff --git a/integration/language_service_plugin/README.md b/integration/language_service_plugin/README.md new file mode 100644 index 0000000000000..3873350e21698 --- /dev/null +++ b/integration/language_service_plugin/README.md @@ -0,0 +1,36 @@ +# Angular Language Service Test + +This directory is an integration test for `@angular/language-service` to ensure +that various versions of the server can be loaded in the supported versions of +TypeScript's language service. + +## New supported version of TypeScript + +To add a new supported version of TypeScript: + +1) Create directory in `typescripts` to hold the new version following the pattern + of the other versions. +2) Add the directory name to the end of the `TYPESCRIPTS` variable in the + `scripts/env.sh` file. +3) Run `scripts/update_golden.sh` to generate the expected files. +4) Verify the expected output is reasonable by comparing to a known good output + from a previous version. + +## Update golden files + +If the expected output needs to be updated run `scripts/update_golden.sh` to +update the expected output of the server. + +## Adding a new fixture + +Currently there is no automated way to produce a new fixture. The way the +current fixtures were created was to hack a version of tsserver.js to write the +commands from `VSCode` to a file while performing the operation to be tested. +I also hand modified the input to remove superfluous request. + +Once a new fixture is created: + +1) Add the fixture base name (without the .json) to `FIXTURES` in + `scripts/env.sh`. +2) Run `scripts/udpate_golden.sh` to produce the expected output files. +3) Hand validate the expected output is reasonable. diff --git a/integration/language_service_plugin/fixtures/getCompletions-expected-2.3.json b/integration/language_service_plugin/fixtures/getCompletions-expected-2.3.json new file mode 100644 index 0000000000000..3560e80927dda --- /dev/null +++ b/integration/language_service_plugin/fixtures/getCompletions-expected-2.3.json @@ -0,0 +1,260 @@ +[ + { + "type": "response", + "command": "configure", + "success": true + }, + { + "type": "response", + "command": "compilerOptionsForInferredProjects", + "success": true, + "body": true + }, + { + "type": "response", + "command": "completions", + "success": true, + "body": [ + { + "name": "anchor", + "kind": "method", + "kindModifiers": "", + "sortText": "anchor" + }, + { + "name": "big", + "kind": "method", + "kindModifiers": "", + "sortText": "big" + }, + { + "name": "blink", + "kind": "method", + "kindModifiers": "", + "sortText": "blink" + }, + { + "name": "bold", + "kind": "method", + "kindModifiers": "", + "sortText": "bold" + }, + { + "name": "charAt", + "kind": "method", + "kindModifiers": "", + "sortText": "charAt" + }, + { + "name": "charCodeAt", + "kind": "method", + "kindModifiers": "", + "sortText": "charCodeAt" + }, + { + "name": "codePointAt", + "kind": "method", + "kindModifiers": "", + "sortText": "codePointAt" + }, + { + "name": "concat", + "kind": "method", + "kindModifiers": "", + "sortText": "concat" + }, + { + "name": "endsWith", + "kind": "method", + "kindModifiers": "", + "sortText": "endsWith" + }, + { + "name": "fixed", + "kind": "method", + "kindModifiers": "", + "sortText": "fixed" + }, + { + "name": "fontcolor", + "kind": "method", + "kindModifiers": "", + "sortText": "fontcolor" + }, + { + "name": "fontsize", + "kind": "method", + "kindModifiers": "", + "sortText": "fontsize" + }, + { + "name": "includes", + "kind": "method", + "kindModifiers": "", + "sortText": "includes" + }, + { + "name": "indexOf", + "kind": "method", + "kindModifiers": "", + "sortText": "indexOf" + }, + { + "name": "italics", + "kind": "method", + "kindModifiers": "", + "sortText": "italics" + }, + { + "name": "lastIndexOf", + "kind": "method", + "kindModifiers": "", + "sortText": "lastIndexOf" + }, + { + "name": "length", + "kind": "property", + "kindModifiers": "", + "sortText": "length" + }, + { + "name": "link", + "kind": "method", + "kindModifiers": "", + "sortText": "link" + }, + { + "name": "localeCompare", + "kind": "method", + "kindModifiers": "", + "sortText": "localeCompare" + }, + { + "name": "match", + "kind": "method", + "kindModifiers": "", + "sortText": "match" + }, + { + "name": "normalize", + "kind": "method", + "kindModifiers": "", + "sortText": "normalize" + }, + { + "name": "repeat", + "kind": "method", + "kindModifiers": "", + "sortText": "repeat" + }, + { + "name": "replace", + "kind": "method", + "kindModifiers": "", + "sortText": "replace" + }, + { + "name": "search", + "kind": "method", + "kindModifiers": "", + "sortText": "search" + }, + { + "name": "slice", + "kind": "method", + "kindModifiers": "", + "sortText": "slice" + }, + { + "name": "small", + "kind": "method", + "kindModifiers": "", + "sortText": "small" + }, + { + "name": "split", + "kind": "method", + "kindModifiers": "", + "sortText": "split" + }, + { + "name": "startsWith", + "kind": "method", + "kindModifiers": "", + "sortText": "startsWith" + }, + { + "name": "strike", + "kind": "method", + "kindModifiers": "", + "sortText": "strike" + }, + { + "name": "sub", + "kind": "method", + "kindModifiers": "", + "sortText": "sub" + }, + { + "name": "substr", + "kind": "method", + "kindModifiers": "", + "sortText": "substr" + }, + { + "name": "substring", + "kind": "method", + "kindModifiers": "", + "sortText": "substring" + }, + { + "name": "sup", + "kind": "method", + "kindModifiers": "", + "sortText": "sup" + }, + { + "name": "toLocaleLowerCase", + "kind": "method", + "kindModifiers": "", + "sortText": "toLocaleLowerCase" + }, + { + "name": "toLocaleUpperCase", + "kind": "method", + "kindModifiers": "", + "sortText": "toLocaleUpperCase" + }, + { + "name": "toLowerCase", + "kind": "method", + "kindModifiers": "", + "sortText": "toLowerCase" + }, + { + "name": "toString", + "kind": "method", + "kindModifiers": "", + "sortText": "toString" + }, + { + "name": "toUpperCase", + "kind": "method", + "kindModifiers": "", + "sortText": "toUpperCase" + }, + { + "name": "trim", + "kind": "method", + "kindModifiers": "", + "sortText": "trim" + }, + { + "name": "valueOf", + "kind": "method", + "kindModifiers": "", + "sortText": "valueOf" + } + ] + } +] diff --git a/integration/language_service_plugin/fixtures/getCompletions.json b/integration/language_service_plugin/fixtures/getCompletions.json new file mode 100644 index 0000000000000..94be1ebe386a8 --- /dev/null +++ b/integration/language_service_plugin/fixtures/getCompletions.json @@ -0,0 +1,68 @@ +[ + { + "seq": 0, + "type": "request", + "command": "configure", + "arguments": { + "hostInfo": "vscode" + } + }, + { + "seq": 1, + "type": "request", + "command": "compilerOptionsForInferredProjects", + "arguments": { + "options": { + "module": "CommonJS", + "target": "ES6", + "allowSyntheticDefaultImports": true, + "allowNonTsExtensions": true, + "allowJs": true, + "jsx": "Preserve" + } + } + }, + { + "seq": 4, + "type": "request", + "command": "open", + "arguments": { + "file": "$$PWD$$/project/app/app.component.ts", + "fileContent": "import { Component } from '@angular/core';\n\n@Component({\n selector: 'my-app',\n template: `

Hello {{name}}

`,\n})\nexport class AppComponent { name = 'Angular'; }\n" + } + }, + { + "seq": 7, + "type": "request", + "command": "geterr", + "arguments": { + "delay": 0, + "files": [ + "$$PWD$$/project/app/app.component.ts" + ] + } + }, + { + "seq": 12, + "type": "request", + "command": "change", + "arguments": { + "file": "$$PWD$$/project/app/app.component.ts", + "line": 5, + "offset": 30, + "endLine": 5, + "endOffset": 30, + "insertString": "." + } + }, + { + "seq": 13, + "type": "request", + "command": "completions", + "arguments": { + "file": "$$PWD$$/project/app/app.component.ts", + "line": 5, + "offset": 31 + } + } +] \ No newline at end of file diff --git a/integration/language_service_plugin/fixtures/smokeTest-expected-2.3.json b/integration/language_service_plugin/fixtures/smokeTest-expected-2.3.json new file mode 100644 index 0000000000000..55645cf60dc5e --- /dev/null +++ b/integration/language_service_plugin/fixtures/smokeTest-expected-2.3.json @@ -0,0 +1,13 @@ +[ + { + "type": "response", + "command": "configure", + "success": true + }, + { + "type": "response", + "command": "compilerOptionsForInferredProjects", + "success": true, + "body": true + } +] diff --git a/integration/language_service_plugin/fixtures/smokeTest.json b/integration/language_service_plugin/fixtures/smokeTest.json new file mode 100644 index 0000000000000..7ddc202c9a65f --- /dev/null +++ b/integration/language_service_plugin/fixtures/smokeTest.json @@ -0,0 +1,45 @@ +[ + { + "seq": 0, + "type": "request", + "command": "configure", + "arguments": { + "hostInfo": "vscode" + } + }, + { + "seq": 1, + "type": "request", + "command": "compilerOptionsForInferredProjects", + "arguments": { + "options": { + "module": "CommonJS", + "target": "ES6", + "allowSyntheticDefaultImports": true, + "allowNonTsExtensions": true, + "allowJs": true, + "jsx": "Preserve" + } + } + }, + { + "seq": 2, + "type": "request", + "command": "open", + "arguments": { + "file": "$$PWD$$/app/app.module.ts", + "fileContent": "" + } + }, + { + "seq": 3, + "type": "request", + "command": "geterr", + "arguments": { + "delay": 0, + "files": [ + "$$PWD$$/app/app.module.ts" + ] + } + } +] \ No newline at end of file diff --git a/integration/language_service_plugin/package.json b/integration/language_service_plugin/package.json new file mode 100644 index 0000000000000..65645d7a4f2f2 --- /dev/null +++ b/integration/language_service_plugin/package.json @@ -0,0 +1,26 @@ +{ + "name": "language_service_plugin", + "version": "0.0.0", + "license": "MIT", + "decription": "Angular Langauge Service plugin integration test", + "dependencies": { + "@angular/common": "file:../../dist/packages-dist/common", + "@angular/compiler": "file:../../dist/packages-dist/compiler", + "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", + "@angular/core": "file:../../dist/packages-dist/core", + "@angular/language-service": "file:../../dist/packages-dist/language-service", + "@angular/platform-browser": "file:../../dist/packages-dist/platform-browser", + "@angular/platform-server": "file:../../dist/packages-dist/platform-server", + "@angular/tsc-wrapped": "file:../../dist/tools/@angular/tsc-wrapped", + "@types/minimist": "^1.2.0", + "@types/node": "^7.0.5", + "minimist": "^1.2.0", + "rxjs": "file:../../node_modules/rxjs", + "typescript": "^2.1.5", + "zone.js": "0.7.6" + }, + "scripts": { + "postinstall": "scripts/install.sh", + "test": "tsc -p tools && scripts/test.sh" + } +} diff --git a/integration/language_service_plugin/project/app/app.component.ts b/integration/language_service_plugin/project/app/app.component.ts new file mode 100644 index 0000000000000..7fb173cd011f7 --- /dev/null +++ b/integration/language_service_plugin/project/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: `

Hello {{name}}

`, +}) +export class AppComponent { name = 'Angular'; } diff --git a/integration/language_service_plugin/project/app/app.module.ts b/integration/language_service_plugin/project/app/app.module.ts new file mode 100644 index 0000000000000..357b003a5ab73 --- /dev/null +++ b/integration/language_service_plugin/project/app/app.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/integration/language_service_plugin/project/app/main.ts b/integration/language_service_plugin/project/app/main.ts new file mode 100644 index 0000000000000..6af7a5b2ae880 --- /dev/null +++ b/integration/language_service_plugin/project/app/main.ts @@ -0,0 +1,5 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/integration/language_service_plugin/project/tsconfig.json b/integration/language_service_plugin/project/tsconfig.json new file mode 100644 index 0000000000000..6a81fdd7df2a5 --- /dev/null +++ b/integration/language_service_plugin/project/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "plugins": [ + { "name": "@angular/language-service" } + ] + } +} diff --git a/integration/language_service_plugin/scripts/env.sh b/integration/language_service_plugin/scripts/env.sh new file mode 100755 index 0000000000000..321f42a45c447 --- /dev/null +++ b/integration/language_service_plugin/scripts/env.sh @@ -0,0 +1,2 @@ +TYPESCRIPTS=2.3 +FIXTURES="smokeTest getCompletions" diff --git a/integration/language_service_plugin/scripts/install.sh b/integration/language_service_plugin/scripts/install.sh new file mode 100755 index 0000000000000..d8354792591ab --- /dev/null +++ b/integration/language_service_plugin/scripts/install.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -ex -o pipefail + +cd `dirname $0` +cd .. +source scripts/env.sh + +# Setup TypeScripts +for TYPESCRIPT in ${TYPESCRIPTS[@]} +do + ( + cd typescripts/$TYPESCRIPT + yarn + ) +done \ No newline at end of file diff --git a/integration/language_service_plugin/scripts/test.sh b/integration/language_service_plugin/scripts/test.sh new file mode 100755 index 0000000000000..29f5d34be2b4e --- /dev/null +++ b/integration/language_service_plugin/scripts/test.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -ex -o pipefail + +cd `dirname $0` +cd .. +source scripts/env.sh + +HOST="node tools/typescript_host.js" +VALIDATE="node tools/typescript_validator.js" + +for TYPESCRIPT in ${TYPESCRIPTS[@]} +do + SERVER="node typescripts/$TYPESCRIPT/node_modules/typescript/lib/tsserver.js" + for FIXTURE_BASE in ${FIXTURES[@]} + do + FIXTURE=fixtures/$FIXTURE_BASE.json + EXPECTED=fixtures/$FIXTURE_BASE-expected-$TYPESCRIPT.json + if [[ ${UPDATE_GOLDEN} == true ]]; then + $HOST --file $FIXTURE --pwd $(pwd) | $SERVER | $VALIDATE --golden > $EXPECTED + else + $HOST --file $FIXTURE --pwd $(pwd) | $SERVER | $VALIDATE --expect $EXPECTED + fi + done +done \ No newline at end of file diff --git a/integration/language_service_plugin/scripts/update_golden.sh b/integration/language_service_plugin/scripts/update_golden.sh new file mode 100755 index 0000000000000..4fd0d2484dc6c --- /dev/null +++ b/integration/language_service_plugin/scripts/update_golden.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -ex -o pipefail + +cd `dirname $0` +cd .. + +UPDATE_GOLDEN=true scripts/test.sh \ No newline at end of file diff --git a/integration/language_service_plugin/tools/tsconfig.json b/integration/language_service_plugin/tools/tsconfig.json new file mode 100644 index 0000000000000..c576365a6e265 --- /dev/null +++ b/integration/language_service_plugin/tools/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "noImplicitAny": true, + "skipLibCheck": true, + "sourceMap": false, + "lib": ["es2015", "dom"], + "types": [ + "node", + "minimist" + ] + }, + "files": [ + "typescript_host.ts", + "typescript_validator.ts" + ] +} \ No newline at end of file diff --git a/integration/language_service_plugin/tools/typescript_host.ts b/integration/language_service_plugin/tools/typescript_host.ts new file mode 100644 index 0000000000000..4dc2f415c8bae --- /dev/null +++ b/integration/language_service_plugin/tools/typescript_host.ts @@ -0,0 +1,77 @@ +import * as fs from 'fs'; +import * as minimist from 'minimist'; + +const RE_PWD = /\$\$PWD\$\$/g; + +let errorsDetected = false; + +function reportError(arg: string): boolean { + console.error(`Unknown argument: ${arg}`); + errorsDetected = true; + return false; +} + +function help() { + console.log('TypeScript Host') + console.log(`${process.argv[1]} --file [--pwd ]`); + console.log(` + Send JSON message using the JSON RPC protocol to stdout. + `) +} + +let args = minimist(process.argv.slice(2), { string: ['file', 'pwd'], unknown: reportError }); + +if (errorsDetected) { + help(); + process.exit(2); +} + +const file = args['file']; +if (!file) { + console.log('stdin form not supported yet.') + process.exit(1); +} + +// Sender +const pending: string[] = []; +let writing = false; + +function writeMessage(message: string) { + writing = true; + process.stdout.write(message + '\n', checkPending); +} + +function checkPending() { + writing = false; + if (pending.length) { + writeMessage(pending.shift()); + } +} + +function send(message: string) { + if (writing) { + pending.push(message); + } else { + writeMessage(message); + } +} + +try { + let content = fs.readFileSync(file, 'utf8'); + if (args['pwd']) { + content = content.replace(RE_PWD, args['pwd']); + } + + const json = JSON.parse(content); + + if (Array.isArray(json)) { + for (const message of json) { + send(JSON.stringify(message)); + } + } else { + throw Error('Expected an array for input messages.') + } +} catch(e) { + console.error(`Error: ${e.message}`); + process.exit(2); +} \ No newline at end of file diff --git a/integration/language_service_plugin/tools/typescript_validator.ts b/integration/language_service_plugin/tools/typescript_validator.ts new file mode 100644 index 0000000000000..0bad6a4d071a1 --- /dev/null +++ b/integration/language_service_plugin/tools/typescript_validator.ts @@ -0,0 +1,164 @@ +import * as fs from 'fs'; +import * as minimist from 'minimist'; + +let errorsDetected = false; + +const start = Date.now(); + +function reportError(arg: string): boolean { + console.error(`Unknown argument: ${arg}`); + errorsDetected = true; + return false; +} + +function help() { + console.log('TypeScript Validator') + console.log(`${process.argv[1]} [--expect | --golden] [--pwd ]`); + console.log(` + Validate that the emitted output produces the expect JSON.`) +} + +let args = minimist(process.argv.slice(2), { string: ['expect', 'pwd'], boolean: ['golden'], unknown: reportError }); + +if (!args.golden && !args.expect) { + console.log('Expected -golden or -expect'); + errorsDetected = true; +} + +if (args.golden && args.expect) { + console.log('Expected -golded or -expect but not both'); + errorsDetected = true; +} + +if (errorsDetected) { + help(); + process.exit(2); +} + +var expected: any; +if (args.expect) { + expected = JSON.parse(fs.readFileSync(args.expect, 'utf8')); +} + +// Reader +let pending = Buffer.alloc(0); + +const prefix = 'Content-Length: '; + +function tryReadMessage(cb: (message: any) => void) { + const firstLine = pending.indexOf(10); + if (firstLine >= 1) { + const line = pending.toString('utf8', 0, firstLine); + if (!line.startsWith(prefix)) { + throw Error(`Unexpected input: ${line}`); + } + const length = +line.substring(prefix.length, firstLine - 1); + const dataStart = firstLine + 2; + const messageText = pending.toString('utf8', dataStart, dataStart + length); + const message = JSON.parse(messageText); + pending = pending.slice(dataStart + length + 1); + cb(message); + tryReadMessage(cb); + } +} + +function collect(cb: (error: any, messages: any[]) => void) { + const result: any[] = []; + + function report(error: any, messages: any[]) { + cb(error, messages); + cb = () => {}; + } + + process.stdin.on('error', report); + process.stdin.on('data', (data: Buffer) => { + try { + pending = Buffer.concat([pending, data], pending.length + data.length); + tryReadMessage((message: any) => { + result.push(message); + }); + } catch (e) { + report(e, []); + } + }); + + process.stdin.on('close', () => { + report(null, result); + }); +} + +function sanitize(messages: any[]): any[] { + return messages.filter((message: any) => { + return message && message.type == 'response'; + }).map((message: any) => { + // Only preserve a fixed set of fields. + const result: any = {}; + if (message.type != null) result.type = message.type; + if (message.command != null) result.command = message.command; + if (message.success != null) result.success = message.success; + if (message.body != null) result.body = message.body; + return result; + }); +} + + +function isPrimitive(value: any): boolean { + return Object(value) !== value; +} + +function expectPrimitive(received: any, expected: any) { + if (received !== expected) { + throw new Error(`Expected ${expected} but received ${received}`); + } +} + +function expectArray(received: any, expected: any[]) { + if (!Array.isArray(received)) { + throw new Error(`Expected an array, received ${JSON.stringify(received)}`); + } + if (received.length != expected.length) { + throw new Error(`Expected an array length ${expected.length}, received ${JSON.stringify(received)}`); + } + for (let i = 0; i < expected.length; i++) { + expect(received[i], expected[i]); + } +} + +function expectObject(received: any, expected: any) { + for (const name of Object.getOwnPropertyNames(expected)) { + if (!received.hasOwnProperty(name)) { + throw new Error(`Expected object an object containing a field ${name}, received ${JSON.stringify(expected)}`); + } + expect(received[name], expected[name]); + } +} + +function expect(received: any, expected: any) { + if (isPrimitive(expected)) { + expectPrimitive(received, expected); + } else if (Array.isArray(expected)) { + expectArray(received, expected); + } else { + expectObject(received, expected); + } +} + + +collect((err: any, messages: any[]) => { + if (err) { + console.error(err.message); + process.exit(1); + } + if (args.golden) { + console.log(JSON.stringify(sanitize(messages), null, ' ')); + } else { + try { + expect(sanitize(messages), expected); + console.log('PASSED:', Date.now() - start, 'ms'); + process.exit(0); + } catch(e) { + console.log('FAILED:', e.message); + process.exit(1); + } + } +}); diff --git a/integration/language_service_plugin/tsconfig.json b/integration/language_service_plugin/tsconfig.json new file mode 100644 index 0000000000000..2c7260d1bcdb0 --- /dev/null +++ b/integration/language_service_plugin/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true + } +} diff --git a/integration/language_service_plugin/typescripts/2.3/package.json b/integration/language_service_plugin/typescripts/2.3/package.json new file mode 100644 index 0000000000000..1654fdfe9702a --- /dev/null +++ b/integration/language_service_plugin/typescripts/2.3/package.json @@ -0,0 +1,15 @@ +{ + "name": "2.3", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "typescript": "2.3.0-dev.20170223" + } +} diff --git a/integration/language_service_plugin/typescripts/2.3/yarn.lock b/integration/language_service_plugin/typescripts/2.3/yarn.lock new file mode 100644 index 0000000000000..600ef21a14cc9 --- /dev/null +++ b/integration/language_service_plugin/typescripts/2.3/yarn.lock @@ -0,0 +1,7 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +typescript@2.3.0-dev.20170223: + version "2.3.0-dev.20170223" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.0-dev.20170223.tgz#286494c36625ea2eb26f963ed205cd9ca5c41447"