nativescript 8.1.4 → 8.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,15 @@
1
1
  [
2
+ {
3
+ "name": "@jsdevtools/coverage-istanbul-loader"
4
+ },
2
5
  {
3
6
  "name": "karma"
4
7
  },
5
8
  {
6
- "name": "karma-nativescript-launcher"
9
+ "name": "karma-coverage"
7
10
  },
8
11
  {
9
- "name": "karma-webpack",
10
- "excludedPeerDependencies": ["webpack"]
12
+ "name": "karma-nativescript-launcher"
11
13
  },
12
14
  {
13
15
  "name": "mocha",
@@ -48,5 +50,8 @@
48
50
  "name": "@types/qunit",
49
51
  "framework": "qunit",
50
52
  "projectType": ".ts"
53
+ },
54
+ {
55
+ "name": "nyc"
51
56
  }
52
57
  ]
@@ -1 +1 @@
1
- {"karma":"6.3.4","karma-nativescript-launcher":"0.4.0","karma-webpack":"5.0.0","mocha":"9.1.2","karma-mocha":"2.0.1","karma-chai":"0.1.0","karma-jasmine":"4.0.1","karma-qunit":"4.1.2","@types/karma-chai":"0.1.2","@types/mocha":"9.0.0","@types/jasmine":"3.9.1","@types/qunit":"2.11.2"}
1
+ {"@jsdevtools/coverage-istanbul-loader":"3.0.5","karma":"6.3.9","karma-coverage":"2.0.3","karma-nativescript-launcher":"0.4.0","mocha":"9.1.3","karma-mocha":"2.0.1","karma-chai":"0.1.0","karma-jasmine":"4.0.1","karma-qunit":"4.1.2","@types/karma-chai":"0.1.2","@types/mocha":"9.0.0","@types/jasmine":"3.10.2","@types/qunit":"2.11.2","nyc":"15.1.0"}
package/lib/.d.ts CHANGED
@@ -217,6 +217,7 @@
217
217
  /// <reference path="common/test/unit-tests/project-files-provider-base.ts" />
218
218
  /// <reference path="common/test/unit-tests/services/files-hash-service.ts" />
219
219
  /// <reference path="common/test/unit-tests/services/help-service.ts" />
220
+ /// <reference path="common/test/unit-tests/services/hook-service.ts" />
220
221
  /// <reference path="common/test/unit-tests/services/json-file-settings-service.ts" />
221
222
  /// <reference path="common/test/unit-tests/services/net-service.ts" />
222
223
  /// <reference path="common/test/unit-tests/services/settings-service.ts" />
@@ -37,8 +37,13 @@ class CleanCommand {
37
37
  }
38
38
  catch (err) {
39
39
  }
40
- yield this.$projectCleanupService.clean(pathsToClean);
41
- spinner.succeed("Project successfully cleaned.");
40
+ const success = yield this.$projectCleanupService.clean(pathsToClean);
41
+ if (success) {
42
+ spinner.succeed("Project successfully cleaned.");
43
+ }
44
+ else {
45
+ spinner.fail(`${"Project unsuccessfully cleaned.".red}`);
46
+ }
42
47
  });
43
48
  }
44
49
  }
@@ -91,12 +91,19 @@ class TestInitCommand {
91
91
  }
92
92
  }
93
93
  yield this.$pluginsService.add("@nativescript/unit-test-runner", this.$projectData);
94
+ this.$logger.clearScreen();
95
+ const bufferedLogs = [];
94
96
  const testsDir = path.join(this.$projectData.appDirectoryPath, "tests");
95
97
  const projectTestsDir = path.relative(this.$projectData.projectDir, testsDir);
96
98
  const relativeTestsDir = path.relative(this.$projectData.appDirectoryPath, testsDir);
97
99
  let shouldCreateSampleTests = true;
98
100
  if (this.$fs.exists(testsDir)) {
99
- this.$logger.info(`${projectTestsDir} directory already exists, will not create an example test project.`);
101
+ const specFilenamePattern = `<filename>.spec${projectFilesExtension}`;
102
+ bufferedLogs.push([
103
+ `Note: The "${projectTestsDir}" directory already exists, will not create example tests in the project.`,
104
+ `You may create "${specFilenamePattern}" files anywhere you'd like.`,
105
+ "",
106
+ ].join("\n").yellow);
100
107
  shouldCreateSampleTests = false;
101
108
  }
102
109
  this.$fs.ensureDirectoryExists(testsDir);
@@ -113,14 +120,48 @@ class TestInitCommand {
113
120
  });
114
121
  this.$fs.writeFile(path.join(projectDir, "karma.conf.js"), karmaConf);
115
122
  const exampleFilePath = this.$resources.resolvePath(`test/example.${frameworkToInstall}${projectFilesExtension}`);
123
+ const targetExampleTestPath = path.join(testsDir, `example.spec${projectFilesExtension}`);
116
124
  if (shouldCreateSampleTests && this.$fs.exists(exampleFilePath)) {
117
- this.$fs.copyFile(exampleFilePath, path.join(testsDir, `example${projectFilesExtension}`));
118
- this.$logger.info(`\nExample test file created in ${projectTestsDir}`.yellow);
125
+ this.$fs.copyFile(exampleFilePath, targetExampleTestPath);
126
+ const targetExampleTestRelativePath = path.relative(projectDir, targetExampleTestPath);
127
+ bufferedLogs.push(`Added example test: ${targetExampleTestRelativePath.yellow}`);
119
128
  }
120
- else {
121
- this.$logger.info(`\nPlace your test files under ${projectTestsDir}`.yellow);
129
+ const testMainResourcesPath = this.$resources.resolvePath(`test/test-main${projectFilesExtension}`);
130
+ const testMainPath = path.join(this.$projectData.appDirectoryPath, `test${projectFilesExtension}`);
131
+ if (!this.$fs.exists(testMainPath)) {
132
+ this.$fs.copyFile(testMainResourcesPath, testMainPath);
133
+ const testMainRelativePath = path.relative(projectDir, testMainPath);
134
+ bufferedLogs.push(`Main test entrypoint created: ${testMainRelativePath.yellow}`);
122
135
  }
123
- this.$logger.info('Run your tests using the "$ ns test <platform>" command.'.yellow);
136
+ const testTsConfigTemplate = this.$resources.readText("test/tsconfig.spec.json");
137
+ const testTsConfig = _.template(testTsConfigTemplate)({
138
+ basePath: this.$projectData.getAppDirectoryRelativePath(),
139
+ });
140
+ this.$fs.writeFile(path.join(projectDir, "tsconfig.spec.json"), testTsConfig);
141
+ bufferedLogs.push(`Added/replaced ${"tsconfig.spec.json".yellow}`);
142
+ const greyDollarSign = "$".grey;
143
+ this.$logger.info([
144
+ [
145
+ `Tests using`.green,
146
+ frameworkToInstall.cyan,
147
+ `were successfully initialized.`.green,
148
+ ].join(" "),
149
+ "",
150
+ ...bufferedLogs,
151
+ "",
152
+ `Note: @nativescript/unit-test-runner was included in "dependencies" as a convenience to automatically adjust your app's Info.plist on iOS and AndroidManifest.xml on Android to ensure the socket connects properly.`
153
+ .yellow,
154
+ "",
155
+ `For production you may want to move to "devDependencies" and manage the settings yourself.`
156
+ .yellow,
157
+ "",
158
+ "",
159
+ `You can now run your tests:`,
160
+ "",
161
+ ` ${greyDollarSign} ${"ns test ios".green}`,
162
+ ` ${greyDollarSign} ${"ns test android".green}`,
163
+ "",
164
+ ].join("\n"));
124
165
  });
125
166
  }
126
167
  }
@@ -91,6 +91,9 @@ class CommandDispatcher {
91
91
  printVersion() {
92
92
  return __awaiter(this, void 0, void 0, function* () {
93
93
  this.$logger.info(this.$staticConfig.version);
94
+ if (this.$options.json) {
95
+ return;
96
+ }
94
97
  const spinner = this.$terminalSpinnerService.createSpinner();
95
98
  spinner.start("Checking for updates...");
96
99
  const nativescriptCliVersion = yield this.$versionsService.getNativescriptCliVersion();
@@ -23,7 +23,7 @@ class Hook {
23
23
  }
24
24
  }
25
25
  class HooksService {
26
- constructor($childProcess, $fs, $logger, $errors, $config, $staticConfig, $injector, $projectHelper, $options, $performanceService) {
26
+ constructor($childProcess, $fs, $logger, $errors, $config, $staticConfig, $injector, $projectHelper, $options, $performanceService, $projectConfigService) {
27
27
  this.$childProcess = $childProcess;
28
28
  this.$fs = $fs;
29
29
  this.$logger = $logger;
@@ -34,6 +34,7 @@ class HooksService {
34
34
  this.$projectHelper = $projectHelper;
35
35
  this.$options = $options;
36
36
  this.$performanceService = $performanceService;
37
+ this.$projectConfigService = $projectConfigService;
37
38
  }
38
39
  get hookArgsName() {
39
40
  return "hookArgs";
@@ -46,6 +47,10 @@ class HooksService {
46
47
  this.hooksDirectories.push(path.join(projectDir, HooksService.HOOKS_DIRECTORY_NAME));
47
48
  }
48
49
  this.$logger.trace("Hooks directories: " + util.inspect(this.hooksDirectories));
50
+ const customHooks = this.$projectConfigService.getValue("hooks", []);
51
+ if (customHooks.length) {
52
+ this.$logger.trace("Custom hooks: " + util.inspect(customHooks));
53
+ }
49
54
  }
50
55
  static formatHookName(commandName) {
51
56
  return commandName.replace(/\|[\s\S]*$/, "");
@@ -79,6 +84,10 @@ class HooksService {
79
84
  for (const hooksDirectory of this.hooksDirectories) {
80
85
  results.push(yield this.executeHooksInDirectory(hooksDirectory, hookName, hookArguments));
81
86
  }
87
+ const customHooks = this.getCustomHooksByName(hookName);
88
+ for (const hook of customHooks) {
89
+ results.push(yield this.executeHook(this.$projectHelper.projectDir, hookName, hook, hookArguments));
90
+ }
82
91
  }
83
92
  catch (err) {
84
93
  this.$logger.trace(`Failed during hook execution ${hookName}.`);
@@ -87,75 +96,102 @@ class HooksService {
87
96
  return _.flatten(results);
88
97
  });
89
98
  }
90
- executeHooksInDirectory(directoryPath, hookName, hookArguments) {
99
+ executeHook(directoryPath, hookName, hook, hookArguments) {
91
100
  return __awaiter(this, void 0, void 0, function* () {
92
101
  hookArguments = hookArguments || {};
93
- const results = [];
94
- const hooks = this.getHooksByName(directoryPath, hookName);
95
- for (let i = 0; i < hooks.length; ++i) {
96
- const hook = hooks[i];
97
- const relativePath = path.relative(directoryPath, hook.fullPath);
98
- const trackId = relativePath.replace(new RegExp("\\" + path.sep, "g"), constants_1.AnalyticsEventLabelDelimiter);
99
- let command = this.getSheBangInterpreter(hook);
100
- let inProc = false;
101
- if (!command) {
102
- command = hook.fullPath;
103
- if (path.extname(hook.fullPath).toLowerCase() === ".js") {
104
- command = process.argv[0];
105
- inProc = this.shouldExecuteInProcess(this.$fs.readText(hook.fullPath));
106
- }
102
+ let result;
103
+ const relativePath = path.relative(directoryPath, hook.fullPath);
104
+ const trackId = relativePath.replace(new RegExp("\\" + path.sep, "g"), constants_1.AnalyticsEventLabelDelimiter);
105
+ let command = this.getSheBangInterpreter(hook);
106
+ let inProc = false;
107
+ if (!command) {
108
+ command = hook.fullPath;
109
+ if (path.extname(hook.fullPath).toLowerCase() === ".js") {
110
+ command = process.argv[0];
111
+ inProc = this.shouldExecuteInProcess(this.$fs.readText(hook.fullPath));
107
112
  }
108
- const startTime = this.$performanceService.now();
109
- if (inProc) {
110
- this.$logger.trace("Executing %s hook at location %s in-process", hookName, hook.fullPath);
111
- const hookEntryPoint = require(hook.fullPath);
112
- this.$logger.trace(`Validating ${hookName} arguments.`);
113
- const invalidArguments = this.validateHookArguments(hookEntryPoint, hook.fullPath);
114
- if (invalidArguments.length) {
115
- this.$logger.warn(`${hook.fullPath} will NOT be executed because it has invalid arguments - ${invalidArguments.join(", ").grey}.`);
116
- continue;
117
- }
118
- const projectDataHookArg = hookArguments["hookArgs"] && hookArguments["hookArgs"]["projectData"];
119
- if (projectDataHookArg) {
120
- hookArguments["projectData"] = hookArguments["$projectData"] = projectDataHookArg;
113
+ }
114
+ const startTime = this.$performanceService.now();
115
+ if (inProc) {
116
+ this.$logger.trace("Executing %s hook at location %s in-process", hookName, hook.fullPath);
117
+ const hookEntryPoint = require(hook.fullPath);
118
+ this.$logger.trace(`Validating ${hookName} arguments.`);
119
+ const invalidArguments = this.validateHookArguments(hookEntryPoint, hook.fullPath);
120
+ if (invalidArguments.length) {
121
+ this.$logger.warn(`${hook.fullPath} will NOT be executed because it has invalid arguments - ${invalidArguments.join(", ").grey}.`);
122
+ return;
123
+ }
124
+ const projectDataHookArg = hookArguments["hookArgs"] && hookArguments["hookArgs"]["projectData"];
125
+ if (projectDataHookArg) {
126
+ hookArguments["projectData"] = hookArguments["$projectData"] = projectDataHookArg;
127
+ }
128
+ const maybePromise = this.$injector.resolve(hookEntryPoint, hookArguments);
129
+ if (maybePromise) {
130
+ this.$logger.trace("Hook promises to signal completion");
131
+ try {
132
+ result = yield maybePromise;
121
133
  }
122
- const maybePromise = this.$injector.resolve(hookEntryPoint, hookArguments);
123
- if (maybePromise) {
124
- this.$logger.trace("Hook promises to signal completion");
125
- try {
126
- const result = yield maybePromise;
127
- results.push(result);
134
+ catch (err) {
135
+ if (err &&
136
+ _.isBoolean(err.stopExecution) &&
137
+ err.errorAsWarning === true) {
138
+ this.$logger.warn(err.message || err);
128
139
  }
129
- catch (err) {
130
- if (err &&
131
- _.isBoolean(err.stopExecution) &&
132
- err.errorAsWarning === true) {
133
- this.$logger.warn(err.message || err);
134
- }
135
- else {
136
- this.$logger.error(err);
137
- throw (err || new Error(`Failed to execute hook: ${hook.fullPath}.`));
138
- }
140
+ else {
141
+ this.$logger.error(err);
142
+ throw err || new Error(`Failed to execute hook: ${hook.fullPath}.`);
139
143
  }
140
- this.$logger.trace("Hook completed");
141
144
  }
145
+ this.$logger.trace("Hook completed");
142
146
  }
143
- else {
144
- const environment = this.prepareEnvironment(hook.fullPath);
145
- this.$logger.trace("Executing %s hook at location %s with environment ", hookName, hook.fullPath, environment);
146
- const output = yield this.$childProcess.spawnFromEvent(command, [hook.fullPath], "close", environment, { throwError: false });
147
- results.push(output);
148
- if (output.exitCode !== 0) {
149
- throw new Error(output.stdout + output.stderr);
150
- }
151
- this.$logger.trace("Finished executing %s hook at location %s with environment ", hookName, hook.fullPath, environment);
147
+ }
148
+ else {
149
+ const environment = this.prepareEnvironment(hook.fullPath);
150
+ this.$logger.trace("Executing %s hook at location %s with environment ", hookName, hook.fullPath, environment);
151
+ const output = yield this.$childProcess.spawnFromEvent(command, [hook.fullPath], "close", environment, { throwError: false });
152
+ result = output;
153
+ if (output.exitCode !== 0) {
154
+ throw new Error(output.stdout + output.stderr);
155
+ }
156
+ this.$logger.trace("Finished executing %s hook at location %s with environment ", hookName, hook.fullPath, environment);
157
+ }
158
+ const endTime = this.$performanceService.now();
159
+ this.$performanceService.processExecutionData(trackId, startTime, endTime, [
160
+ hookArguments,
161
+ ]);
162
+ return result;
163
+ });
164
+ }
165
+ executeHooksInDirectory(directoryPath, hookName, hookArguments) {
166
+ return __awaiter(this, void 0, void 0, function* () {
167
+ hookArguments = hookArguments || {};
168
+ const results = [];
169
+ const hooks = this.getHooksByName(directoryPath, hookName);
170
+ for (let i = 0; i < hooks.length; ++i) {
171
+ const hook = hooks[i];
172
+ const result = yield this.executeHook(directoryPath, hookName, hook, hookArguments);
173
+ if (result) {
174
+ results.push(result);
152
175
  }
153
- const endTime = this.$performanceService.now();
154
- this.$performanceService.processExecutionData(trackId, startTime, endTime, [hookArguments]);
155
176
  }
156
177
  return results;
157
178
  });
158
179
  }
180
+ getCustomHooksByName(hookName) {
181
+ const hooks = [];
182
+ const customHooks = this.$projectConfigService.getValue("hooks", []);
183
+ for (const cHook of customHooks) {
184
+ if (cHook.type === hookName) {
185
+ const fullPath = path.join(this.$projectHelper.projectDir, cHook.script);
186
+ const isFile = this.$fs.getFsStats(fullPath).isFile();
187
+ if (isFile) {
188
+ const fileNameParts = cHook.script.split("/");
189
+ hooks.push(new Hook(this.getBaseFilename(fileNameParts[fileNameParts.length - 1]), fullPath));
190
+ }
191
+ }
192
+ }
193
+ return hooks;
194
+ }
159
195
  getHooksByName(directoryPath, hookName) {
160
196
  const allBaseHooks = this.getHooksInDirectory(directoryPath);
161
197
  const baseHooks = _.filter(allBaseHooks, (hook) => hook.name.toLowerCase() === hookName.toLowerCase());
@@ -19,6 +19,7 @@ const simple_git_1 = require("simple-git");
19
19
  const update_controller_base_1 = require("./update-controller-base");
20
20
  const helpers_1 = require("../common/helpers");
21
21
  const yok_1 = require("../common/yok");
22
+ const temp = require("temp");
22
23
  class MigrateController extends update_controller_base_1.UpdateControllerBase {
23
24
  constructor($fs, $platformCommandHelper, $platformsDataService, $packageInstallationManager, $packageManager, $pacoteService, $logger, $errors, $pluginsService, $projectDataService, $projectConfigService, $options, $resources, $injector, $settingsService, $staticConfig, $terminalSpinnerService, $projectCleanupService, $projectBackupService, $childProcess) {
24
25
  super($fs, $platformCommandHelper, $platformsDataService, $packageInstallationManager, $packageManager, $pacoteService);
@@ -150,7 +151,7 @@ class MigrateController extends update_controller_base_1.UpdateControllerBase {
150
151
  {
151
152
  packageName: "@nativescript/unit-test-runner",
152
153
  minVersion: "1.0.0",
153
- desiredVersion: "~2.0.5",
154
+ desiredVersion: "~3.0.0",
154
155
  shouldMigrateAction(dependency, projectData, loose) {
155
156
  return __awaiter(this, void 0, void 0, function* () {
156
157
  if (!this.hasDependency(dependency, projectData)) {
@@ -289,10 +290,21 @@ class MigrateController extends update_controller_base_1.UpdateControllerBase {
289
290
  this.spinner.info("Updating project dependencies");
290
291
  yield this.migrateDependencies(projectData, platforms, loose);
291
292
  this.spinner.succeed("Project dependencies have been updated");
293
+ const isAngular = this.hasDependency({
294
+ packageName: "@nativescript/angular",
295
+ }, projectData);
296
+ let polyfillsPath;
297
+ if (isAngular) {
298
+ polyfillsPath = yield this.checkOrCreatePolyfillsTS(projectData);
299
+ }
292
300
  const tsConfigPath = path.resolve(projectDir, "tsconfig.json");
293
301
  if (this.$fs.exists(tsConfigPath)) {
294
302
  this.spinner.info(`Updating ${"tsconfig.json".yellow}`);
295
- yield this.migrateTSConfig(tsConfigPath);
303
+ yield this.migrateTSConfig({
304
+ tsConfigPath,
305
+ isAngular,
306
+ polyfillsPath,
307
+ });
296
308
  this.spinner.succeed(`Updated ${"tsconfig.json".yellow}`);
297
309
  }
298
310
  yield this.migrateWebpack5(projectDir, projectData);
@@ -673,10 +685,7 @@ class MigrateController extends update_controller_base_1.UpdateControllerBase {
673
685
  const dependencies = [
674
686
  {
675
687
  packageName: "karma-webpack",
676
- minVersion: "3.0.5",
677
- desiredVersion: "~5.0.0",
678
- isDev: true,
679
- shouldAddIfMissing: true,
688
+ shouldRemove: true,
680
689
  },
681
690
  {
682
691
  packageName: "karma-jasmine",
@@ -712,7 +721,7 @@ class MigrateController extends update_controller_base_1.UpdateControllerBase {
712
721
  return dependencies;
713
722
  });
714
723
  }
715
- migrateTSConfig(tsConfigPath) {
724
+ migrateTSConfig({ tsConfigPath, isAngular, polyfillsPath, }) {
716
725
  return __awaiter(this, void 0, void 0, function* () {
717
726
  try {
718
727
  const configContents = this.$fs.readJson(tsConfigPath);
@@ -725,6 +734,16 @@ class MigrateController extends update_controller_base_1.UpdateControllerBase {
725
734
  configContents.compilerOptions.lib = [
726
735
  ...new Set([...(configContents.compilerOptions.lib || []), "es2017"]),
727
736
  ];
737
+ if (isAngular) {
738
+ if (configContents.files) {
739
+ configContents.files = [
740
+ ...new Set([
741
+ ...(configContents.files || []),
742
+ polyfillsPath !== null && polyfillsPath !== void 0 ? polyfillsPath : "./src/polyfills.ts",
743
+ ]),
744
+ ];
745
+ }
746
+ }
728
747
  this.$fs.writeJson(tsConfigPath, configContents);
729
748
  return true;
730
749
  }
@@ -734,6 +753,30 @@ class MigrateController extends update_controller_base_1.UpdateControllerBase {
734
753
  }
735
754
  });
736
755
  }
756
+ checkOrCreatePolyfillsTS(projectData) {
757
+ return __awaiter(this, void 0, void 0, function* () {
758
+ const { projectDir, appDirectoryPath } = projectData;
759
+ const possiblePaths = [
760
+ `${appDirectoryPath}/polyfills.ts`,
761
+ `./src/polyfills.ts`,
762
+ `./app/polyfills.ts`,
763
+ ].map((possiblePath) => path.resolve(projectDir, possiblePath));
764
+ let polyfillsPath = possiblePaths.find((possiblePath) => {
765
+ return this.$fs.exists(possiblePath);
766
+ });
767
+ if (polyfillsPath) {
768
+ return "./" + path.relative(projectDir, polyfillsPath);
769
+ }
770
+ const tempDir = temp.mkdirSync({
771
+ prefix: "migrate-angular-polyfills",
772
+ });
773
+ yield this.$pacoteService.extractPackage(constants.RESERVED_TEMPLATE_NAMES["angular"], tempDir);
774
+ this.$fs.copyFile(path.resolve(tempDir, "src/polyfills.ts"), possiblePaths[0]);
775
+ this.$fs.deleteDirectory(tempDir);
776
+ this.spinner.succeed(`Created fresh ${"polyfills.ts".cyan}`);
777
+ return "./" + path.relative(projectDir, possiblePaths[0]);
778
+ });
779
+ }
737
780
  migrateNativeScriptAngular() {
738
781
  return __awaiter(this, void 0, void 0, function* () {
739
782
  const minVersion = "10.0.0";
@@ -799,6 +842,12 @@ class MigrateController extends update_controller_base_1.UpdateControllerBase {
799
842
  desiredVersion: "~0.11.4",
800
843
  shouldAddIfMissing: true,
801
844
  },
845
+ {
846
+ packageName: "@angular/cli",
847
+ minVersion,
848
+ desiredVersion,
849
+ isDev: true,
850
+ },
802
851
  {
803
852
  packageName: "@angular/compiler-cli",
804
853
  minVersion,
@@ -134,6 +134,11 @@ interface INsConfigAndroid extends INsConfigPlaform {
134
134
  enableMultithreadedJavascript?: boolean;
135
135
  }
136
136
 
137
+ interface INsConfigHooks {
138
+ type?: string;
139
+ script: string;
140
+ }
141
+
137
142
  interface INsConfig {
138
143
  id?: string;
139
144
  main?: string;
@@ -146,6 +151,7 @@ interface INsConfig {
146
151
  ios?: INsConfigIOS;
147
152
  android?: INsConfigAndroid;
148
153
  ignoredNativeDependencies?: string[];
154
+ hooks?: INsConfigHooks[];
149
155
  }
150
156
 
151
157
  interface IProjectData extends ICreateProjectData {
@@ -302,13 +308,13 @@ interface IProjectCleanupService {
302
308
  * Clean multiple paths
303
309
  * @param {string[]} pathsToClean
304
310
  */
305
- clean(pathsToClean: string[]): Promise<void>;
311
+ clean(pathsToClean: string[]): Promise<boolean>;
306
312
 
307
313
  /**
308
314
  * Clean a single path
309
315
  * @param {string} pathToClean
310
316
  */
311
- cleanPath(pathToClean: string): Promise<void>;
317
+ cleanPath(pathToClean: string): Promise<boolean>;
312
318
  }
313
319
 
314
320
  interface IBackup {
@@ -346,7 +352,7 @@ interface IProjectConfigService {
346
352
  * Get value for a given config key path
347
353
  * @param key the property key path
348
354
  */
349
- getValue(key: string): any;
355
+ getValue(key: string, defaultValue?: any): any;
350
356
  /**
351
357
  * Set value for a given config key path
352
358
  * @param key the property key path
@@ -21,7 +21,7 @@ const decorators_2 = require("./common/decorators");
21
21
  const constants_1 = require("./constants");
22
22
  const yok_1 = require("./common/yok");
23
23
  class PackageManager {
24
- constructor($errors, $npm, $options, $yarn, $pnpm, $logger, $userSettingsService) {
24
+ constructor($errors, $npm, $options, $yarn, $pnpm, $logger, $userSettingsService, $projectConfigService) {
25
25
  this.$errors = $errors;
26
26
  this.$npm = $npm;
27
27
  this.$options = $options;
@@ -29,6 +29,7 @@ class PackageManager {
29
29
  this.$pnpm = $pnpm;
30
30
  this.$logger = $logger;
31
31
  this.$userSettingsService = $userSettingsService;
32
+ this.$projectConfigService = $projectConfigService;
32
33
  }
33
34
  init() {
34
35
  return __awaiter(this, void 0, void 0, function* () {
@@ -103,6 +104,16 @@ class PackageManager {
103
104
  catch (err) {
104
105
  this.$errors.fail(`Unable to read package manager config from user settings ${err}`);
105
106
  }
107
+ try {
108
+ const configPm = this.$projectConfigService.getValue("cli.packageManager");
109
+ if (configPm) {
110
+ this.$logger.trace(`Determined packageManager to use from user config is: ${configPm}`);
111
+ pm = configPm;
112
+ }
113
+ }
114
+ catch (err) {
115
+ this.$logger.trace("Tried to read cli.packageManager from project config and failed. Error is: ", err);
116
+ }
106
117
  if (pm === constants_1.PackageManagers.yarn || this.$options.yarn) {
107
118
  this._packageManagerName = constants_1.PackageManagers.yarn;
108
119
  return this.$yarn;
@@ -22,19 +22,25 @@ class ProjectCleanupService {
22
22
  }
23
23
  clean(pathsToClean) {
24
24
  return __awaiter(this, void 0, void 0, function* () {
25
+ let success = true;
25
26
  for (const pathToClean of pathsToClean) {
26
- yield this.cleanPath(pathToClean).catch((error) => {
27
+ const isCleaned = yield this.cleanPath(pathToClean).catch((error) => {
27
28
  this.$logger.trace(`Encountered error while cleaning. Error is: ${error.message}.`, error);
29
+ return false;
28
30
  });
31
+ success = success && isCleaned;
29
32
  }
33
+ return success;
30
34
  });
31
35
  }
32
36
  cleanPath(pathToClean) {
33
37
  return __awaiter(this, void 0, void 0, function* () {
34
38
  this.spinner.clear();
39
+ let success = true;
40
+ let fileType;
35
41
  if (!pathToClean || pathToClean.trim().length === 0) {
36
42
  this.$logger.trace("cleanPath called with no pathToClean.");
37
- return;
43
+ return success;
38
44
  }
39
45
  const filePath = path.resolve(this.$projectHelper.projectDir, pathToClean);
40
46
  const displayPath = `${path.relative(this.$projectHelper.projectDir, filePath)}`.yellow;
@@ -44,16 +50,25 @@ class ProjectCleanupService {
44
50
  if (stat.isDirectory()) {
45
51
  this.$logger.trace(`Path '${filePath}' is a directory, deleting.`);
46
52
  this.$fs.deleteDirectorySafe(filePath);
47
- this.spinner.succeed(`Cleaned directory ${displayPath}`);
53
+ fileType = "directory";
48
54
  }
49
55
  else {
50
56
  this.$logger.trace(`Path '${filePath}' is a file, deleting.`);
51
57
  this.$fs.deleteFile(filePath);
52
- this.spinner.succeed(`Cleaned file ${displayPath}`);
58
+ fileType = "file";
53
59
  }
54
- return;
60
+ success = !this.$fs.exists(filePath);
61
+ if (success) {
62
+ this.spinner.succeed(`Cleaned ${fileType} ${displayPath}`);
63
+ }
64
+ else {
65
+ const message = `Failed to Clean ${fileType}`.red;
66
+ this.spinner.fail(`${message} ${displayPath}`);
67
+ }
68
+ return success;
55
69
  }
56
70
  this.$logger.trace(`Path '${filePath}' not found, skipping.`);
71
+ return success;
57
72
  });
58
73
  }
59
74
  }
@@ -92,7 +92,11 @@ export default {
92
92
  .filter(Boolean)
93
93
  .map((c) => {
94
94
  if (this.$fs.isRelativePath(c)) {
95
- return path.join(projectDir || this.projectHelper.projectDir, c);
95
+ const dir = projectDir || this.projectHelper.projectDir;
96
+ if (!dir) {
97
+ return c;
98
+ }
99
+ return path.join(dir, c);
96
100
  }
97
101
  return c;
98
102
  });
@@ -120,6 +120,7 @@ class TestExecutionService {
120
120
  path: this.$options.path,
121
121
  tns: process.argv[1],
122
122
  node: process.execPath,
123
+ env: this.$options.env,
123
124
  options: {
124
125
  debugTransport: this.$options.debugTransport,
125
126
  debugBrk: this.$options.debugBrk,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nativescript",
3
3
  "preferGlobal": true,
4
- "version": "8.1.4",
4
+ "version": "8.1.5",
5
5
  "author": "NativeScript <support@nativescript.org>",
6
6
  "description": "Command-line interface for building NativeScript projects",
7
7
  "bin": {
@@ -1,4 +1,3 @@
1
- const filePatterns = [${ testFiles }];
2
1
  module.exports = function (config) {
3
2
  const options = {
4
3
 
@@ -11,8 +10,8 @@ module.exports = function (config) {
11
10
  frameworks: [${ frameworks }],
12
11
 
13
12
 
14
- // list of files / patterns to load in the browser
15
- files: filePatterns,
13
+ // list of files / patterns to load in the browser. Leave empty for webpack projects
14
+ // files: [],
16
15
 
17
16
 
18
17
  // list of files to exclude
@@ -31,6 +30,16 @@ module.exports = function (config) {
31
30
  // available reporters: https://npmjs.org/browse/keyword/karma-reporter
32
31
  reporters: ['progress'],
33
32
 
33
+ // configure optional coverage, enable via --env.codeCoverage
34
+ coverageReporter: {
35
+ dir: require('path').join(__dirname, './coverage'),
36
+ subdir: '.',
37
+ reporters: [
38
+ { type: 'html' },
39
+ { type: 'text-summary' }
40
+ ]
41
+ },
42
+
34
43
 
35
44
  // web server port
36
45
  port: 9876,
@@ -74,41 +83,9 @@ module.exports = function (config) {
74
83
  singleRun: false
75
84
  };
76
85
 
77
- setWebpackPreprocessor(config, options);
78
- setWebpack(config, options);
79
-
80
- config.set(options);
81
- }
82
- module.exports.filePatterns = filePatterns;
83
- // You can also use RegEx if you'd like:
84
- // module.exports.filesRegex = /\.\/tests\/.*\.ts$/;
85
-
86
- function setWebpackPreprocessor(config, options) {
87
- if (config && config.bundle) {
88
- if (!options.preprocessors) {
89
- options.preprocessors = {};
90
- }
91
-
92
- options.files.forEach(file => {
93
- if (!options.preprocessors[file]) {
94
- options.preprocessors[file] = [];
95
- }
96
- options.preprocessors[file].push('webpack');
97
- });
86
+ if(config._NS && config._NS.env && config._NS.env.codeCoverage) {
87
+ options.reporters = (options.reporters || []).concat(['coverage']);
98
88
  }
99
- }
100
89
 
101
- function setWebpack(config, options) {
102
- if (config && config.bundle) {
103
- const env = {};
104
- env[config.platform] = true;
105
- env.sourceMap = config.debugBrk;
106
- env.appPath = config.appPath;
107
- env.karmaWebpack = true;
108
- options.webpack = require('./webpack.config')(env);
109
- delete options.webpack.entry;
110
- delete options.webpack.output.libraryTarget;
111
- const invalidPluginsForUnitTesting = ["GenerateBundleStarterPlugin", "GenerateNativeScriptEntryPointsPlugin"];
112
- options.webpack.plugins = options.webpack.plugins.filter(p => !invalidPluginsForUnitTesting.includes(p.constructor.name));
113
- }
90
+ config.set(options);
114
91
  }
@@ -0,0 +1,9 @@
1
+ import { runTestApp } from "@nativescript/unit-test-runner";
2
+ // import other polyfills here
3
+
4
+ runTestApp({
5
+ runTests: () => {
6
+ const tests = require.context("./", true, /\.spec\.js$/);
7
+ tests.keys().map(tests);
8
+ },
9
+ });
@@ -0,0 +1,11 @@
1
+ import { runTestApp } from "@nativescript/unit-test-runner";
2
+ // import other polyfills here
3
+
4
+ declare let require: any;
5
+
6
+ runTestApp({
7
+ runTests: () => {
8
+ const tests = require.context("./", true, /\.spec\.ts$/);
9
+ tests.keys().map(tests);
10
+ },
11
+ });
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "sourceMap": true
5
+ },
6
+ "files": ["${ basePath }/test.ts"],
7
+ "include": ["${ basePath }/**/*.spec.ts", "${ basePath }/**/*.d.ts"],
8
+ "exclude": ["node_modules", "platforms", "e2e"]
9
+ }
@@ -1,9 +0,0 @@
1
- // Place your settings in this file to overwrite default and user settings.
2
- {
3
- "files.exclude": {
4
- "**/.git": true,
5
- "**/.DS_Store": true,
6
- "**/*.js": { "when": "$(basename).ts"},
7
- "**/*.js.map": true
8
- }
9
- }