diff --git a/package.json b/package.json index 9c4f0af..c05bd03 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "bugs": "https://github.com/Microsoft/vscode-cordova/issues", "license": "SEE LICENSE IN LICENSE.txt", "engines": { - "vscode": "^0.10.1" + "vscode": "^0.10.7" }, "categories": [ "Debuggers", @@ -43,6 +43,10 @@ "command": "cordova.prepare", "title": "Cordova: Prepare" }, + { + "command": "cordova.simulate", + "title": "Cordova: Simulate" + }, { "command": "ionic.build", "title": "Ionic: Build" @@ -184,6 +188,17 @@ "cwd": "${workspaceRoot}", "devServerAddress": "localhost", "ionicLiveReload": true + }, + { + "name": "Simulate in browser", + "type": "cordova", + "request": "launch", + "platform": "android", + "target": "browser", + "port": 9222, + "sourceMaps": true, + "cwd": "${workspaceRoot}", + "ionicLiveReload": false } ], "configurationAttributes": { @@ -320,6 +335,7 @@ "scripts": { "vscode:prepublish": "gulp", "compile": "gulp", + "postinstall": "node ./node_modules/vscode/bin/install", "test": "node ./node_modules/mocha/bin/mocha --recursive -u tdd ./out/debugger/test/ ./out/test/debugger" }, "dependencies": { @@ -327,6 +343,7 @@ "plist-with-patches": "^0.5.1", "q": "^1.4.1", "source-map": "^0.5.3", + "taco-simulate": "dlebu/taco-simulate#dev", "vscode-extension-telemetry": "0.0.5", "winreg": "0.0.13", "ws": "0.8.0" @@ -345,7 +362,7 @@ "sinon": "^1.17.2", "tslint": "^2.5.1", "typescript": "^1.6.2", - "vscode": "0.10.x", + "vscode": "^0.11.0", "vsce": "1.0.0" } } diff --git a/src/cordova.ts b/src/cordova.ts index 1007d19..a953284 100644 --- a/src/cordova.ts +++ b/src/cordova.ts @@ -9,6 +9,7 @@ import {CordovaProjectHelper} from './utils/cordovaProjectHelper'; import {CordovaCommandHelper} from './utils/cordovaCommandHelper'; import {ExtensionServer} from './extension/extensionServer'; import * as Q from "q"; +import {PluginSimulator} from "./extension/simulate"; import {Telemetry} from './utils/telemetry'; import {IProjectType, TelemetryHelper} from './utils/telemetryHelper'; import {TsdHelper} from './utils/tsdHelper'; @@ -21,7 +22,7 @@ let TSCONFIG_FILENAME = "tsconfig.json"; export function activate(context: vscode.ExtensionContext): void { // Asynchronously enable telemetry - Telemetry.init('cordova-tools', require('./../../package.json').version, {isExtensionProcess: true}); + Telemetry.init('cordova-tools', require('./../../package.json').version, { isExtensionProcess: true }); // Get the project root and check if it is a Cordova project if (!vscode.workspace.rootPath) { @@ -68,6 +69,9 @@ export function activate(context: vscode.ExtensionContext): void { extensionServer.setup(); context.subscriptions.push(extensionServer); + let simulator = new PluginSimulator(); + context.subscriptions.push(simulator); + // Register Cordova commands context.subscriptions.push(vscode.commands.registerCommand('cordova.prepare', () => CordovaCommandHelper.executeCordovaCommand(cordovaProjectRoot, "prepare"))); @@ -75,6 +79,8 @@ export function activate(context: vscode.ExtensionContext): void { () => CordovaCommandHelper.executeCordovaCommand(cordovaProjectRoot, "build"))); context.subscriptions.push(vscode.commands.registerCommand('cordova.run', () => CordovaCommandHelper.executeCordovaCommand(cordovaProjectRoot, "run"))); + context.subscriptions.push(vscode.commands.registerCommand('cordova.simulate', + () => simulator.simulate(vscode.workspace.rootPath))); context.subscriptions.push(vscode.commands.registerCommand('ionic.prepare', () => CordovaCommandHelper.executeCordovaCommand(cordovaProjectRoot, "prepare", true))); context.subscriptions.push(vscode.commands.registerCommand('ionic.build', diff --git a/src/extension/simulate.ts b/src/extension/simulate.ts new file mode 100644 index 0000000..63e1514 --- /dev/null +++ b/src/extension/simulate.ts @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +import * as Q from "q"; +import * as cordovaServer from "cordova-serve"; +import * as path from "path"; +import * as simulate from "taco-simulate"; +import * as vscode from "vscode"; + +/** + * Plugin simulation entry point. + */ +export class PluginSimulator implements vscode.Disposable { + private registration: vscode.Disposable; + private simulateUri = vscode.Uri.parse("browser-simulate://authority/browser-simulate"); + + public simulate(projectDirectory: string): Q.Promise { + let target = "chrome"; + return simulate.launchServer({ platform: "browser", target: target, dir: projectDirectory }) + .then(simulateInfo => { + return simulate.launchBrowser(target, simulateInfo.appUrl) + .then(() => { + let provider = new SimHostContentProvider(simulateInfo.simHostUrl); + this.registration = vscode.workspace.registerTextDocumentContentProvider("browser-simulate", provider); + return vscode.commands.executeCommand('vscode.previewHtml', this.simulateUri, vscode.ViewColumn.Two); + }); + }); + } + + public dispose(): void { + if (this.registration) { + this.registration.dispose(); + } + } +} + +/** + * Content provider hosting the simulation UI inside a document. + */ +class SimHostContentProvider implements vscode.TextDocumentContentProvider { + private simHostUrl: string; + + constructor(simHostUrl) { + this.simHostUrl = simHostUrl; + } + + public provideTextDocumentContent(uri: vscode.Uri): string { + return `
`; + } +} \ No newline at end of file diff --git a/typings/cordova-serve/cordova-serve.d.ts b/typings/cordova-serve/cordova-serve.d.ts new file mode 100644 index 0000000..10e9c79 --- /dev/null +++ b/typings/cordova-serve/cordova-serve.d.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +declare module "cordova-serve" { + export interface LaunchBrowserOptions { + target: string; + url: string; + } + + export function launchBrowser(options: LaunchBrowserOptions): Promise; +} \ No newline at end of file diff --git a/typings/request/request.d.ts b/typings/request/request.d.ts index d47ed5f..b9f5720 100755 --- a/typings/request/request.d.ts +++ b/typings/request/request.d.ts @@ -1,7 +1,7 @@ // Type definitions for request // Project: https://github.com/mikeal/request -// Definitions by: Carlos Ballesteros Velasco , bonnici , Bart van der Schoor , Joe Skeen -// Definitions: https://github.com/borisyankov/DefinitelyTyped +// Definitions by: Carlos Ballesteros Velasco , bonnici , Bart van der Schoor , Joe Skeen , Christopher Currens +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // Imported from: https://github.com/soywiz/typescript-node-definitions/d.ts @@ -11,6 +11,7 @@ declare module 'request' { import stream = require('stream'); import http = require('http'); + import https = require('https'); import FormData = require('form-data'); import url = require('url'); import fs = require('fs'); @@ -62,7 +63,7 @@ declare module 'request' { interface DefaultUriUrlRequestApi extends RequestAPI { - + defaults(options: TOptions): DefaultUriUrlRequestApi; (): TRequest; get(): TRequest; @@ -86,6 +87,7 @@ declare module 'request' { qs?: any; json?: any; multipart?: RequestPart[] | Multipart; + agent?: http.Agent | https.Agent; agentOptions?: any; agentClass?: any; forever?: any; @@ -110,6 +112,7 @@ declare module 'request' { passphrase?: string; ca?: Buffer; har?: HttpArchiveRequest; + useQuerystring?: boolean; } interface UriOptions { @@ -124,7 +127,10 @@ declare module 'request' { uri?: string; url?: string; } - export type Options = RequiredUriUrl & CoreOptions; + + export type OptionsWithUri = UriOptions & CoreOptions; + export type OptionsWithUrl = UrlOptions & CoreOptions; + export type Options = OptionsWithUri | OptionsWithUrl; export interface RequestCallback { (error: any, response: http.IncomingMessage, body: any): void; @@ -178,7 +184,12 @@ declare module 'request' { oauth(oauth: OAuthOptions): Request; jar(jar: CookieJar): Request; - on(event: string, listener: Function): Request; + on(event: string, listener: Function): this; + on(event: 'request', listener: (req: http.ClientRequest) => void): this; + on(event: 'response', listener: (resp: http.IncomingMessage) => void): this; + on(event: 'data', listener: (data: Buffer | string) => void): this; + on(event: 'error', listener: (e: Error) => void): this; + on(event: 'complete', listener: (resp: http.IncomingMessage, body?: string | Buffer) => void): this; write(buffer: Buffer, cb?: Function): boolean; write(str: string, cb?: Function): boolean; @@ -248,4 +259,4 @@ declare module 'request' { } var request: request.RequestAPI; export = request; -} +} \ No newline at end of file diff --git a/typings/taco-simulate/taco-simulate.d.ts b/typings/taco-simulate/taco-simulate.d.ts new file mode 100644 index 0000000..fb287f4 --- /dev/null +++ b/typings/taco-simulate/taco-simulate.d.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +declare module "taco-simulate" { + export interface SimulateOptions { + platform?: string; + target?: string; + port?: number; + dir?: string; + } + + export interface SimulateInfo { + appUrl: string, + simHostUrl: string + } + + export function launchBrowser(target: string, url: string): Q.Promise; + export function launchServer(opts?: SimulateOptions): Q.Promise; +} \ No newline at end of file diff --git a/typings/ws/ws.d.ts b/typings/ws/ws.d.ts index 99983df..43c30a5 100644 --- a/typings/ws/ws.d.ts +++ b/typings/ws/ws.d.ts @@ -1,14 +1,14 @@ // Type definitions for ws // Project: https://github.com/einaros/ws // Definitions by: Paul Loyd -// Definitions: https://github.com/borisyankov/DefinitelyTyped +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped /// declare module "ws" { - import events = require('events'); - import http = require('http'); - import net = require('net'); + import * as events from 'events'; + import * as http from 'http'; + import * as net from 'net'; class WebSocket extends events.EventEmitter { static CONNECTING: number; @@ -69,24 +69,24 @@ declare module "ws" { addEventListener(method: string, listener?: () => void): void; // Events - on(event: 'error', cb: (err: Error) => void): WebSocket; - on(event: 'close', cb: (code: number, message: string) => void): WebSocket; - on(event: 'message', cb: (data: any, flags: {binary: boolean}) => void): WebSocket; - on(event: 'ping', cb: (data: any, flags: {binary: boolean}) => void): WebSocket; - on(event: 'pong', cb: (data: any, flags: {binary: boolean}) => void): WebSocket; - on(event: 'open', cb: () => void): WebSocket; - on(event: string, listener: () => void): WebSocket; - - addListener(event: 'error', cb: (err: Error) => void): WebSocket; - addListener(event: 'close', cb: (code: number, message: string) => void): WebSocket; - addListener(event: 'message', cb: (data: any, flags: {binary: boolean}) => void): WebSocket; - addListener(event: 'ping', cb: (data: any, flags: {binary: boolean}) => void): WebSocket; - addListener(event: 'pong', cb: (data: any, flags: {binary: boolean}) => void): WebSocket; - addListener(event: 'open', cb: () => void): WebSocket; - addListener(event: string, listener: () => void): WebSocket; + on(event: 'error', cb: (err: Error) => void): this; + on(event: 'close', cb: (code: number, message: string) => void): this; + on(event: 'message', cb: (data: any, flags: {binary: boolean}) => void): this; + on(event: 'ping', cb: (data: any, flags: {binary: boolean}) => void): this; + on(event: 'pong', cb: (data: any, flags: {binary: boolean}) => void): this; + on(event: 'open', cb: () => void): this; + on(event: string, listener: () => void): this; + + addListener(event: 'error', cb: (err: Error) => void): this; + addListener(event: 'close', cb: (code: number, message: string) => void): this; + addListener(event: 'message', cb: (data: any, flags: {binary: boolean}) => void): this; + addListener(event: 'ping', cb: (data: any, flags: {binary: boolean}) => void): this; + addListener(event: 'pong', cb: (data: any, flags: {binary: boolean}) => void): this; + addListener(event: 'open', cb: () => void): this; + addListener(event: string, listener: () => void): this; } - module WebSocket { + namespace WebSocket { export interface IServerOptions { host?: string; port?: number; @@ -115,15 +115,15 @@ declare module "ws" { upgradeHead: Buffer, callback: (client: WebSocket) => void): void; // Events - on(event: 'error', cb: (err: Error) => void): Server; - on(event: 'headers', cb: (headers: string[]) => void): Server; - on(event: 'connection', cb: (client: WebSocket) => void): Server; - on(event: string, listener: () => void): Server; - - addListener(event: 'error', cb: (err: Error) => void): Server; - addListener(event: 'headers', cb: (headers: string[]) => void): Server; - addListener(event: 'connection', cb: (client: WebSocket) => void): Server; - addListener(event: string, listener: () => void): Server; + on(event: 'error', cb: (err: Error) => void): this; + on(event: 'headers', cb: (headers: string[]) => void): this; + on(event: 'connection', cb: (client: WebSocket) => void): this; + on(event: string, listener: () => void): this; + + addListener(event: 'error', cb: (err: Error) => void): this; + addListener(event: 'headers', cb: (headers: string[]) => void): this; + addListener(event: 'connection', cb: (client: WebSocket) => void): this; + addListener(event: string, listener: () => void): this; } export function createServer(options?: IServerOptions, @@ -133,4 +133,4 @@ declare module "ws" { } export = WebSocket; -} +} \ No newline at end of file