From 8ed7b5b9da31b77f960551cfbd288cdb75fef481 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Fri, 22 Mar 2019 08:42:36 +0200 Subject: [PATCH 1/6] chore: set version to 5.3.1 --- npm-shrinkwrap.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index ae508103b4..8c3f83c9f4 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "nativescript", - "version": "5.3.0", + "version": "5.3.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index aa0f51a830..6817f93334 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nativescript", "preferGlobal": true, - "version": "5.3.0", + "version": "5.3.1", "author": "Telerik ", "description": "Command-line interface for building NativeScript projects", "bin": { From f0e77dfb3bedac384d0435f2abb4f2e006481f8c Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 22 Mar 2019 10:40:35 +0200 Subject: [PATCH 2/6] feat: add ability to pass schema and keys to preview app from public api and nsconfig --- lib/commands/preview.ts | 6 +++++- lib/definitions/preview-app-livesync.d.ts | 18 ++++++++++++++++-- lib/definitions/project.d.ts | 6 ++++++ lib/project-data.ts | 2 ++ lib/services/livesync/livesync-service.ts | 7 ++++++- .../livesync/playground/preview-sdk-service.ts | 10 +++++++--- 6 files changed, 42 insertions(+), 7 deletions(-) diff --git a/lib/commands/preview.ts b/lib/commands/preview.ts index a7f613b1d5..7415099c79 100644 --- a/lib/commands/preview.ts +++ b/lib/commands/preview.ts @@ -29,7 +29,11 @@ export class PreviewCommand implements ICommand { env: this.$options.env }); - await this.$previewQrCodeService.printLiveSyncQrCode({ useHotModuleReload: this.$options.hmr, link: this.$options.link }); + await this.$previewQrCodeService.printLiveSyncQrCode({ + nsConfigPreviewAppSchema: this.$projectData.previewAppSchema, + useHotModuleReload: this.$options.hmr, + link: this.$options.link + }); } public async canExecute(args: string[]): Promise { diff --git a/lib/definitions/preview-app-livesync.d.ts b/lib/definitions/preview-app-livesync.d.ts index bf728df915..79cddd8cf1 100644 --- a/lib/definitions/preview-app-livesync.d.ts +++ b/lib/definitions/preview-app-livesync.d.ts @@ -18,15 +18,28 @@ declare global { filesToRemove?: string[]; } - interface IPreviewAppLiveSyncData extends IProjectDir, IHasUseHotModuleReloadOption, IBundle, IEnvOptions { } + interface IPreviewAppLiveSyncData extends IProjectDir, IHasUseHotModuleReloadOption, IBundle, IEnvOptions { + qrCodeData?: IPreviewAppQrCodeData; + } + + interface IPreviewAppQrCodeData { + publishKey?: string; + subscribeKey?: string; + schemaName?: string; + } interface IPreviewSdkService extends EventEmitter { - getQrCodeUrl(options: IHasUseHotModuleReloadOption): string; + getQrCodeUrl(options: IGetQrCodeUrlOptions): string; initialize(getInitialFiles: (device: Device) => Promise): void; applyChanges(filesPayload: FilesPayload): Promise; stop(): void; } + interface IGetQrCodeUrlOptions extends IHasUseHotModuleReloadOption { + nsConfigPreviewAppSchema?: string; + qrCodeData?: IPreviewAppQrCodeData; + } + interface IPreviewAppPluginsService { getPluginsUsageWarnings(data: IPreviewAppLiveSyncData, device: Device): string[]; comparePluginsOnDevice(data: IPreviewAppLiveSyncData, device: Device): Promise; @@ -48,6 +61,7 @@ declare global { } interface IPrintLiveSyncOptions extends IHasUseHotModuleReloadOption { + nsConfigPreviewAppSchema?: string; /** * If set to true, a link will be shown on console instead of QR code * Default value is false. diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index 066c3d781c..05d67d21ab 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -75,6 +75,7 @@ interface INsConfig { appResourcesPath?: string; shared?: boolean; useLegacyWorkflow?: boolean; + previewAppSchema?: string; } interface IProjectData extends ICreateProjectData { @@ -105,6 +106,11 @@ interface IProjectData extends ICreateProjectData { */ useLegacyWorkflow: boolean; + /** + * Defines the schema for the preview app + */ + previewAppSchema: string; + /** * Initializes project data with the given project directory. If none supplied defaults to --path option or cwd. * @param {string} projectDir Project root directory. diff --git a/lib/project-data.ts b/lib/project-data.ts index 1039624b98..328d8a6198 100644 --- a/lib/project-data.ts +++ b/lib/project-data.ts @@ -62,6 +62,7 @@ export class ProjectData implements IProjectData { public podfilePath: string; public isShared: boolean; public useLegacyWorkflow: boolean; + public previewAppSchema: string; constructor(private $fs: IFileSystem, private $errors: IErrors, @@ -137,6 +138,7 @@ export class ProjectData implements IProjectData { this.podfilePath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.PODFILE_NAME); this.isShared = !!(this.nsConfig && this.nsConfig.shared); this.useLegacyWorkflow = this.nsConfig && this.nsConfig.useLegacyWorkflow; + this.previewAppSchema = this.nsConfig && this.nsConfig.previewAppSchema; return; } diff --git a/lib/services/livesync/livesync-service.ts b/lib/services/livesync/livesync-service.ts index d150d1b417..502a4ef21a 100644 --- a/lib/services/livesync/livesync-service.ts +++ b/lib/services/livesync/livesync-service.ts @@ -66,7 +66,12 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi env: data.env, }); - const url = this.$previewSdkService.getQrCodeUrl({ useHotModuleReload: data.useHotModuleReload }); + const projectData = this.$projectDataService.getProjectData(data.projectDir); + const url = this.$previewSdkService.getQrCodeUrl({ + nsConfigPreviewAppSchema: projectData.previewAppSchema, + qrCodeData: data.qrCodeData, + useHotModuleReload: data.useHotModuleReload + }); const result = await this.$previewQrCodeService.getLiveSyncQrCode(url); return result; } diff --git a/lib/services/livesync/playground/preview-sdk-service.ts b/lib/services/livesync/playground/preview-sdk-service.ts index 5947e11632..bbdec6abdf 100644 --- a/lib/services/livesync/playground/preview-sdk-service.ts +++ b/lib/services/livesync/playground/preview-sdk-service.ts @@ -16,9 +16,13 @@ export class PreviewSdkService extends EventEmitter implements IPreviewSdkServic super(); } - public getQrCodeUrl(options: IHasUseHotModuleReloadOption): string { - const hmrValue = options.useHotModuleReload ? "1" : "0"; - return `nsplay://boot?instanceId=${this.instanceId}&pKey=${PubnubKeys.PUBLISH_KEY}&sKey=${PubnubKeys.SUBSCRIBE_KEY}&template=play-ng&hmr=${hmrValue}`; + public getQrCodeUrl(options: IGetQrCodeUrlOptions): string { + const { nsConfigPreviewAppSchema, qrCodeData = { }, useHotModuleReload } = options; + const schema = qrCodeData.schemaName || nsConfigPreviewAppSchema || "nsplay"; + const publishKey = qrCodeData.publishKey || PubnubKeys.PUBLISH_KEY; + const subscribeKey = qrCodeData.subscribeKey || PubnubKeys.SUBSCRIBE_KEY; + const hmrValue = useHotModuleReload ? "1" : "0"; + return `${schema}://boot?instanceId=${this.instanceId}&pKey=${publishKey}&sKey=${subscribeKey}&template=play-ng&hmr=${hmrValue}`; } public async initialize(getInitialFiles: (device: Device) => Promise): Promise { From 69442c91cc895e57ecd853f11a868c9b2a78f38a Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 22 Mar 2019 10:40:51 +0200 Subject: [PATCH 3/6] test: add unit tests --- test/services/preview-sdk-service.ts | 107 ++++++++++++++++++++++++--- test/stubs.ts | 1 + 2 files changed, 99 insertions(+), 9 deletions(-) diff --git a/test/services/preview-sdk-service.ts b/test/services/preview-sdk-service.ts index 3385173648..0e9de72606 100644 --- a/test/services/preview-sdk-service.ts +++ b/test/services/preview-sdk-service.ts @@ -2,6 +2,7 @@ import { PreviewSdkService } from "../../lib/services/livesync/playground/previe import { Yok } from "../../lib/common/yok"; import { assert } from "chai"; import { LoggerStub } from "../stubs"; +import { PubnubKeys } from "../../lib/services/livesync/playground/preview-app-constants"; const getPreviewSdkService = (): IPreviewSdkService => { const testInjector = new Yok(); @@ -19,20 +20,108 @@ const getPreviewSdkService = (): IPreviewSdkService => { describe('PreviewSdkService', () => { describe('getQrCodeUrl', () => { - it('sets hmr to 1 when useHotModuleReload is true', async () => { - const sdk = getPreviewSdkService(); + describe("hmr", () => { + it('sets hmr to 1 when useHotModuleReload is true', async () => { + const sdk = getPreviewSdkService(); - const previewUrl = sdk.getQrCodeUrl({ useHotModuleReload: true }); + const previewUrl = sdk.getQrCodeUrl({ useHotModuleReload: true }); - assert.isTrue(previewUrl.indexOf("hmr=1") > -1); + assert.isTrue(previewUrl.indexOf("hmr=1") > -1); + }); + it('sets hmr to 0 when useHotModuleReload is false', async () => { + const sdk = getPreviewSdkService(); + + const previewUrl = sdk.getQrCodeUrl({ useHotModuleReload: false }); + + assert.isTrue(previewUrl.indexOf("hmr=0") > -1); + }); + }); + + describe("schema", () => { + const testCases: [{ name: string, schemaFromApi: string, schemaFromNsConfig: string, expectedSchemaName: string }] = [ + { + name: "should return the schema from api", + schemaFromApi: "ksplay", + schemaFromNsConfig: null, + expectedSchemaName: "ksplay" + }, + { + name: "should return the schema from nsconfig", + schemaFromApi: null, + schemaFromNsConfig: "ksplay", + expectedSchemaName: "ksplay" + }, + { + name: "should return the default schema", + schemaFromApi: null, + schemaFromNsConfig: null, + expectedSchemaName: "nsplay" + } + ]; + + _.each(testCases, testCase => { + it(`${testCase.name}`, () => { + const qrCodeData = { schemaName: testCase.schemaFromApi }; + const qrCodeOptions = { nsConfigPreviewAppSchema: testCase.schemaFromNsConfig, qrCodeData, useHotModuleReload: true }; + const previewSdkService = getPreviewSdkService(); + + const qrCodeUrl = previewSdkService.getQrCodeUrl(qrCodeOptions); + + assert.deepEqual(qrCodeUrl.split(":")[0], testCase.expectedSchemaName); + }); + }); }); - }); - it('sets hmr to 0 when useHotModuleReload is false', async () => { - const sdk = getPreviewSdkService(); + describe("publishKey", () => { + const testCases = [ + { + name: "should return the provided key from api", + publishKeyFromApi: "myTestPublishKey", + expectedPublishKey: "myTestPublishKey" + }, + { + name: "should return the default key", + publishKeyFromApi: null, + expectedPublishKey: PubnubKeys.PUBLISH_KEY + } + ]; - const previewUrl = sdk.getQrCodeUrl({ useHotModuleReload: false }); + _.each(testCases, testCase => { + it(`${testCase.name}`, () => { + const qrCodeOptions = { projectData: {}, qrCodeData: { publishKey: testCase.publishKeyFromApi }, useHotModuleReload: true }; + const previewSdkService = getPreviewSdkService(); - assert.isTrue(previewUrl.indexOf("hmr=0") > -1); + const qrCodeUrl = previewSdkService.getQrCodeUrl(qrCodeOptions); + + assert.isTrue(qrCodeUrl.indexOf(`&pKey=${testCase.expectedPublishKey}`) > -1); + }); + }); + }); + + describe("subscribeKey", () => { + const testCases = [ + { + name: "should return the provided key from api", + subscribeKeyFromApi: "myTestSubscribeKey", + expectedSubscribeKey: "myTestSubscribeKey" + }, + { + name: "should return the default key", + subscribeKeyFromApi: null, + expectedSubscribeKey: PubnubKeys.SUBSCRIBE_KEY + } + ]; + + _.each(testCases, testCase => { + it(`${testCase.name}`, () => { + const qrCodeOptions = { projectData: {}, qrCodeData: { subscribeKey: testCase.subscribeKeyFromApi }, useHotModuleReload: true }; + const previewSdkService = getPreviewSdkService(); + + const qrCodeUrl = previewSdkService.getQrCodeUrl(qrCodeOptions); + + assert.isTrue(qrCodeUrl.indexOf(`&sKey=${testCase.expectedSubscribeKey}`) > -1); + }); + }); + }); }); }); diff --git a/test/stubs.ts b/test/stubs.ts index 1ee833096d..8ef40eb0e6 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -332,6 +332,7 @@ export class ProjectDataStub implements IProjectData { public podfilePath: string; public isShared: boolean; public useLegacyWorkflow: boolean; + public previewAppSchema: string; public initializeProjectData(projectDir?: string): void { this.projectDir = this.projectDir || projectDir; From 43fda3bea3e9a16ce11ee71e563bd9979a6a5658 Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 22 Mar 2019 12:12:47 +0200 Subject: [PATCH 4/6] fix: respect the schema only from nsconfig file --- lib/commands/preview.ts | 2 +- lib/definitions/preview-app-livesync.d.ts | 18 +--- lib/services/livesync/livesync-service.ts | 7 +- .../playground/preview-sdk-service.ts | 16 ++-- .../platform-environment-requirements.ts | 2 +- test/services/preview-sdk-service.ts | 90 +++++-------------- 6 files changed, 36 insertions(+), 99 deletions(-) diff --git a/lib/commands/preview.ts b/lib/commands/preview.ts index 7415099c79..1dddd24a3c 100644 --- a/lib/commands/preview.ts +++ b/lib/commands/preview.ts @@ -30,7 +30,7 @@ export class PreviewCommand implements ICommand { }); await this.$previewQrCodeService.printLiveSyncQrCode({ - nsConfigPreviewAppSchema: this.$projectData.previewAppSchema, + projectDir: this.$projectData.projectDir, useHotModuleReload: this.$options.hmr, link: this.$options.link }); diff --git a/lib/definitions/preview-app-livesync.d.ts b/lib/definitions/preview-app-livesync.d.ts index 79cddd8cf1..4eef7d8cc7 100644 --- a/lib/definitions/preview-app-livesync.d.ts +++ b/lib/definitions/preview-app-livesync.d.ts @@ -18,15 +18,7 @@ declare global { filesToRemove?: string[]; } - interface IPreviewAppLiveSyncData extends IProjectDir, IHasUseHotModuleReloadOption, IBundle, IEnvOptions { - qrCodeData?: IPreviewAppQrCodeData; - } - - interface IPreviewAppQrCodeData { - publishKey?: string; - subscribeKey?: string; - schemaName?: string; - } + interface IPreviewAppLiveSyncData extends IProjectDir, IHasUseHotModuleReloadOption, IBundle, IEnvOptions { } interface IPreviewSdkService extends EventEmitter { getQrCodeUrl(options: IGetQrCodeUrlOptions): string; @@ -35,10 +27,7 @@ declare global { stop(): void; } - interface IGetQrCodeUrlOptions extends IHasUseHotModuleReloadOption { - nsConfigPreviewAppSchema?: string; - qrCodeData?: IPreviewAppQrCodeData; - } + interface IGetQrCodeUrlOptions extends IHasUseHotModuleReloadOption, IProjectDir { } interface IPreviewAppPluginsService { getPluginsUsageWarnings(data: IPreviewAppLiveSyncData, device: Device): string[]; @@ -60,8 +49,7 @@ declare global { platform?: string; } - interface IPrintLiveSyncOptions extends IHasUseHotModuleReloadOption { - nsConfigPreviewAppSchema?: string; + interface IPrintLiveSyncOptions extends IGetQrCodeUrlOptions { /** * If set to true, a link will be shown on console instead of QR code * Default value is false. diff --git a/lib/services/livesync/livesync-service.ts b/lib/services/livesync/livesync-service.ts index 502a4ef21a..5c36471064 100644 --- a/lib/services/livesync/livesync-service.ts +++ b/lib/services/livesync/livesync-service.ts @@ -66,12 +66,7 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi env: data.env, }); - const projectData = this.$projectDataService.getProjectData(data.projectDir); - const url = this.$previewSdkService.getQrCodeUrl({ - nsConfigPreviewAppSchema: projectData.previewAppSchema, - qrCodeData: data.qrCodeData, - useHotModuleReload: data.useHotModuleReload - }); + const url = this.$previewSdkService.getQrCodeUrl({ projectDir: data.projectDir, useHotModuleReload: data.useHotModuleReload }); const result = await this.$previewQrCodeService.getLiveSyncQrCode(url); return result; } diff --git a/lib/services/livesync/playground/preview-sdk-service.ts b/lib/services/livesync/playground/preview-sdk-service.ts index bbdec6abdf..fc9565184a 100644 --- a/lib/services/livesync/playground/preview-sdk-service.ts +++ b/lib/services/livesync/playground/preview-sdk-service.ts @@ -12,17 +12,21 @@ export class PreviewSdkService extends EventEmitter implements IPreviewSdkServic private $httpClient: Server.IHttpClient, private $logger: ILogger, private $previewDevicesService: IPreviewDevicesService, - private $previewAppLogProvider: IPreviewAppLogProvider) { + private $previewAppLogProvider: IPreviewAppLogProvider, + private $projectDataService: IProjectDataService) { super(); } public getQrCodeUrl(options: IGetQrCodeUrlOptions): string { - const { nsConfigPreviewAppSchema, qrCodeData = { }, useHotModuleReload } = options; - const schema = qrCodeData.schemaName || nsConfigPreviewAppSchema || "nsplay"; - const publishKey = qrCodeData.publishKey || PubnubKeys.PUBLISH_KEY; - const subscribeKey = qrCodeData.subscribeKey || PubnubKeys.SUBSCRIBE_KEY; + const { projectDir, useHotModuleReload } = options; + const projectData = this.$projectDataService.getProjectData(projectDir); + const schema = projectData.previewAppSchema || "nsplay"; + // TODO: Use the correct keys for the schema + const publishKey = PubnubKeys.PUBLISH_KEY; + const subscribeKey = PubnubKeys.SUBSCRIBE_KEY; const hmrValue = useHotModuleReload ? "1" : "0"; - return `${schema}://boot?instanceId=${this.instanceId}&pKey=${publishKey}&sKey=${subscribeKey}&template=play-ng&hmr=${hmrValue}`; + const result = `${schema}://boot?instanceId=${this.instanceId}&pKey=${publishKey}&sKey=${subscribeKey}&template=play-ng&hmr=${hmrValue}`; + return result; } public async initialize(getInitialFiles: (device: Device) => Promise): Promise { diff --git a/lib/services/platform-environment-requirements.ts b/lib/services/platform-environment-requirements.ts index 4cbd86c4ad..e30353eded 100644 --- a/lib/services/platform-environment-requirements.ts +++ b/lib/services/platform-environment-requirements.ts @@ -194,7 +194,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ useHotModuleReload: options.hmr }); - await this.$previewQrCodeService.printLiveSyncQrCode({ useHotModuleReload: options.hmr, link: options.link }); + await this.$previewQrCodeService.printLiveSyncQrCode({ projectDir, useHotModuleReload: options.hmr, link: options.link }); } } diff --git a/test/services/preview-sdk-service.ts b/test/services/preview-sdk-service.ts index 0e9de72606..c129ead91d 100644 --- a/test/services/preview-sdk-service.ts +++ b/test/services/preview-sdk-service.ts @@ -2,9 +2,8 @@ import { PreviewSdkService } from "../../lib/services/livesync/playground/previe import { Yok } from "../../lib/common/yok"; import { assert } from "chai"; import { LoggerStub } from "../stubs"; -import { PubnubKeys } from "../../lib/services/livesync/playground/preview-app-constants"; -const getPreviewSdkService = (): IPreviewSdkService => { +const createTestInjector = (): IInjector => { const testInjector = new Yok(); testInjector.register("logger", LoggerStub); testInjector.register("config", {}); @@ -14,46 +13,49 @@ const getPreviewSdkService = (): IPreviewSdkService => { testInjector.register("httpClient", { httpRequest: async (options: any, proxySettings?: IProxySettings): Promise => undefined }); + testInjector.register("projectDataService", { + getProjectData: () => ({}) + }); - return testInjector.resolve("previewSdkService"); + return testInjector; }; describe('PreviewSdkService', () => { + let injector: IInjector, previewSdkService: IPreviewSdkService; + + beforeEach(() => { + injector = createTestInjector(); + previewSdkService = injector.resolve("previewSdkService"); + }); + describe('getQrCodeUrl', () => { describe("hmr", () => { it('sets hmr to 1 when useHotModuleReload is true', async () => { - const sdk = getPreviewSdkService(); - - const previewUrl = sdk.getQrCodeUrl({ useHotModuleReload: true }); + const previewUrl = previewSdkService.getQrCodeUrl({ projectDir: "", useHotModuleReload: true }); assert.isTrue(previewUrl.indexOf("hmr=1") > -1); }); it('sets hmr to 0 when useHotModuleReload is false', async () => { - const sdk = getPreviewSdkService(); - - const previewUrl = sdk.getQrCodeUrl({ useHotModuleReload: false }); + const previewUrl = previewSdkService.getQrCodeUrl({ projectDir: "", useHotModuleReload: false }); assert.isTrue(previewUrl.indexOf("hmr=0") > -1); }); }); describe("schema", () => { - const testCases: [{ name: string, schemaFromApi: string, schemaFromNsConfig: string, expectedSchemaName: string }] = [ + const testCases = [ { name: "should return the schema from api", - schemaFromApi: "ksplay", - schemaFromNsConfig: null, - expectedSchemaName: "ksplay" + schemaFromNsConfig: "nsplay", + expectedSchemaName: "nsplay" }, { name: "should return the schema from nsconfig", - schemaFromApi: null, schemaFromNsConfig: "ksplay", expectedSchemaName: "ksplay" }, { name: "should return the default schema", - schemaFromApi: null, schemaFromNsConfig: null, expectedSchemaName: "nsplay" } @@ -61,9 +63,9 @@ describe('PreviewSdkService', () => { _.each(testCases, testCase => { it(`${testCase.name}`, () => { - const qrCodeData = { schemaName: testCase.schemaFromApi }; - const qrCodeOptions = { nsConfigPreviewAppSchema: testCase.schemaFromNsConfig, qrCodeData, useHotModuleReload: true }; - const previewSdkService = getPreviewSdkService(); + const qrCodeOptions = { projectDir: "myTestDir", useHotModuleReload: true }; + const projectDataService = injector.resolve("projectDataService"); + projectDataService.getProjectData = () => ({ previewAppSchema: testCase.schemaFromNsConfig }); const qrCodeUrl = previewSdkService.getQrCodeUrl(qrCodeOptions); @@ -71,57 +73,5 @@ describe('PreviewSdkService', () => { }); }); }); - - describe("publishKey", () => { - const testCases = [ - { - name: "should return the provided key from api", - publishKeyFromApi: "myTestPublishKey", - expectedPublishKey: "myTestPublishKey" - }, - { - name: "should return the default key", - publishKeyFromApi: null, - expectedPublishKey: PubnubKeys.PUBLISH_KEY - } - ]; - - _.each(testCases, testCase => { - it(`${testCase.name}`, () => { - const qrCodeOptions = { projectData: {}, qrCodeData: { publishKey: testCase.publishKeyFromApi }, useHotModuleReload: true }; - const previewSdkService = getPreviewSdkService(); - - const qrCodeUrl = previewSdkService.getQrCodeUrl(qrCodeOptions); - - assert.isTrue(qrCodeUrl.indexOf(`&pKey=${testCase.expectedPublishKey}`) > -1); - }); - }); - }); - - describe("subscribeKey", () => { - const testCases = [ - { - name: "should return the provided key from api", - subscribeKeyFromApi: "myTestSubscribeKey", - expectedSubscribeKey: "myTestSubscribeKey" - }, - { - name: "should return the default key", - subscribeKeyFromApi: null, - expectedSubscribeKey: PubnubKeys.SUBSCRIBE_KEY - } - ]; - - _.each(testCases, testCase => { - it(`${testCase.name}`, () => { - const qrCodeOptions = { projectData: {}, qrCodeData: { subscribeKey: testCase.subscribeKeyFromApi }, useHotModuleReload: true }; - const previewSdkService = getPreviewSdkService(); - - const qrCodeUrl = previewSdkService.getQrCodeUrl(qrCodeOptions); - - assert.isTrue(qrCodeUrl.indexOf(`&sKey=${testCase.expectedSubscribeKey}`) > -1); - }); - }); - }); }); }); From d50b5d41b487c9131b57b92ee1594033628e0577 Mon Sep 17 00:00:00 2001 From: fatme Date: Mon, 25 Mar 2019 08:27:34 +0200 Subject: [PATCH 5/6] fix: add support for android 'Q' https://github.com/NativeScript/nativescript-cli/issues/4451 --- lib/common/mobile/android/android-device.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/common/mobile/android/android-device.ts b/lib/common/mobile/android/android-device.ts index 81a2623cbb..a98c2b0528 100644 --- a/lib/common/mobile/android/android-device.ts +++ b/lib/common/mobile/android/android-device.ts @@ -71,11 +71,16 @@ export class AndroidDevice implements Mobile.IAndroidDevice { const adbStatusInfo = AndroidDevice.ADB_DEVICE_STATUS_INFO[this.status]; const type = await this.getType(); + let version = details.release; + if (version && version.toLowerCase() === 'q') { + version = '10.0.0'; + } + this.deviceInfo = { identifier: this.identifier, displayName: details.name, model: details.model, - version: details.release, + version, vendor: details.brand, platform: this.$devicePlatformsConstants.Android, status: adbStatusInfo ? adbStatusInfo.deviceStatus : this.status, From b720651bdd9e67141f75a4c9f02f391aa768ad85 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 27 Mar 2019 22:33:11 +0200 Subject: [PATCH 6/6] fix: livesync should stop when all devices are disconnected Whenever all devices/emulators/simulators that we are using for LiveSync operation are disconnected or we are unable to sync changes on them, the command (`tns debug`, `tns run`...) should exit. This is not happening currently due to the setIntervals and iOS device detection that happens and does not stop when the devices are disconnected. So workaround the problem by handling the liveSyncStopped event for the livesync related commands. In case we receive liveSyncStopped for all devices that we've been using for LiveSync action, call process.exit. Use non-zero exit code for this case, as if we receive liveSyncStopped event, we've either received error for particular device or it has been stopped. For both cases this is not a correct behavior for LiveSync. --- lib/common/declarations.d.ts | 3 +- lib/constants.ts | 11 + lib/definitions/livesync.d.ts | 1263 +++++++++++---------- lib/helpers/livesync-command-helper.ts | 11 + lib/services/livesync/livesync-service.ts | 21 +- test/stubs.ts | 2 +- 6 files changed, 668 insertions(+), 643 deletions(-) diff --git a/lib/common/declarations.d.ts b/lib/common/declarations.d.ts index aa1369441a..5e096b0368 100644 --- a/lib/common/declarations.d.ts +++ b/lib/common/declarations.d.ts @@ -596,7 +596,8 @@ declare const enum ErrorCodes { KARMA_FAIL = 130, UNHANDLED_REJECTION_FAILURE = 131, DELETED_KILL_FILE = 132, - TESTS_INIT_REQUIRED = 133 + TESTS_INIT_REQUIRED = 133, + ALL_DEVICES_DISCONNECTED = 134 } interface IFutureDispatcher { diff --git a/lib/constants.ts b/lib/constants.ts index ed6b281de0..a1a8961018 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1,4 +1,5 @@ require("colors"); +import { PreviewAppLiveSyncEvents } from "./services/livesync/playground/preview-app-constants"; export const APP_FOLDER_NAME = "app"; export const APP_RESOURCES_FOLDER_NAME = "App_Resources"; @@ -269,3 +270,13 @@ export class AndroidAppBundleMessages { public static ANDROID_APP_BUNDLE_DOCS_MESSAGE = "What is Android App Bundle: https://docs.nativescript.org/tooling/publishing/android-app-bundle"; public static ANDROID_APP_BUNDLE_PUBLISH_DOCS_MESSAGE = "How to use Android App Bundle for publishing: https://docs.nativescript.org/tooling/publishing/publishing-android-apps#android-app-bundle"; } + +export const LiveSyncEvents = { + liveSyncStopped: "liveSyncStopped", + // In case we name it error, EventEmitter expects instance of Error to be raised and will also raise uncaught exception in case there's no handler + liveSyncError: "liveSyncError", + previewAppLiveSyncError: PreviewAppLiveSyncEvents.PREVIEW_APP_LIVE_SYNC_ERROR, + liveSyncExecuted: "liveSyncExecuted", + liveSyncStarted: "liveSyncStarted", + liveSyncNotification: "notify" +}; diff --git a/lib/definitions/livesync.d.ts b/lib/definitions/livesync.d.ts index 717f41693f..b71cb07b93 100644 --- a/lib/definitions/livesync.d.ts +++ b/lib/definitions/livesync.d.ts @@ -1,629 +1,634 @@ -// This interface is a mashup of NodeJS' along with Chokidar's event watchers -interface IFSWatcher extends NodeJS.EventEmitter { - // from fs.FSWatcher - close(): void; - - /** - * events.EventEmitter - * 1. change - * 2. error - */ - addListener(event: string, listener: Function): this; - addListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - addListener(event: "error", listener: (code: number, signal: string) => void): this; - - on(event: string, listener: Function): this; - on(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - on(event: "error", listener: (code: number, signal: string) => void): this; - - once(event: string, listener: Function): this; - once(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - once(event: "error", listener: (code: number, signal: string) => void): this; - - prependListener(event: string, listener: Function): this; - prependListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - prependListener(event: "error", listener: (code: number, signal: string) => void): this; - - prependOnceListener(event: string, listener: Function): this; - prependOnceListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - prependOnceListener(event: "error", listener: (code: number, signal: string) => void): this; - - // From chokidar FSWatcher - - /** - * Add files, directories, or glob patterns for tracking. Takes an array of strings or just one - * string. - */ - add(paths: string | string[]): void; - - /** - * Stop watching files, directories, or glob patterns. Takes an array of strings or just one - * string. - */ - unwatch(paths: string | string[]): void; - - /** - * Returns an object representing all the paths on the file system being watched by this - * `FSWatcher` instance. The object's keys are all the directories (using absolute paths unless - * the `cwd` option was used), and the values are arrays of the names of the items contained in - * each directory. - */ - getWatched(): IDictionary; - - /** - * Removes all listeners from watched files. - */ - close(): void; -} - -interface ILiveSyncProcessInfo { - timer: NodeJS.Timer; - watcherInfo: { - watcher: IFSWatcher, - patterns: string[] - }; - actionsChain: Promise; - isStopped: boolean; - deviceDescriptors: ILiveSyncDeviceInfo[]; - currentSyncAction: Promise; - syncToPreviewApp: boolean; -} - -interface IOptionalOutputPath { - /** - * Path where the build result is located (directory containing .ipa, .apk or .zip). - * This is required for initial checks where LiveSync will skip the rebuild in case there's already a build result and no change requiring rebuild is made since then. - * In case it is not passed, the default output for local builds will be used. - */ - outputPath?: string; -} - -/** - * Describes action used whenever building a project. - */ -interface IBuildAction { - /** - * @returns {Promise} Path to build artifact (.ipa, .apk or .zip). - */ - (): Promise; -} - -/** - * Describes options that can be passed in order to specify the exact location of the built package. - */ -interface IOutputDirectoryOptions extends IPlatform { - /** - * Directory where the project is located. - */ - projectDir: string; - - /** - * Whether the build is for emulator or not. - */ - emulator?: boolean; -} - -/** - * Describes information for LiveSync on a device. - */ -interface ILiveSyncDeviceInfo extends IOptionalOutputPath, IOptionalDebuggingOptions { - /** - * Device identifier. - */ - identifier: string; - - /** - * Action that will rebuild the application. The action must return a Promise, which is resolved with at path to build artifact. - */ - buildAction: IBuildAction; - - /** - * Whether to skip preparing the native platform. - */ - skipNativePrepare?: boolean; - - /** - * Whether debugging has been enabled for this device or not - */ - debugggingEnabled?: boolean; - - /** - * Describes options specific for each platform, like provision for iOS, target sdk for Android, etc. - */ - platformSpecificOptions?: IPlatformOptions; -} - -interface IOptionalSkipWatcher { - /** - * Defines if the watcher should be skipped. If not passed, fs.Watcher will be started. - */ - skipWatcher?: boolean; -} - -/** - * Describes a LiveSync operation. - */ -interface ILiveSyncInfo extends IProjectDir, IEnvOptions, IBundle, IRelease, IOptionalSkipWatcher, IHasUseHotModuleReloadOption, IHasSyncToPreviewAppOption { - /** - * Defines if all project files should be watched for changes. In case it is not passed, only `app` dir of the project will be watched for changes. - * In case it is set to true, the package.json of the project and node_modules directory will also be watched, so any change there will be transferred to device(s). - */ - watchAllFiles?: boolean; - - /** - * Forces a build before the initial livesync. - */ - clean?: boolean; - - /** - * Defines if initial sync will be forced. - * In case it is true, transfers all project's directory on device - * In case it is false, transfers only changed files. - */ - force?: boolean; - - /** - * Defines the timeout in seconds {N} CLI will wait to find the inspector socket port from device's logs. - * If not provided, defaults to 10seconds. - */ - timeout?: string; -} - -interface IHasSyncToPreviewAppOption { - /** - * Defines if the livesync should be executed in preview app on device. - */ - syncToPreviewApp?: boolean; -} - -interface IHasUseHotModuleReloadOption { - /** - * Defines if the hot module reload should be used. - */ - useHotModuleReload: boolean; -} - -interface ILiveSyncEventData { - deviceIdentifier: string, - applicationIdentifier?: string, - projectDir: string, - syncedFiles?: string[], - error?: Error, - notification?: string, - isFullSync?: boolean -} - -interface ILatestAppPackageInstalledSettings extends IDictionary> { /* empty */ } - -interface IIsEmulator { - isEmulator: boolean; -} - -interface ILiveSyncBuildInfo extends IIsEmulator, IPlatform { - pathToBuildItem: string; -} - -interface IProjectDataComposition { - projectData: IProjectData; -} - -/** - * Desribes object that can be passed to ensureLatestAppPackageIsInstalledOnDevice method. - */ -interface IEnsureLatestAppPackageIsInstalledOnDeviceOptions extends IProjectDataComposition, IEnvOptions, IBundle, IRelease, ISkipNativeCheckOptional, IOptionalFilesToRemove, IOptionalFilesToSync { - device: Mobile.IDevice; - preparedPlatforms: string[]; - rebuiltInformation: ILiveSyncBuildInfo[]; - deviceBuildInfoDescriptor: ILiveSyncDeviceInfo; - settings: ILatestAppPackageInstalledSettings; - liveSyncData?: ILiveSyncInfo; - modifiedFiles?: string[]; -} - -/** - * Describes the action that has been executed during ensureLatestAppPackageIsInstalledOnDevice execution. - */ -interface IAppInstalledOnDeviceResult { - /** - * Defines if the app has been installed on device from the ensureLatestAppPackageIsInstalledOnDevice method. - */ - appInstalled: boolean; -} - -/** - * Describes LiveSync operations. - */ -interface ILiveSyncService { - /** - * Starts LiveSync operation by rebuilding the application if necessary and starting watcher. - * @param {ILiveSyncDeviceInfo[]} deviceDescriptors Describes each device for which we would like to sync the application - identifier, outputPath and action to rebuild the app. - * @param {ILiveSyncInfo} liveSyncData Describes the LiveSync operation - for which project directory is the operation and other settings. - * @returns {Promise} - */ - liveSync(deviceDescriptors: ILiveSyncDeviceInfo[], liveSyncData: ILiveSyncInfo): Promise; - - /** - * Starts LiveSync operation to Preview app. - * @param {IPreviewAppLiveSyncData} data Describes information about the current operation. - * @returns {Promise} Data of the QR code that should be used to start the LiveSync operation. - */ - liveSyncToPreviewApp(data: IPreviewAppLiveSyncData): Promise; - - /** - * Stops LiveSync operation for specified directory. - * @param {string} projectDir The directory for which to stop the operation. - * @param {string[]} @optional deviceIdentifiers Device ids for which to stop the application. In case nothing is passed, LiveSync operation will be stopped for all devices. - * @param { shouldAwaitAllActions: boolean } @optional stopOptions Specifies whether we should await all actions. - * @returns {Promise} - */ - stopLiveSync(projectDir: string, deviceIdentifiers?: string[], stopOptions?: { shouldAwaitAllActions: boolean }): Promise; - - /** - * Returns the device information for current LiveSync operation of specified project. - * In case LiveSync has been started on many devices, but stopped for some of them at a later point, - * calling the method after that will return information only for devices for which LiveSync operation is in progress. - * @param {string} projectDir The path to project for which the LiveSync operation is executed - * @returns {ILiveSyncDeviceInfo[]} Array of elements describing parameters used to start LiveSync on each device. - */ - getLiveSyncDeviceDescriptors(projectDir: string): ILiveSyncDeviceInfo[]; -} - -/** - * Describes LiveSync operations while debuggging. - */ -interface IDebugLiveSyncService extends ILiveSyncService { - /** - * Method used to retrieve the glob patterns which CLI will watch for file changes. Defaults to the whole app directory. - * @param {ILiveSyncInfo} liveSyncData Information needed for livesync - for example if bundle is passed or if a release build should be performed. - * @param {IProjectData} projectData Project data. - * @param {string[]} platforms Platforms to start the watcher for. - * @returns {Promise} The glob patterns. - */ - getWatcherPatterns(liveSyncData: ILiveSyncInfo, projectData: IProjectData, platforms: string[]): Promise; - - /** - * Prints debug information. - * @param {IDebugInformation} debugInformation Information to be printed. - * @returns {IDebugInformation} Full url and port where the frontend client can be connected. - */ - printDebugInformation(debugInformation: IDebugInformation): IDebugInformation; - - /** - * Enables debugging for the specified devices - * @param {IEnableDebuggingDeviceOptions[]} deviceOpts Settings used for enabling debugging for each device. - * @param {IDebuggingAdditionalOptions} enableDebuggingOptions Settings used for enabling debugging. - * @returns {Promise[]} Array of promises for each device. - */ - enableDebugging(deviceOpts: IEnableDebuggingDeviceOptions[], enableDebuggingOptions: IDebuggingAdditionalOptions): Promise[]; - - /** - * Disables debugging for the specified devices - * @param {IDisableDebuggingDeviceOptions[]} deviceOptions Settings used for disabling debugging for each device. - * @param {IDebuggingAdditionalOptions} debuggingAdditionalOptions Settings used for disabling debugging. - * @returns {Promise[]} Array of promises for each device. - */ - disableDebugging(deviceOptions: IDisableDebuggingDeviceOptions[], debuggingAdditionalOptions: IDebuggingAdditionalOptions): Promise[]; - - /** - * Attaches a debugger to the specified device. - * @param {IAttachDebuggerOptions} settings Settings used for controling the attaching process. - * @returns {Promise} Full url and port where the frontend client can be connected. - */ - attachDebugger(settings: IAttachDebuggerOptions): Promise; -} - -/** - * Describes additional debugging settings. - */ -interface IDebuggingAdditionalOptions extends IProjectDir { } - -/** - * Describes settings used when disabling debugging. - */ -interface IDisableDebuggingDeviceOptions extends Mobile.IDeviceIdentifier { } - -interface IOptionalDebuggingOptions { - /** - * Optional debug options - can be used to control the start of a debug process. - */ - debugOptions?: IDebugOptions; -} - -/** - * Describes settings used when enabling debugging. - */ -interface IEnableDebuggingDeviceOptions extends Mobile.IDeviceIdentifier, IOptionalDebuggingOptions { } - -/** - * Describes settings passed to livesync service in order to control event emitting during refresh application. - */ -interface IRefreshApplicationSettings { - shouldSkipEmitLiveSyncNotification: boolean; - shouldCheckDeveloperDiscImage: boolean; -} - -/** - * Describes settings used for attaching a debugger. - */ -interface IAttachDebuggerOptions extends IDebuggingAdditionalOptions, IEnableDebuggingDeviceOptions, IIsEmulator, IPlatform, IOptionalOutputPath { -} - -interface IConnectTimeoutOption { - /** - * Time to wait for successful connection. Defaults to 30000 miliseconds. - */ - connectTimeout?: number; -} - -interface ILiveSyncWatchInfo extends IProjectDataComposition, IHasUseHotModuleReloadOption, IConnectTimeoutOption { - filesToRemove: string[]; - filesToSync: string[]; - isReinstalled: boolean; - syncAllFiles: boolean; - liveSyncDeviceInfo: ILiveSyncDeviceInfo; - hmrData: IPlatformHmrData; - force?: boolean; -} - -interface ILiveSyncResultInfo extends IHasUseHotModuleReloadOption { - modifiedFilesData: Mobile.ILocalToDevicePathData[]; - isFullSync: boolean; - waitForDebugger?: boolean; - deviceAppData: Mobile.IDeviceAppData; - didRecover?: boolean -} - -interface IAndroidLiveSyncResultInfo extends ILiveSyncResultInfo, IAndroidLivesyncSyncOperationResult { } - -interface IFullSyncInfo extends IProjectDataComposition, IHasUseHotModuleReloadOption, IConnectTimeoutOption { - device: Mobile.IDevice; - watch: boolean; - syncAllFiles: boolean; - liveSyncDeviceInfo: ILiveSyncDeviceInfo; - force?: boolean; -} - -interface IPlatformHmrData { - hash: string; - fallbackFiles: string[]; -} - -interface ITransferFilesOptions { - isFullSync: boolean; - force?: boolean; -} - -interface IPlatformLiveSyncService { - fullSync(syncInfo: IFullSyncInfo): Promise; - liveSyncWatchAction(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise; - tryRefreshApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; - restartApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; - shouldRestart(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; - getDeviceLiveSyncService(device: Mobile.IDevice, projectData: IProjectData): INativeScriptDeviceLiveSyncService; -} -interface IRestartApplicationInfo { - didRestart: boolean; -} - -interface INativeScriptDeviceLiveSyncService { - /** - * Specifies some action that will be executed before every sync operation - */ - beforeLiveSyncAction?(deviceAppData: Mobile.IDeviceAppData): Promise; - - /** - * Tries to refresh the application's content on the device - */ - tryRefreshApplication(projectData: IProjectData, - liveSyncInfo: ILiveSyncResultInfo): Promise; - - /** - * Restarts the specified application - */ - restartApplication(projectData: IProjectData, - liveSyncInfo: ILiveSyncResultInfo): Promise; - - /** - * Returns if the application have to be restarted in order to apply the specified livesync changes - */ - shouldRestart(projectData: IProjectData, - liveSyncInfo: ILiveSyncResultInfo): Promise; - - /** - * Removes specified files from a connected device - * @param {Mobile.IDeviceAppData} deviceAppData Data about device and app. - * @param {Mobile.ILocalToDevicePathData[]} localToDevicePaths Object containing a mapping of file paths from the system to the device. - * @param {string} projectFilesPath The Path to the app folder inside platforms folder - * @return {Promise} - */ - removeFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath?: string): Promise; - - /** - * Transfers specified files to a connected device - * @param {Mobile.IDeviceAppData} deviceAppData Data about device and app. - * @param {Mobile.ILocalToDevicePathData[]} localToDevicePaths Object containing a mapping of file paths from the system to the device. - * @param {string} projectFilesPath The Path to the app folder inside platforms folder - * @param {boolean} isFullSync Indicates if the operation is part of a fullSync - * @return {Promise} Returns the ILocalToDevicePathData of all transfered files - */ - transferFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string, projectData: IProjectData, liveSyncDeviceInfo: ILiveSyncDeviceInfo, options: ITransferFilesOptions): Promise; -} - -interface IAndroidNativeScriptDeviceLiveSyncService extends INativeScriptDeviceLiveSyncService { - /** - * Guarantees all remove/update operations have finished - * @param {ILiveSyncResultInfo} liveSyncInfo Describes the LiveSync operation - for which project directory is the operation and other settings. - * @return {Promise} - */ - finalizeSync(liveSyncInfo: ILiveSyncResultInfo, projectData: IProjectData): Promise; -} - -interface ILiveSyncSocket extends INetSocket { - uid: string, - writeAsync(data: Buffer): Promise -} - -interface IAndroidLivesyncTool { - /** - * The protocol version the current app(adnroid runtime) is using. - */ - protocolVersion: string; - - /** - * Creates new socket connection. - * @param configuration - The configuration to the socket connection. - * @returns {Promise} - */ - connect(configuration: IAndroidLivesyncToolConfiguration): Promise; - /** - * Sends a file through the socket. - * @param filePath - The full path to the file. - * @returns {Promise} - */ - sendFile(filePath: string): Promise; - /** - * Sends files through the socket. - * @param filePaths - Array of files that will be send by the socket. - * @returns {Promise} - */ - sendFiles(filePaths: string[]): Promise; - /** - * Sends all files from directory by the socket. - * @param directoryPath - The path to the directory which files will be send by the socket. - * @returns {Promise} - */ - sendDirectory(directoryPath: string): Promise; - /** - * Removes file - * @param filePath - The full path to the file. - * @returns {Promise} - */ - removeFile(filePath: string): Promise; - /** - * Removes files - * @param filePaths - Array of files that will be removed. - * @returns {Promise} - */ - removeFiles(filePaths: string[]): Promise; - /** - * Sends doSyncOperation that will be handled by the runtime. - * @param options - * @returns {Promise} - */ - sendDoSyncOperation(options?: IDoSyncOperationOptions): Promise; - /** - * Generates new operation identifier. - */ - generateOperationIdentifier(): string; - /** - * Checks if the current operation is in progress. - * @param operationId - The identifier of the operation. - */ - isOperationInProgress(operationId: string): boolean; - - /** - * Closes the current socket connection. - * @param error - Optional error for rejecting pending sync operations - */ - end(error?: Error): void; - - /** - * Returns true if a connection has been already established - */ - hasConnection(): boolean; -} - -/** - * doRefresh - Indicates if the application should be refreshed. Defaults to true. - * operationId - The identifier of the operation - * timeout - The timeout in milliseconds - */ -interface IDoSyncOperationOptions { - doRefresh?: boolean, - timeout?: number, - operationId?: string -} - -interface IAndroidLivesyncToolConfiguration extends IConnectTimeoutOption { - /** - * The application identifier. - */ - appIdentifier: string; - /** - * The device identifier. - */ - deviceIdentifier: string; - /** - * The path to app folder inside platforms folder: platforms/android/app/src/main/assets/app/ - */ - appPlatformsPath: string; - /** - * If not provided, defaults to 127.0.0.1 - */ - localHostAddress?: string; - /** - * If provider will call it when an error occurs. - */ - errorHandler?: any; -} - -interface IAndroidLivesyncSyncOperationResult { - operationId: string, - didRefresh: boolean -} - -interface IDeviceProjectRootOptions { - appIdentifier: string; - getDirname?: boolean; - syncAllFiles?: boolean; - watch?: boolean; -} - -interface IDevicePathProvider { - getDeviceProjectRootPath(device: Mobile.IDevice, options: IDeviceProjectRootOptions): Promise; - getDeviceSyncZipPath(device: Mobile.IDevice): string; -} - -/** - * Describes additional options, that can be passed to LiveSyncCommandHelper. - */ -interface ILiveSyncCommandHelperAdditionalOptions extends IBuildPlatformAction, INativePrepare, IHasSyncToPreviewAppOption { - /** - * A map representing devices which have debugging enabled initially. - */ - deviceDebugMap?: IDictionary; - - /** - * Returns the path to the directory where the build output may be found. - * @param {IOutputDirectoryOptions} options Options that are used to determine the build output directory. - * @returns {string} The build output directory. - */ - getOutputDirectory?(options: IOutputDirectoryOptions): string; -} - -interface ILiveSyncCommandHelper { - /** - * Method sets up configuration, before calling livesync and expects that devices are already discovered. - * @param {Mobile.IDevice[]} devices List of discovered devices - * @param {string} platform The platform for which the livesync will be ran - * @param {ILiveSyncCommandHelperAdditionalOptions} additionalOptions @optional Additional options to control LiveSync. - * @returns {Promise} - */ - executeLiveSyncOperation(devices: Mobile.IDevice[], platform: string, additionalOptions?: ILiveSyncCommandHelperAdditionalOptions): Promise; - getPlatformsForOperation(platform: string): string[]; - - /** - * Validates the given platform's data - bundle identifier, etc. - * @param {string} platform The platform to be validated. - * @return {Promise} - */ - validatePlatform(platform: string): Promise>; - - /** - * Executes livesync operation. Meant to be called from within a command. - * @param {string} platform @optional platform for whith to run the livesync operation - * @param {ILiveSyncCommandHelperAdditionalOptions} additionalOptions @optional Additional options to control LiveSync. - * @returns {Promise} - */ - executeCommandLiveSync(platform?: string, additionalOptions?: ILiveSyncCommandHelperAdditionalOptions): Promise; -} +import { EventEmitter } from "events"; + +declare global { + // This interface is a mashup of NodeJS' along with Chokidar's event watchers + interface IFSWatcher extends NodeJS.EventEmitter { + // from fs.FSWatcher + close(): void; + + /** + * events.EventEmitter + * 1. change + * 2. error + */ + addListener(event: string, listener: Function): this; + addListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; + addListener(event: "error", listener: (code: number, signal: string) => void): this; + + on(event: string, listener: Function): this; + on(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; + on(event: "error", listener: (code: number, signal: string) => void): this; + + once(event: string, listener: Function): this; + once(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; + once(event: "error", listener: (code: number, signal: string) => void): this; + + prependListener(event: string, listener: Function): this; + prependListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; + prependListener(event: "error", listener: (code: number, signal: string) => void): this; + + prependOnceListener(event: string, listener: Function): this; + prependOnceListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; + prependOnceListener(event: "error", listener: (code: number, signal: string) => void): this; + + // From chokidar FSWatcher + + /** + * Add files, directories, or glob patterns for tracking. Takes an array of strings or just one + * string. + */ + add(paths: string | string[]): void; + + /** + * Stop watching files, directories, or glob patterns. Takes an array of strings or just one + * string. + */ + unwatch(paths: string | string[]): void; + + /** + * Returns an object representing all the paths on the file system being watched by this + * `FSWatcher` instance. The object's keys are all the directories (using absolute paths unless + * the `cwd` option was used), and the values are arrays of the names of the items contained in + * each directory. + */ + getWatched(): IDictionary; + + /** + * Removes all listeners from watched files. + */ + close(): void; + } + + interface ILiveSyncProcessInfo { + timer: NodeJS.Timer; + watcherInfo: { + watcher: IFSWatcher, + patterns: string[] + }; + actionsChain: Promise; + isStopped: boolean; + deviceDescriptors: ILiveSyncDeviceInfo[]; + currentSyncAction: Promise; + syncToPreviewApp: boolean; + } + + interface IOptionalOutputPath { + /** + * Path where the build result is located (directory containing .ipa, .apk or .zip). + * This is required for initial checks where LiveSync will skip the rebuild in case there's already a build result and no change requiring rebuild is made since then. + * In case it is not passed, the default output for local builds will be used. + */ + outputPath?: string; + } + + /** + * Describes action used whenever building a project. + */ + interface IBuildAction { + /** + * @returns {Promise} Path to build artifact (.ipa, .apk or .zip). + */ + (): Promise; + } + + /** + * Describes options that can be passed in order to specify the exact location of the built package. + */ + interface IOutputDirectoryOptions extends IPlatform { + /** + * Directory where the project is located. + */ + projectDir: string; + + /** + * Whether the build is for emulator or not. + */ + emulator?: boolean; + } + + /** + * Describes information for LiveSync on a device. + */ + interface ILiveSyncDeviceInfo extends IOptionalOutputPath, IOptionalDebuggingOptions { + /** + * Device identifier. + */ + identifier: string; + + /** + * Action that will rebuild the application. The action must return a Promise, which is resolved with at path to build artifact. + */ + buildAction: IBuildAction; + + /** + * Whether to skip preparing the native platform. + */ + skipNativePrepare?: boolean; + + /** + * Whether debugging has been enabled for this device or not + */ + debugggingEnabled?: boolean; + + /** + * Describes options specific for each platform, like provision for iOS, target sdk for Android, etc. + */ + platformSpecificOptions?: IPlatformOptions; + } + + interface IOptionalSkipWatcher { + /** + * Defines if the watcher should be skipped. If not passed, fs.Watcher will be started. + */ + skipWatcher?: boolean; + } + + /** + * Describes a LiveSync operation. + */ + interface ILiveSyncInfo extends IProjectDir, IEnvOptions, IBundle, IRelease, IOptionalSkipWatcher, IHasUseHotModuleReloadOption, IHasSyncToPreviewAppOption { + /** + * Defines if all project files should be watched for changes. In case it is not passed, only `app` dir of the project will be watched for changes. + * In case it is set to true, the package.json of the project and node_modules directory will also be watched, so any change there will be transferred to device(s). + */ + watchAllFiles?: boolean; + + /** + * Forces a build before the initial livesync. + */ + clean?: boolean; + + /** + * Defines if initial sync will be forced. + * In case it is true, transfers all project's directory on device + * In case it is false, transfers only changed files. + */ + force?: boolean; + + /** + * Defines the timeout in seconds {N} CLI will wait to find the inspector socket port from device's logs. + * If not provided, defaults to 10seconds. + */ + timeout?: string; + } + + interface IHasSyncToPreviewAppOption { + /** + * Defines if the livesync should be executed in preview app on device. + */ + syncToPreviewApp?: boolean; + } + + interface IHasUseHotModuleReloadOption { + /** + * Defines if the hot module reload should be used. + */ + useHotModuleReload: boolean; + } + + interface ILiveSyncEventData { + deviceIdentifier: string, + applicationIdentifier?: string, + projectDir: string, + syncedFiles?: string[], + error?: Error, + notification?: string, + isFullSync?: boolean + } + + interface ILatestAppPackageInstalledSettings extends IDictionary> { /* empty */ } + + interface IIsEmulator { + isEmulator: boolean; + } + + interface ILiveSyncBuildInfo extends IIsEmulator, IPlatform { + pathToBuildItem: string; + } + + interface IProjectDataComposition { + projectData: IProjectData; + } + + /** + * Desribes object that can be passed to ensureLatestAppPackageIsInstalledOnDevice method. + */ + interface IEnsureLatestAppPackageIsInstalledOnDeviceOptions extends IProjectDataComposition, IEnvOptions, IBundle, IRelease, ISkipNativeCheckOptional, IOptionalFilesToRemove, IOptionalFilesToSync { + device: Mobile.IDevice; + preparedPlatforms: string[]; + rebuiltInformation: ILiveSyncBuildInfo[]; + deviceBuildInfoDescriptor: ILiveSyncDeviceInfo; + settings: ILatestAppPackageInstalledSettings; + liveSyncData?: ILiveSyncInfo; + modifiedFiles?: string[]; + } + + /** + * Describes the action that has been executed during ensureLatestAppPackageIsInstalledOnDevice execution. + */ + interface IAppInstalledOnDeviceResult { + /** + * Defines if the app has been installed on device from the ensureLatestAppPackageIsInstalledOnDevice method. + */ + appInstalled: boolean; + } + + /** + * Describes LiveSync operations. + */ + interface ILiveSyncService extends EventEmitter { + /** + * Starts LiveSync operation by rebuilding the application if necessary and starting watcher. + * @param {ILiveSyncDeviceInfo[]} deviceDescriptors Describes each device for which we would like to sync the application - identifier, outputPath and action to rebuild the app. + * @param {ILiveSyncInfo} liveSyncData Describes the LiveSync operation - for which project directory is the operation and other settings. + * @returns {Promise} + */ + liveSync(deviceDescriptors: ILiveSyncDeviceInfo[], liveSyncData: ILiveSyncInfo): Promise; + + /** + * Starts LiveSync operation to Preview app. + * @param {IPreviewAppLiveSyncData} data Describes information about the current operation. + * @returns {Promise} Data of the QR code that should be used to start the LiveSync operation. + */ + liveSyncToPreviewApp(data: IPreviewAppLiveSyncData): Promise; + + /** + * Stops LiveSync operation for specified directory. + * @param {string} projectDir The directory for which to stop the operation. + * @param {string[]} @optional deviceIdentifiers Device ids for which to stop the application. In case nothing is passed, LiveSync operation will be stopped for all devices. + * @param { shouldAwaitAllActions: boolean } @optional stopOptions Specifies whether we should await all actions. + * @returns {Promise} + */ + stopLiveSync(projectDir: string, deviceIdentifiers?: string[], stopOptions?: { shouldAwaitAllActions: boolean }): Promise; + + /** + * Returns the device information for current LiveSync operation of specified project. + * In case LiveSync has been started on many devices, but stopped for some of them at a later point, + * calling the method after that will return information only for devices for which LiveSync operation is in progress. + * @param {string} projectDir The path to project for which the LiveSync operation is executed + * @returns {ILiveSyncDeviceInfo[]} Array of elements describing parameters used to start LiveSync on each device. + */ + getLiveSyncDeviceDescriptors(projectDir: string): ILiveSyncDeviceInfo[]; + } + + /** + * Describes LiveSync operations while debuggging. + */ + interface IDebugLiveSyncService extends ILiveSyncService { + /** + * Method used to retrieve the glob patterns which CLI will watch for file changes. Defaults to the whole app directory. + * @param {ILiveSyncInfo} liveSyncData Information needed for livesync - for example if bundle is passed or if a release build should be performed. + * @param {IProjectData} projectData Project data. + * @param {string[]} platforms Platforms to start the watcher for. + * @returns {Promise} The glob patterns. + */ + getWatcherPatterns(liveSyncData: ILiveSyncInfo, projectData: IProjectData, platforms: string[]): Promise; + + /** + * Prints debug information. + * @param {IDebugInformation} debugInformation Information to be printed. + * @returns {IDebugInformation} Full url and port where the frontend client can be connected. + */ + printDebugInformation(debugInformation: IDebugInformation): IDebugInformation; + + /** + * Enables debugging for the specified devices + * @param {IEnableDebuggingDeviceOptions[]} deviceOpts Settings used for enabling debugging for each device. + * @param {IDebuggingAdditionalOptions} enableDebuggingOptions Settings used for enabling debugging. + * @returns {Promise[]} Array of promises for each device. + */ + enableDebugging(deviceOpts: IEnableDebuggingDeviceOptions[], enableDebuggingOptions: IDebuggingAdditionalOptions): Promise[]; + + /** + * Disables debugging for the specified devices + * @param {IDisableDebuggingDeviceOptions[]} deviceOptions Settings used for disabling debugging for each device. + * @param {IDebuggingAdditionalOptions} debuggingAdditionalOptions Settings used for disabling debugging. + * @returns {Promise[]} Array of promises for each device. + */ + disableDebugging(deviceOptions: IDisableDebuggingDeviceOptions[], debuggingAdditionalOptions: IDebuggingAdditionalOptions): Promise[]; + + /** + * Attaches a debugger to the specified device. + * @param {IAttachDebuggerOptions} settings Settings used for controling the attaching process. + * @returns {Promise} Full url and port where the frontend client can be connected. + */ + attachDebugger(settings: IAttachDebuggerOptions): Promise; + } + + /** + * Describes additional debugging settings. + */ + interface IDebuggingAdditionalOptions extends IProjectDir { } + + /** + * Describes settings used when disabling debugging. + */ + interface IDisableDebuggingDeviceOptions extends Mobile.IDeviceIdentifier { } + + interface IOptionalDebuggingOptions { + /** + * Optional debug options - can be used to control the start of a debug process. + */ + debugOptions?: IDebugOptions; + } + + /** + * Describes settings used when enabling debugging. + */ + interface IEnableDebuggingDeviceOptions extends Mobile.IDeviceIdentifier, IOptionalDebuggingOptions { } + + /** + * Describes settings passed to livesync service in order to control event emitting during refresh application. + */ + interface IRefreshApplicationSettings { + shouldSkipEmitLiveSyncNotification: boolean; + shouldCheckDeveloperDiscImage: boolean; + } + + /** + * Describes settings used for attaching a debugger. + */ + interface IAttachDebuggerOptions extends IDebuggingAdditionalOptions, IEnableDebuggingDeviceOptions, IIsEmulator, IPlatform, IOptionalOutputPath { + } + + interface IConnectTimeoutOption { + /** + * Time to wait for successful connection. Defaults to 30000 miliseconds. + */ + connectTimeout?: number; + } + + interface ILiveSyncWatchInfo extends IProjectDataComposition, IHasUseHotModuleReloadOption, IConnectTimeoutOption { + filesToRemove: string[]; + filesToSync: string[]; + isReinstalled: boolean; + syncAllFiles: boolean; + liveSyncDeviceInfo: ILiveSyncDeviceInfo; + hmrData: IPlatformHmrData; + force?: boolean; + } + + interface ILiveSyncResultInfo extends IHasUseHotModuleReloadOption { + modifiedFilesData: Mobile.ILocalToDevicePathData[]; + isFullSync: boolean; + waitForDebugger?: boolean; + deviceAppData: Mobile.IDeviceAppData; + didRecover?: boolean + } + + interface IAndroidLiveSyncResultInfo extends ILiveSyncResultInfo, IAndroidLivesyncSyncOperationResult { } + + interface IFullSyncInfo extends IProjectDataComposition, IHasUseHotModuleReloadOption, IConnectTimeoutOption { + device: Mobile.IDevice; + watch: boolean; + syncAllFiles: boolean; + liveSyncDeviceInfo: ILiveSyncDeviceInfo; + force?: boolean; + } + + interface IPlatformHmrData { + hash: string; + fallbackFiles: string[]; + } + + interface ITransferFilesOptions { + isFullSync: boolean; + force?: boolean; + } + + interface IPlatformLiveSyncService { + fullSync(syncInfo: IFullSyncInfo): Promise; + liveSyncWatchAction(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise; + tryRefreshApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; + restartApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; + shouldRestart(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; + getDeviceLiveSyncService(device: Mobile.IDevice, projectData: IProjectData): INativeScriptDeviceLiveSyncService; + } + interface IRestartApplicationInfo { + didRestart: boolean; + } + + interface INativeScriptDeviceLiveSyncService { + /** + * Specifies some action that will be executed before every sync operation + */ + beforeLiveSyncAction?(deviceAppData: Mobile.IDeviceAppData): Promise; + + /** + * Tries to refresh the application's content on the device + */ + tryRefreshApplication(projectData: IProjectData, + liveSyncInfo: ILiveSyncResultInfo): Promise; + + /** + * Restarts the specified application + */ + restartApplication(projectData: IProjectData, + liveSyncInfo: ILiveSyncResultInfo): Promise; + + /** + * Returns if the application have to be restarted in order to apply the specified livesync changes + */ + shouldRestart(projectData: IProjectData, + liveSyncInfo: ILiveSyncResultInfo): Promise; + + /** + * Removes specified files from a connected device + * @param {Mobile.IDeviceAppData} deviceAppData Data about device and app. + * @param {Mobile.ILocalToDevicePathData[]} localToDevicePaths Object containing a mapping of file paths from the system to the device. + * @param {string} projectFilesPath The Path to the app folder inside platforms folder + * @return {Promise} + */ + removeFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath?: string): Promise; + + /** + * Transfers specified files to a connected device + * @param {Mobile.IDeviceAppData} deviceAppData Data about device and app. + * @param {Mobile.ILocalToDevicePathData[]} localToDevicePaths Object containing a mapping of file paths from the system to the device. + * @param {string} projectFilesPath The Path to the app folder inside platforms folder + * @param {boolean} isFullSync Indicates if the operation is part of a fullSync + * @return {Promise} Returns the ILocalToDevicePathData of all transfered files + */ + transferFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string, projectData: IProjectData, liveSyncDeviceInfo: ILiveSyncDeviceInfo, options: ITransferFilesOptions): Promise; + } + + interface IAndroidNativeScriptDeviceLiveSyncService extends INativeScriptDeviceLiveSyncService { + /** + * Guarantees all remove/update operations have finished + * @param {ILiveSyncResultInfo} liveSyncInfo Describes the LiveSync operation - for which project directory is the operation and other settings. + * @return {Promise} + */ + finalizeSync(liveSyncInfo: ILiveSyncResultInfo, projectData: IProjectData): Promise; + } + + interface ILiveSyncSocket extends INetSocket { + uid: string, + writeAsync(data: Buffer): Promise + } + + interface IAndroidLivesyncTool { + /** + * The protocol version the current app(adnroid runtime) is using. + */ + protocolVersion: string; + + /** + * Creates new socket connection. + * @param configuration - The configuration to the socket connection. + * @returns {Promise} + */ + connect(configuration: IAndroidLivesyncToolConfiguration): Promise; + /** + * Sends a file through the socket. + * @param filePath - The full path to the file. + * @returns {Promise} + */ + sendFile(filePath: string): Promise; + /** + * Sends files through the socket. + * @param filePaths - Array of files that will be send by the socket. + * @returns {Promise} + */ + sendFiles(filePaths: string[]): Promise; + /** + * Sends all files from directory by the socket. + * @param directoryPath - The path to the directory which files will be send by the socket. + * @returns {Promise} + */ + sendDirectory(directoryPath: string): Promise; + /** + * Removes file + * @param filePath - The full path to the file. + * @returns {Promise} + */ + removeFile(filePath: string): Promise; + /** + * Removes files + * @param filePaths - Array of files that will be removed. + * @returns {Promise} + */ + removeFiles(filePaths: string[]): Promise; + /** + * Sends doSyncOperation that will be handled by the runtime. + * @param options + * @returns {Promise} + */ + sendDoSyncOperation(options?: IDoSyncOperationOptions): Promise; + /** + * Generates new operation identifier. + */ + generateOperationIdentifier(): string; + /** + * Checks if the current operation is in progress. + * @param operationId - The identifier of the operation. + */ + isOperationInProgress(operationId: string): boolean; + + /** + * Closes the current socket connection. + * @param error - Optional error for rejecting pending sync operations + */ + end(error?: Error): void; + + /** + * Returns true if a connection has been already established + */ + hasConnection(): boolean; + } + + /** + * doRefresh - Indicates if the application should be refreshed. Defaults to true. + * operationId - The identifier of the operation + * timeout - The timeout in milliseconds + */ + interface IDoSyncOperationOptions { + doRefresh?: boolean, + timeout?: number, + operationId?: string + } + + interface IAndroidLivesyncToolConfiguration extends IConnectTimeoutOption { + /** + * The application identifier. + */ + appIdentifier: string; + /** + * The device identifier. + */ + deviceIdentifier: string; + /** + * The path to app folder inside platforms folder: platforms/android/app/src/main/assets/app/ + */ + appPlatformsPath: string; + /** + * If not provided, defaults to 127.0.0.1 + */ + localHostAddress?: string; + /** + * If provider will call it when an error occurs. + */ + errorHandler?: any; + } + + interface IAndroidLivesyncSyncOperationResult { + operationId: string, + didRefresh: boolean + } + + interface IDeviceProjectRootOptions { + appIdentifier: string; + getDirname?: boolean; + syncAllFiles?: boolean; + watch?: boolean; + } + + interface IDevicePathProvider { + getDeviceProjectRootPath(device: Mobile.IDevice, options: IDeviceProjectRootOptions): Promise; + getDeviceSyncZipPath(device: Mobile.IDevice): string; + } + + /** + * Describes additional options, that can be passed to LiveSyncCommandHelper. + */ + interface ILiveSyncCommandHelperAdditionalOptions extends IBuildPlatformAction, INativePrepare, IHasSyncToPreviewAppOption { + /** + * A map representing devices which have debugging enabled initially. + */ + deviceDebugMap?: IDictionary; + + /** + * Returns the path to the directory where the build output may be found. + * @param {IOutputDirectoryOptions} options Options that are used to determine the build output directory. + * @returns {string} The build output directory. + */ + getOutputDirectory?(options: IOutputDirectoryOptions): string; + } + + interface ILiveSyncCommandHelper { + /** + * Method sets up configuration, before calling livesync and expects that devices are already discovered. + * @param {Mobile.IDevice[]} devices List of discovered devices + * @param {string} platform The platform for which the livesync will be ran + * @param {ILiveSyncCommandHelperAdditionalOptions} additionalOptions @optional Additional options to control LiveSync. + * @returns {Promise} + */ + executeLiveSyncOperation(devices: Mobile.IDevice[], platform: string, additionalOptions?: ILiveSyncCommandHelperAdditionalOptions): Promise; + getPlatformsForOperation(platform: string): string[]; + + /** + * Validates the given platform's data - bundle identifier, etc. + * @param {string} platform The platform to be validated. + * @return {Promise} + */ + validatePlatform(platform: string): Promise>; + + /** + * Executes livesync operation. Meant to be called from within a command. + * @param {string} platform @optional platform for whith to run the livesync operation + * @param {ILiveSyncCommandHelperAdditionalOptions} additionalOptions @optional Additional options to control LiveSync. + * @returns {Promise} + */ + executeCommandLiveSync(platform?: string, additionalOptions?: ILiveSyncCommandHelperAdditionalOptions): Promise; + } + +} \ No newline at end of file diff --git a/lib/helpers/livesync-command-helper.ts b/lib/helpers/livesync-command-helper.ts index 1d64c300e3..9a086ed61d 100644 --- a/lib/helpers/livesync-command-helper.ts +++ b/lib/helpers/livesync-command-helper.ts @@ -1,3 +1,5 @@ +import { LiveSyncEvents } from "../constants"; + export class LiveSyncCommandHelper implements ILiveSyncCommandHelper { public static MIN_SUPPORTED_WEBPACK_VERSION_WITH_HMR = "0.17.0"; @@ -120,6 +122,15 @@ export class LiveSyncCommandHelper implements ILiveSyncCommandHelper { force: this.$options.force }; + const remainingDevicesToSync = devices.map(d => d.deviceInfo.identifier); + this.$liveSyncService.on(LiveSyncEvents.liveSyncStopped, (data: { projectDir: string, deviceIdentifier: string }) => { + _.remove(remainingDevicesToSync, d => d === data.deviceIdentifier); + + if (remainingDevicesToSync.length === 0) { + process.exit(ErrorCodes.ALL_DEVICES_DISCONNECTED); + } + }); + await this.$liveSyncService.liveSync(deviceDescriptors, liveSyncInfo); } diff --git a/lib/services/livesync/livesync-service.ts b/lib/services/livesync/livesync-service.ts index 5c36471064..6b7061f46b 100644 --- a/lib/services/livesync/livesync-service.ts +++ b/lib/services/livesync/livesync-service.ts @@ -3,24 +3,21 @@ import * as choki from "chokidar"; import { EOL } from "os"; import { EventEmitter } from "events"; import { hook } from "../../common/helpers"; -import { PACKAGE_JSON_FILE_NAME, LiveSyncTrackActionNames, USER_INTERACTION_NEEDED_EVENT_NAME, DEBUGGER_ATTACHED_EVENT_NAME, DEBUGGER_DETACHED_EVENT_NAME, TrackActionNames } from "../../constants"; +import { + PACKAGE_JSON_FILE_NAME, + LiveSyncTrackActionNames, + USER_INTERACTION_NEEDED_EVENT_NAME, + DEBUGGER_ATTACHED_EVENT_NAME, + DEBUGGER_DETACHED_EVENT_NAME, + TrackActionNames, + LiveSyncEvents +} from "../../constants"; import { DeviceTypes, DeviceDiscoveryEventNames, HmrConstants } from "../../common/constants"; import { cache } from "../../common/decorators"; -import { PreviewAppLiveSyncEvents } from "./playground/preview-app-constants"; import { performanceLog } from "../../common/decorators"; const deviceDescriptorPrimaryKey = "identifier"; -const LiveSyncEvents = { - liveSyncStopped: "liveSyncStopped", - // In case we name it error, EventEmitter expects instance of Error to be raised and will also raise uncaught exception in case there's no handler - liveSyncError: "liveSyncError", - previewAppLiveSyncError: PreviewAppLiveSyncEvents.PREVIEW_APP_LIVE_SYNC_ERROR, - liveSyncExecuted: "liveSyncExecuted", - liveSyncStarted: "liveSyncStarted", - liveSyncNotification: "notify" -}; - export class LiveSyncService extends EventEmitter implements IDebugLiveSyncService { // key is projectDir protected liveSyncProcessesInfo: IDictionary = {}; diff --git a/test/stubs.ts b/test/stubs.ts index 8ef40eb0e6..510b604b2b 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -656,7 +656,7 @@ export class DebugServiceStub extends EventEmitter implements IDeviceDebugServic public platform: string; } -export class LiveSyncServiceStub implements ILiveSyncService { +export class LiveSyncServiceStub extends EventEmitter implements ILiveSyncService { public async liveSyncToPreviewApp(data: IPreviewAppLiveSyncData): Promise { return; }