From 9f948a1361e3e4903f416fa80ed25e60c83ffcf1 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 21 Jan 2020 11:41:24 +0200 Subject: [PATCH] feat: improve detection of NativeScript plugins Currently in case you have multiple occurences of a NativeScript plugin in node_modules, most of the time the build of application fails. For iOS Xcode fails with duplicate resources (most commonly frameworks) and for Android the Static Binding Generator will fail in case the JavaScript of a plugin differs. Improve the handling by checking the versions of NativeScript plugins. In case the same version is installed multiple times, show warning to the user and link only one of the versions to the native build. In case multiple versions are detected, throw an error - currently we cannot support this case. --- lib/declarations.d.ts | 4 +- lib/definitions/plugins.d.ts | 3 +- lib/services/plugins-service.ts | 87 ++++- .../node-modules-dependencies-builder.ts | 4 +- test/plugins-service.ts | 330 +++++++++++++++++- test/stubs.ts | 5 +- .../node-modules-dependencies-builder.ts | 63 ++-- 7 files changed, 427 insertions(+), 69 deletions(-) diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index 7afd8d6e9b..d32c64800c 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -368,6 +368,8 @@ interface IDependencyData { * Dependencies of the current module. */ dependencies?: string[]; + + version: string; } interface INpmsResult { @@ -1071,4 +1073,4 @@ interface IWatchIgnoreListService { interface INpmConfigService { getConfig(): IDictionary; -} \ No newline at end of file +} diff --git a/lib/definitions/plugins.d.ts b/lib/definitions/plugins.d.ts index 3ab41f3a89..9cc8be5360 100644 --- a/lib/definitions/plugins.d.ts +++ b/lib/definitions/plugins.d.ts @@ -14,7 +14,6 @@ interface IPluginsService { */ getDependenciesFromPackageJson(projectDir: string): IPackageJsonDepedenciesResult; preparePluginNativeCode(preparePluginNativeCodeData: IPreparePluginNativeCodeData): Promise; - convertToPluginData(cacheData: any, projectDir: string): IPluginData; isNativeScriptPlugin(pluginPackageJsonPath: string): boolean; } @@ -44,7 +43,7 @@ interface IPluginData extends INodeModuleData { interface INodeModuleData extends IBasePluginData { fullPath: string; isPlugin: boolean; - moduleInfo: any; + nativescript: any; } interface IPluginPlatformsData { diff --git a/lib/services/plugins-service.ts b/lib/services/plugins-service.ts index 3b95776bd9..8c887a4740 100644 --- a/lib/services/plugins-service.ts +++ b/lib/services/plugins-service.ts @@ -9,6 +9,9 @@ export class PluginsService implements IPluginsService { private static NPM_CONFIG = { save: true }; + + private static LOCK_FILES = ["package-lock.json", "npm-shrinkwrap.json", "yarn.lock", "pnpm-lock.yaml"]; + private get $platformsDataService(): IPlatformsDataService { return this.$injector.resolve("platformsDataService"); } @@ -169,24 +172,17 @@ export class PluginsService implements IPluginsService { return _.filter(nodeModules, nodeModuleData => nodeModuleData && nodeModuleData.isPlugin); } - //This method will traverse all non dev dependencies (not only the root/installed ones) and filter the plugins. public getAllProductionPlugins(projectData: IProjectData, dependencies?: IDependencyData[]): IPluginData[] { - const allProductionPlugins: IPluginData[] = []; dependencies = dependencies || this.$nodeModulesDependenciesBuilder.getProductionDependencies(projectData.projectDir); if (_.isEmpty(dependencies)) { - return allProductionPlugins; + return []; } - _.forEach(dependencies, dependency => { - const isPlugin = !!dependency.nativescript; - if (isPlugin) { - const pluginData = this.convertToPluginData(dependency, projectData.projectDir); - allProductionPlugins.push(pluginData); - } - }); - - return allProductionPlugins; + let productionPlugins: IDependencyData[] = dependencies.filter(d => !!d.nativescript); + productionPlugins = this.ensureValidProductionPlugins(productionPlugins, projectData.projectDir); + const pluginData = productionPlugins.map(plugin => this.convertToPluginData(plugin, projectData.projectDir)); + return pluginData; } public getDependenciesFromPackageJson(projectDir: string): IPackageJsonDepedenciesResult { @@ -206,14 +202,71 @@ export class PluginsService implements IPluginsService { return pluginPackageJsonContent && pluginPackageJsonContent.nativescript; } - public convertToPluginData(cacheData: any, projectDir: string): IPluginData { + private ensureValidProductionPlugins = _.memoize<(productionDependencies: IDependencyData[], projectDir: string) => IDependencyData[]>(this._ensureValidProductionPlugins, (productionDependencies: IDependencyData[], projectDir: string) => { + let key = _.sortBy(productionDependencies, p => p.directory).map(d => JSON.stringify(d, null, 2)).join("\n"); + key += projectDir; + return key; + }); + + private _ensureValidProductionPlugins(productionDependencies: IDependencyData[], projectDir: string): IDependencyData[] { + const clonedProductionDependencies = _.cloneDeep(productionDependencies); + const dependenciesGroupedByName = _.groupBy(clonedProductionDependencies, p => p.name); + _.each(dependenciesGroupedByName, (dependencyOccurrences, dependencyName) => { + if (dependencyOccurrences.length > 1) { + // the dependency exists multiple times in node_modules + const dependencyOccurrencesGroupedByVersion = _.groupBy(dependencyOccurrences, g => g.version); + const versions = _.keys(dependencyOccurrencesGroupedByVersion); + if (versions.length === 1) { + // all dependencies with this name have the same version + this.$logger.warn(`Detected same versions (${_.first(versions)}) of the ${dependencyName} installed at locations: ${_.map(dependencyOccurrences, d => d.directory).join(", ")}`); + const selectedPackage = _.minBy(dependencyOccurrences, d => d.depth); + this.$logger.info(`CLI will use only the native code from '${selectedPackage.directory}'.`.green); + _.each(dependencyOccurrences, dependency => { + if (dependency !== selectedPackage) { + clonedProductionDependencies.splice(clonedProductionDependencies.indexOf(dependency), 1); + } + }); + } else { + const message = this.getFailureMessageForDifferentDependencyVersions(dependencyName, dependencyOccurrencesGroupedByVersion, projectDir); + this.$errors.fail(message); + } + } + }); + + return clonedProductionDependencies; + } + + private getFailureMessageForDifferentDependencyVersions(dependencyName: string, dependencyOccurrencesGroupedByVersion: IDictionary, projectDir: string): string { + let message = `Cannot use different versions of a NativeScript plugin in your application. +${dependencyName} plugin occurs multiple times in node_modules:\n`; + _.each(dependencyOccurrencesGroupedByVersion, (dependencies, version) => { + message += dependencies.map(d => `* Path: ${d.directory}, version: ${d.version}\n`); + }); + + const existingLockFiles: string[] = []; + PluginsService.LOCK_FILES.forEach(lockFile => { + if (this.$fs.exists(path.join(projectDir, lockFile))) { + existingLockFiles.push(lockFile); + } + }); + + let msgForLockFiles: string = ""; + if (existingLockFiles.length) { + msgForLockFiles += ` and ${existingLockFiles.join(", ")}`; + } + + message += `Probably you need to update your dependencies, remove node_modules${msgForLockFiles} and try again.`; + return message; + } + + private convertToPluginData(cacheData: IDependencyData | INodeModuleData, projectDir: string): IPluginData { const pluginData: any = {}; pluginData.name = cacheData.name; pluginData.version = cacheData.version; - pluginData.fullPath = cacheData.directory || path.dirname(this.getPackageJsonFilePathForModule(cacheData.name, projectDir)); - pluginData.isPlugin = !!cacheData.nativescript || !!cacheData.moduleInfo; + pluginData.fullPath = (cacheData).directory || path.dirname(this.getPackageJsonFilePathForModule(cacheData.name, projectDir)); + pluginData.isPlugin = !!cacheData.nativescript; pluginData.pluginPlatformsFolderPath = (platform: string) => path.join(pluginData.fullPath, "platforms", platform.toLowerCase()); - const data = cacheData.nativescript || cacheData.moduleInfo; + const data = cacheData.nativescript; if (pluginData.isPlugin) { pluginData.platformsData = data.platforms; @@ -280,7 +333,7 @@ export class PluginsService implements IPluginsService { version: data.version, fullPath: path.dirname(module), isPlugin: data.nativescript !== undefined, - moduleInfo: data.nativescript + nativescript: data.nativescript }; } diff --git a/lib/tools/node-modules/node-modules-dependencies-builder.ts b/lib/tools/node-modules/node-modules-dependencies-builder.ts index 53dd1bcfb1..6f05b60e38 100644 --- a/lib/tools/node-modules/node-modules-dependencies-builder.ts +++ b/lib/tools/node-modules/node-modules-dependencies-builder.ts @@ -93,7 +93,8 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB const dependency: IDependencyData = { name, directory, - depth + depth, + version: null }; const packageJsonPath = path.join(directory, PACKAGE_JSON_FILE_NAME); @@ -102,6 +103,7 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB if (packageJsonExists) { const packageJsonContents = this.$fs.readJson(packageJsonPath); + dependency.version = packageJsonContents.version; if (!!packageJsonContents.nativescript) { // add `nativescript` property, necessary for resolving plugins dependency.nativescript = packageJsonContents.nativescript; diff --git a/test/plugins-service.ts b/test/plugins-service.ts index fa15c86f45..a928ab0caa 100644 --- a/test/plugins-service.ts +++ b/test/plugins-service.ts @@ -37,10 +37,18 @@ import { PLUGINS_BUILD_DATA_FILENAME } from '../lib/constants'; import { GradleCommandService } from '../lib/services/android/gradle-command-service'; import { GradleBuildService } from '../lib/services/android/gradle-build-service'; import { GradleBuildArgsService } from '../lib/services/android/gradle-build-args-service'; +import * as util from "util"; temp.track(); let isErrorThrown = false; +interface ITestCase { + testName: string; + inputDependencies: any[]; + expectedOutput: any[] | Error; + expectedWarning?: string; +} + function createTestInjector() { const testInjector = new Yok(); testInjector.register("messagesService", MessagesService); @@ -571,23 +579,25 @@ describe("Plugins service", () => { }); }); - describe("convertToPluginData", () => { - const createUnitTestsInjector = () => { - const unitTestsInjector = new Yok(); - unitTestsInjector.register("platformsDataService", {}); - unitTestsInjector.register("filesHashService", {}); - unitTestsInjector.register("fs", {}); - unitTestsInjector.register("packageManager", {}); - unitTestsInjector.register("options", {}); - unitTestsInjector.register("logger", {}); - unitTestsInjector.register("errors", {}); - unitTestsInjector.register("injector", unitTestsInjector); - unitTestsInjector.register("mobileHelper", MobileHelper); - unitTestsInjector.register("devicePlatformsConstants", DevicePlatformsConstants); - unitTestsInjector.register("nodeModulesDependenciesBuilder", {}); - return unitTestsInjector; - }; + const createUnitTestsInjector = () => { + const unitTestsInjector = new Yok(); + unitTestsInjector.register("platformsDataService", {}); + unitTestsInjector.register("filesHashService", {}); + unitTestsInjector.register("fs", { + exists: (filePath: string) => false + }); + unitTestsInjector.register("packageManager", {}); + unitTestsInjector.register("options", {}); + unitTestsInjector.register("logger", stubs.LoggerStub); + unitTestsInjector.register("errors", stubs.ErrorsStub); + unitTestsInjector.register("injector", unitTestsInjector); + unitTestsInjector.register("mobileHelper", MobileHelper); + unitTestsInjector.register("devicePlatformsConstants", DevicePlatformsConstants); + unitTestsInjector.register("nodeModulesDependenciesBuilder", {}); + return unitTestsInjector; + }; + describe("convertToPluginData", () => { const pluginDir = "pluginDir"; const dataFromPluginPackageJson = { name: "name", @@ -604,7 +614,7 @@ describe("Plugins service", () => { it("returns correct pluginData", () => { const unitTestsInjector = createUnitTestsInjector(); const pluginsService: PluginsService = unitTestsInjector.resolve(PluginsService); - const pluginData = pluginsService.convertToPluginData(dataFromPluginPackageJson, "my project dir"); + const pluginData = (pluginsService).convertToPluginData(dataFromPluginPackageJson, "my project dir"); // Remove the comparison of a function delete pluginData["pluginPlatformsFolderPath"]; assert.deepEqual(pluginData, { @@ -620,7 +630,7 @@ describe("Plugins service", () => { it("always returns lowercased platform in the path to plugins dir", () => { const unitTestsInjector = createUnitTestsInjector(); const pluginsService: PluginsService = unitTestsInjector.resolve(PluginsService); - const pluginData = pluginsService.convertToPluginData(dataFromPluginPackageJson, "my project dir"); + const pluginData = (pluginsService).convertToPluginData(dataFromPluginPackageJson, "my project dir"); const expectediOSPath = path.join(pluginDir, "platforms", "ios"); const expectedAndroidPath = path.join(pluginDir, "platforms", "android"); @@ -633,4 +643,288 @@ describe("Plugins service", () => { assert.equal(pluginData.pluginPlatformsFolderPath("ANDROID"), expectedAndroidPath); }); }); + + describe("getAllProductionPlugins", () => { + const testCases: ITestCase[] = [ + { + testName: "returns empty array when none of the dependencies is nativescript plugin", + inputDependencies: [ + { + "name": "css-tree", + "directory": "/Users/username/projectDir/node_modules/css-tree", + "depth": 0, + "version": "1.0.0-alpha.39", + "dependencies": [ + "mdn-data", + "source-map" + ] + }, + { + "name": "nativescript-hook", + "directory": "/Users/username/projectDir/node_modules/nativescript-hook", + "depth": 0, + "version": "0.2.5", + "dependencies": [ + "glob", + "mkdirp" + ] + } + ], + expectedOutput: [] + }, + { + testName: "returns correct data when there's no duplication of plugins", + inputDependencies: [ + { + "name": "tns-core-modules", + "directory": "/Users/username/projectDir/node_modules/tns-core-modules", + "depth": 0, + "version": "6.3.2", + "nativescript": { + "platforms": { + "ios": "5.0.0", + "android": "5.0.0" + } + }, + "dependencies": [ + "@nativescript/core" + ] + }, + { + "name": "@nativescript/theme", + "directory": "/Users/username/projectDir/node_modules/@nativescript/theme", + "depth": 0, + "version": "2.2.1", + "nativescript": { + "platforms": { + "android": "6.2.0", + "ios": "6.2.0" + } + }, + "dependencies": [] + }, + ], + expectedOutput: [ + { + "fullPath": "/Users/username/projectDir/node_modules/tns-core-modules", + "isPlugin": true, + "name": "tns-core-modules", + "platformsData": { + "android": "5.0.0", + "ios": "5.0.0", + }, + "version": "6.3.2", + }, + { + "fullPath": "/Users/username/projectDir/node_modules/@nativescript/theme", + "isPlugin": true, + "name": "@nativescript/theme", + "platformsData": { + "android": "6.2.0", + "ios": "6.2.0", + }, + "version": "2.2.1", + } + ] + }, + { + testName: "prints warning when same version of plugin is installed multiple times", + inputDependencies: [ + { + "name": "nativescript-ui-listview", + "directory": "/Users/username/projectDir/node_modules/nativescript-ui-listview", + "depth": 0, + "version": "8.0.1", + "nativescript": { + "platforms": { + "android": "6.0.0", + "ios": "6.0.0" + } + }, + "dependencies": [ + "nativescript-ui-core" + ] + }, + { + "name": "nativescript-ui-core", + "directory": "/Users/username/projectDir/node_modules/nativescript-ui-core", + "depth": 0, + "version": "4.0.0", + "nativescript": { + "platforms": { + "android": "6.0.0", + "ios": "6.0.0" + } + }, + "dependencies": [] + }, + { + "name": "nativescript-ui-core", + "directory": "/Users/username/projectDir/node_modules/nativescript-ui-listview/node_modules/nativescript-ui-core", + "depth": 1, + "version": "4.0.0", + "nativescript": { + "platforms": { + "android": "6.0.0", + "ios": "6.0.0" + } + }, + "dependencies": [] + }, + ], + expectedOutput: [ + { + "fullPath": "/Users/username/projectDir/node_modules/nativescript-ui-listview", + "isPlugin": true, + "name": "nativescript-ui-listview", + "platformsData": { + "android": "6.0.0", + "ios": "6.0.0", + }, + "version": "8.0.1", + }, + { + "fullPath": "/Users/username/projectDir/node_modules/nativescript-ui-core", + "isPlugin": true, + "name": "nativescript-ui-core", + "platformsData": { + "android": "6.0.0", + "ios": "6.0.0", + }, + "version": "4.0.0", + } + ], + expectedWarning: "Detected same versions (4.0.0) of the nativescript-ui-core installed at locations: /Users/username/projectDir/node_modules/nativescript-ui-core, " + + "/Users/username/projectDir/node_modules/nativescript-ui-listview/node_modules/nativescript-ui-core" + }, + { + testName: "fails when different versions of the same plugin are detected", + inputDependencies: [ + { + "name": "nativescript-ui-listview", + "directory": "/Users/username/projectDir/node_modules/nativescript-ui-listview", + "depth": 0, + "version": "8.0.1", + "nativescript": { + "platforms": { + "android": "6.0.0", + "ios": "6.0.0" + } + }, + "dependencies": [ + "nativescript-ui-core" + ] + }, + { + "name": "nativescript-ui-core", + "directory": "/Users/username/projectDir/node_modules/nativescript-ui-core", + "depth": 0, + "version": "3.0.0", + "nativescript": { + "platforms": { + "android": "6.0.0", + "ios": "6.0.0" + } + }, + "dependencies": [] + }, + { + "name": "nativescript-ui-core", + "directory": "/Users/username/projectDir/node_modules/nativescript-ui-listview/node_modules/nativescript-ui-core", + "depth": 1, + "version": "4.0.0", + "nativescript": { + "platforms": { + "android": "6.0.0", + "ios": "6.0.0" + } + }, + "dependencies": [] + }, + ], + expectedOutput: new Error(`Cannot use different versions of a NativeScript plugin in your application. +nativescript-ui-core plugin occurs multiple times in node_modules:\n` + + "* Path: /Users/username/projectDir/node_modules/nativescript-ui-core, version: 3.0.0\n" + + "* Path: /Users/username/projectDir/node_modules/nativescript-ui-listview/node_modules/nativescript-ui-core, version: 4.0.0\n" + + `Probably you need to update your dependencies, remove node_modules and try again.`), + } + ]; + + for (const testCase of testCases) { + it(testCase.testName, () => { + const unitTestsInjector: IInjector = createUnitTestsInjector(); + const pluginsService: IPluginsService = unitTestsInjector.resolve(PluginsService); + + if (testCase.expectedOutput instanceof Error) { + assert.throws(() => pluginsService.getAllProductionPlugins({ projectDir: "projectDir" }, testCase.inputDependencies), testCase.expectedOutput.message); + } else { + const plugins = pluginsService.getAllProductionPlugins({ projectDir: "projectDir" }, testCase.inputDependencies); + + if (testCase.expectedWarning) { + const logger = unitTestsInjector.resolve("logger"); + assert.equal(testCase.expectedWarning + '\n', logger.warnOutput); + } + + for (const plugin of plugins) { + // deepEqual does not compare functions + delete plugin.pluginPlatformsFolderPath; + // pluginVariables is a legacy feature and out of the scope for current tests + delete plugin.pluginVariables; + } + + assert.deepEqual(plugins, testCase.expectedOutput); + } + }); + } + + it(`caches result based on dependencies`, () => { + const unitTestsInjector: IInjector = createUnitTestsInjector(); + const pluginsService: IPluginsService = unitTestsInjector.resolve(PluginsService); + const inputDependencies = [ + { + "name": "tns-core-modules", + "directory": "/Users/username/projectDir/node_modules/tns-core-modules", + "depth": 0, + "version": "6.3.0", + "nativescript": { + "platforms": { + "ios": "5.0.0", + "android": "5.0.0" + } + }, + "dependencies": [ + "@nativescript/core" + ] + }, + { + "name": "tns-core-modules", + "directory": "/Users/username/projectDir/node_modules/some-package/tns-core-modules", + "depth": 1, + "version": "6.3.0", + "nativescript": { + "platforms": { + "ios": "5.0.0", + "android": "5.0.0" + } + }, + "dependencies": [ + "@nativescript/core" + ] + }, + ]; + + _.range(3).forEach(() => { + pluginsService.getAllProductionPlugins({ projectDir: "projectDir" }, inputDependencies); + }); + + const logger = unitTestsInjector.resolve("logger"); + + const expectedWarnMessage = "Detected same versions (%s) of the tns-core-modules installed at locations: /Users/username/projectDir/node_modules/tns-core-modules, /Users/username/projectDir/node_modules/some-package/tns-core-modules\n"; + assert.equal(logger.warnOutput, util.format(expectedWarnMessage, "6.3.0"), "The warn message must be shown only once - the result of the private method must be cached as input dependencies have not changed"); + inputDependencies[0].version = "1.0.0"; + inputDependencies[1].version = "1.0.0"; + pluginsService.getAllProductionPlugins({ projectDir: "projectDir" }, inputDependencies); + assert.equal(logger.warnOutput, util.format(expectedWarnMessage, "6.3.0") + util.format(expectedWarnMessage, "1.0.0"), "When something in input dependencies change, the cached value shouldn't be taken into account"); + }); + }); }); diff --git a/test/stubs.ts b/test/stubs.ts index af3d18a719..9d287d3bd7 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -17,7 +17,9 @@ export class LoggerStub implements ILogger { getLevel(): string { return undefined; } fatal(...args: string[]): void { } error(...args: string[]): void { } - warn(...args: string[]): void { } + warn(...args: string[]): void { + this.warnOutput += util.format.apply(null, args) + "\n"; + } info(...args: string[]): void { this.output += util.format.apply(null, args) + "\n"; } @@ -29,6 +31,7 @@ export class LoggerStub implements ILogger { public output = ""; public traceOutput = ""; + public warnOutput = ""; prepare(item: any): string { return ""; diff --git a/test/tools/node-modules/node-modules-dependencies-builder.ts b/test/tools/node-modules/node-modules-dependencies-builder.ts index 0884817c87..7a59c7ad7a 100644 --- a/test/tools/node-modules/node-modules-dependencies-builder.ts +++ b/test/tools/node-modules/node-modules-dependencies-builder.ts @@ -59,13 +59,14 @@ describe("nodeModulesDependenciesBuilder", () => { return path.join(parentDir || pathToProject, constants.NODE_MODULES_FOLDER_NAME, dependencyName); }; - const getNodeModuleInfoForExpecteDependency = (dir: string, depth: number, nativescript?: any, dependencies?: string[], name?: string): IDependencyData => { + const getNodeModuleInfoForExpecteDependency = (dir: string, depth: number, nativescript?: any, dependencies?: string[], name?: string, version?: string): IDependencyData => { const packageName = name || path.basename(dir); const result: IDependencyData = { name: packageName, directory: getPathToDependencyInNodeModules(dir), depth, - dependencies: dependencies || [] + dependencies: dependencies || [], + version: version }; if (nativescript) { @@ -79,7 +80,7 @@ describe("nodeModulesDependenciesBuilder", () => { return path.join(getPathToDependencyInNodeModules(dependencyName, parentDir), constants.PACKAGE_JSON_FILE_NAME); }; - const getDependenciesObjectFromDependencyInfo = (depInfos: IDependencyInfo[], nativescript: any): { dependencies: IStringDictionary, nativescript?: any, devDependencies: IStringDictionary } => { + const getDependenciesObjectFromDependencyInfo = (depInfos: IDependencyInfo[], nativescript: any, version: string): { dependencies: IStringDictionary, nativescript?: any, devDependencies: IStringDictionary, version: string } => { const dependencies: any = {}; const devDepdencies: any = {}; _.each(depInfos, innerDependency => { @@ -99,6 +100,10 @@ describe("nodeModulesDependenciesBuilder", () => { result.nativescript = nativescript; } + if (version) { + result.version = version; + } + return result; }; @@ -107,7 +112,7 @@ describe("nodeModulesDependenciesBuilder", () => { for (const dependencyInfo of deps) { const pathToPackageJson = getPathToPackageJsonOfDependency(dependencyInfo.name, parentDir); if (filename === pathToPackageJson) { - return getDependenciesObjectFromDependencyInfo(dependencyInfo.dependencies, dependencyInfo.nativescript); + return getDependenciesObjectFromDependencyInfo(dependencyInfo.dependencies, dependencyInfo.nativescript, dependencyInfo.version); } if (dependencyInfo.dependencies) { @@ -128,7 +133,7 @@ describe("nodeModulesDependenciesBuilder", () => { fs.readJson = (filename: string, encoding?: string): any => { const innerDependency = getDependenciesObject(filename, rootDeps, pathToProject); - return innerDependency || getDependenciesObjectFromDependencyInfo(rootDeps, null); + return innerDependency || getDependenciesObjectFromDependencyInfo(rootDeps, null, null); }; const isDirectory = (searchedPath: string, currentRootPath: string, deps: IDependencyInfo[], currentDepthLevel: number): boolean => { @@ -221,8 +226,8 @@ describe("nodeModulesDependenciesBuilder", () => { const actualResult = await nodeModulesDependenciesBuilder.getProductionDependencies(pathToProject); const expectedResult: IDependencyData[] = [ - getNodeModuleInfoForExpecteDependency(firstPackage, 0), - getNodeModuleInfoForExpecteDependency(secondPackage, 0) + getNodeModuleInfoForExpecteDependency(firstPackage, 0, null, null, null, "1.0.0"), + getNodeModuleInfoForExpecteDependency(secondPackage, 0, null, null, null, "1.1.0") ]; assert.deepEqual(actualResult, expectedResult); @@ -241,7 +246,7 @@ describe("nodeModulesDependenciesBuilder", () => { ]; const expectedResult: IDependencyData[] = [ - getNodeModuleInfoForExpecteDependency(secondPackage, 0), + getNodeModuleInfoForExpecteDependency(secondPackage, 0, null, null, null, "1.1.0"), ]; const nodeModulesDependenciesBuilder = generateTest(rootDeps); @@ -264,9 +269,9 @@ describe("nodeModulesDependenciesBuilder", () => { ]; const expectedResult: IDependencyData[] = [ - getNodeModuleInfoForExpecteDependency(scopedPackageName, 0, null, [secondPackage], scopedPackageName), - getNodeModuleInfoForExpecteDependency(secondPackage, 0), - getNodeModuleInfoForExpecteDependency(path.join(scopedPackageName, constants.NODE_MODULES_FOLDER_NAME, secondPackage), 1) + getNodeModuleInfoForExpecteDependency(scopedPackageName, 0, null, [secondPackage], scopedPackageName, "1.0.0"), + getNodeModuleInfoForExpecteDependency(secondPackage, 0, null, null, null, "1.1.0"), + getNodeModuleInfoForExpecteDependency(path.join(scopedPackageName, constants.NODE_MODULES_FOLDER_NAME, secondPackage), 1, null, null, null, "1.2.0") ]; const nodeModulesDependenciesBuilder = generateTest(rootDeps); @@ -288,9 +293,9 @@ describe("nodeModulesDependenciesBuilder", () => { ]; const expectedResult: IDependencyData[] = [ - getNodeModuleInfoForExpecteDependency(firstPackage, 0, null, [scopedPackageName]), - getNodeModuleInfoForExpecteDependency(thirdPackage, 0), - getNodeModuleInfoForExpecteDependency(path.join(firstPackage, constants.NODE_MODULES_FOLDER_NAME, scopedPackageName), 1, null, null, scopedPackageName) + getNodeModuleInfoForExpecteDependency(firstPackage, 0, null, [scopedPackageName], null, "1.0.0"), + getNodeModuleInfoForExpecteDependency(thirdPackage, 0, null, null, null, "1.1.0"), + getNodeModuleInfoForExpecteDependency(path.join(firstPackage, constants.NODE_MODULES_FOLDER_NAME, scopedPackageName), 1, null, null, scopedPackageName, "1.2.0") ]; const nodeModulesDependenciesBuilder = generateTest(rootDeps); @@ -315,9 +320,9 @@ describe("nodeModulesDependenciesBuilder", () => { const actualResult = await nodeModulesDependenciesBuilder.getProductionDependencies(pathToProject); const expectedResult: IDependencyData[] = [ - getNodeModuleInfoForExpecteDependency(firstPackage, 0), - getNodeModuleInfoForExpecteDependency(secondPackage, 0), - getNodeModuleInfoForExpecteDependency(thirdPackage, 0) + getNodeModuleInfoForExpecteDependency(firstPackage, 0, null, null, null, "1.0.0"), + getNodeModuleInfoForExpecteDependency(secondPackage, 0, null, null, null, "1.1.0"), + getNodeModuleInfoForExpecteDependency(thirdPackage, 0, null, null, null, "1.2.0") ]; assert.deepEqual(actualResult, expectedResult); @@ -336,9 +341,9 @@ describe("nodeModulesDependenciesBuilder", () => { ]; const expectedResult: IDependencyData[] = [ - getNodeModuleInfoForExpecteDependency(firstPackage, 0, null, [secondPackage]), - getNodeModuleInfoForExpecteDependency(secondPackage, 0), - getNodeModuleInfoForExpecteDependency(path.join(firstPackage, constants.NODE_MODULES_FOLDER_NAME, secondPackage), 1) + getNodeModuleInfoForExpecteDependency(firstPackage, 0, null, [secondPackage], null, "1.0.0"), + getNodeModuleInfoForExpecteDependency(secondPackage, 0, null, null, null, "1.1.0"), + getNodeModuleInfoForExpecteDependency(path.join(firstPackage, constants.NODE_MODULES_FOLDER_NAME, secondPackage), 1, null, null, null, "1.2.0") ]; const nodeModulesDependenciesBuilder = generateTest(rootDeps); @@ -369,12 +374,12 @@ describe("nodeModulesDependenciesBuilder", () => { const pathToSecondPackageInsideFirstPackage = path.join(firstPackage, constants.NODE_MODULES_FOLDER_NAME, secondPackage); const expectedResult: IDependencyData[] = [ - getNodeModuleInfoForExpecteDependency(firstPackage, 0, null, [secondPackage, thirdPackage]), - getNodeModuleInfoForExpecteDependency(secondPackage, 0), - getNodeModuleInfoForExpecteDependency(thirdPackage, 0), - getNodeModuleInfoForExpecteDependency(pathToSecondPackageInsideFirstPackage, 1, null, [thirdPackage]), - getNodeModuleInfoForExpecteDependency(path.join(firstPackage, constants.NODE_MODULES_FOLDER_NAME, thirdPackage), 1), - getNodeModuleInfoForExpecteDependency(path.join(pathToSecondPackageInsideFirstPackage, constants.NODE_MODULES_FOLDER_NAME, thirdPackage), 2), + getNodeModuleInfoForExpecteDependency(firstPackage, 0, null, [secondPackage, thirdPackage], null, "1.0.0"), + getNodeModuleInfoForExpecteDependency(secondPackage, 0, null, null, null, "1.0.0"), + getNodeModuleInfoForExpecteDependency(thirdPackage, 0, null, null, null, "1.0.0"), + getNodeModuleInfoForExpecteDependency(pathToSecondPackageInsideFirstPackage, 1, null, [thirdPackage], null, "1.1.0"), + getNodeModuleInfoForExpecteDependency(path.join(firstPackage, constants.NODE_MODULES_FOLDER_NAME, thirdPackage), 1, null, null, null, "1.1.0"), + getNodeModuleInfoForExpecteDependency(path.join(pathToSecondPackageInsideFirstPackage, constants.NODE_MODULES_FOLDER_NAME, thirdPackage), 2, null, null, null, "1.2.0"), ]; const nodeModulesDependenciesBuilder = generateTest(rootDeps); @@ -410,9 +415,9 @@ describe("nodeModulesDependenciesBuilder", () => { const actualResult = await nodeModulesDependenciesBuilder.getProductionDependencies(pathToProject); const expectedResult: IDependencyData[] = [ - getNodeModuleInfoForExpecteDependency(firstPackage, 0, getNativeScriptDataForPlugin(firstPackage)), - getNodeModuleInfoForExpecteDependency(secondPackage, 0, getNativeScriptDataForPlugin(secondPackage)), - getNodeModuleInfoForExpecteDependency(thirdPackage, 0, getNativeScriptDataForPlugin(thirdPackage)) + getNodeModuleInfoForExpecteDependency(firstPackage, 0, getNativeScriptDataForPlugin(firstPackage), null, null, "1.0.0"), + getNodeModuleInfoForExpecteDependency(secondPackage, 0, getNativeScriptDataForPlugin(secondPackage), null, null, "1.1.0"), + getNodeModuleInfoForExpecteDependency(thirdPackage, 0, getNativeScriptDataForPlugin(thirdPackage), null, null, "1.2.0") ]; assert.deepEqual(actualResult, expectedResult);