hunk.code_window: const opn = require('opn');
   export const DocTask: any = Task.extend({
     run: function(keyword: string) {
       const searchUrl = `https://angular.io/docs/ts/latest/api/#!?query=${keyword}`;
       return opn(searchUrl, { wait: false });
     }
   });
hunk.labels: keep keep keep replace replace keep keep keep
hunk.after_edit:   run: function(keyword: string, search: boolean) {
       const searchUrl = search ? `https://angular.io/search/#stq=${keyword}&stp=1` :
        `https://angular.io/docs/ts/latest/api/#!?query=${keyword}`;
  
hunk.file_path: packages/@angular/cli/tasks/doc.ts
hunk.type: replace
file: 'use strict';
  
  // This needs to be first so fs module can be mocked correctly.
  let mockFs = require('mock-fs');
  
  import {it} from './spec-utils';
  import {InsertChange, NodeHost, RemoveChange, ReplaceChange} from './change';
  import fs = require('fs');
  
  let path = require('path');
  let Promise = require('@angular/cli/ember-cli/lib/ext/promise');
  
  const readFile =  Promise.denodeify(fs.readFile);
  
  describe('Change', () => {
    let sourcePath = 'src/app/my-component';
  
    beforeEach(() => {
      let mockDrive = {
        'src/app/my-component': {
          'add-file.txt': 'hello',
          'remove-replace-file.txt': 'import * as foo from "./bar"',
          'replace-file.txt': 'import { FooComponent } from "./baz"'
        }
      };
      mockFs(mockDrive);
    });
    afterEach(() => {
      mockFs.restore();
    });
  
    describe('InsertChange', () => {
      let sourceFile = path.join(sourcePath, 'add-file.txt');
  
      it('adds text to the source code', () => {
        let changeInstance = new InsertChange(sourceFile, 6, ' world!');
        return changeInstance
          .apply(NodeHost)
          .then(() => readFile(sourceFile, 'utf8'))
          .then(contents => {
            expect(contents).toEqual('hello world!');
          });
      });
      it('fails for negative position', () => {
        expect(() => new InsertChange(sourceFile, -6, ' world!')).toThrowError();
      });
      it('adds nothing in the source code if empty string is inserted', () => {
        let changeInstance = new InsertChange(sourceFile, 6, '');
        return changeInstance
          .apply(NodeHost)
          .then(() => readFile(sourceFile, 'utf8'))
          .then(contents => {
            expect(contents).toEqual('hello');
          });
      });
    });
  
    describe('RemoveChange', () => {
      let sourceFile = path.join(sourcePath, 'remove-replace-file.txt');
  
      it('removes given text from the source code', () => {
        let changeInstance = new RemoveChange(sourceFile, 9, 'as foo');
        return changeInstance
          .apply(NodeHost)
          .then(() => readFile(sourceFile, 'utf8'))
          .then(contents => {
            expect(contents).toEqual('import *  from "./bar"');
          });
      });
      it('fails for negative position', () => {
        expect(() => new RemoveChange(sourceFile, -6, ' world!')).toThrow();
      });
      it('does not change the file if told to remove empty string', () => {
        let changeInstance = new RemoveChange(sourceFile, 9, '');
        return changeInstance
          .apply(NodeHost)
          .then(() => readFile(sourceFile, 'utf8'))
          .then(contents => {
            expect(contents).toEqual('import * as foo from "./bar"');
          });
      });
    });
  
    describe('ReplaceChange', () => {
      it('replaces the given text in the source code', () => {
        let sourceFile = path.join(sourcePath, 'remove-replace-file.txt');
        let changeInstance = new ReplaceChange(sourceFile, 7, '* as foo', '{ fooComponent }');
        return changeInstance
          .apply(NodeHost)
          .then(() => readFile(sourceFile, 'utf8'))
          .then(contents => {
            expect(contents).toEqual('import { fooComponent } from "./bar"');
          });
      });
      it('fails for negative position', () => {
        let sourceFile = path.join(sourcePath, 'remove-replace-file.txt');
        expect(() => new ReplaceChange(sourceFile, -6, 'hello', ' world!')).toThrow();
      });
      it('fails for invalid replacement', () => {
        let sourceFile = path.join(sourcePath, 'replace-file.txt');
        let changeInstance = new ReplaceChange(sourceFile, 0, 'foobar', '');
        return changeInstance
          .apply(NodeHost)
          .then(() => expect(false).toBe(true), err => {
            // Check that the message contains the string to replace and the string from the file.
            expect(err.message).toContain('foobar');
            expect(err.message).toContain('import');
          });
      });
      it('adds string to the position of an empty string', () => {
        let sourceFile = path.join(sourcePath, 'replace-file.txt');
        let changeInstance = new ReplaceChange(sourceFile, 9, '', 'BarComponent, ');
        return changeInstance
          .apply(NodeHost)
          .then(() => readFile(sourceFile, 'utf8'))
          .then(contents => {
            expect(contents).toEqual('import { BarComponent, FooComponent } from "./baz"');
          });
      });
      it('removes the given string only if an empty string to add is given', () => {
        let sourceFile = path.join(sourcePath, 'remove-replace-file.txt');
        let changeInstance = new ReplaceChange(sourceFile, 8, ' as foo', '');
        return changeInstance
          .apply(NodeHost)
          .then(() => readFile(sourceFile, 'utf8'))
          .then(contents => {
            expect(contents).toEqual('import * from "./bar"');
          });
      });
    });
  });
  