@sasjs/cli 6.4.3 → 6.4.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,37 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -82,22 +49,12 @@ var reactAppFiles_1 = require("./reactAppFiles");
82
49
  var angularAppFiles_1 = require("./angularAppFiles");
83
50
  var create_1 = require("../create");
84
51
  var utils_2 = require("../../../utils");
85
- var shell = __importStar(require("../../../utils/shell"));
86
52
  describe('sasjs create', function () {
87
53
  beforeAll(function () {
88
54
  dotenv_1.default.config();
89
55
  });
90
56
  beforeEach(function () {
91
- var exec = shell.exec;
92
- jest.spyOn(shell, 'exec').mockImplementation(function (command) {
93
- if (!command.includes('npm install')) {
94
- return exec(command, {
95
- silent: true
96
- });
97
- }
98
- // The real install is skipped; the caller ignores the result.
99
- return { stdout: '', stderr: '', code: 0 };
100
- });
57
+ (0, test_1.stubNpm)();
101
58
  });
102
59
  afterEach(function () { return __awaiter(void 0, void 0, void 0, function () {
103
60
  return __generator(this, function (_a) {
@@ -128,9 +85,15 @@ describe('sasjs create', function () {
128
85
  return [4 /*yield*/, expect((0, create_1.create)('.', '')).toResolve()];
129
86
  case 3:
130
87
  _a.sent();
131
- return [4 /*yield*/, verifyCreate('.', '')];
88
+ return [4 /*yield*/, verifyCreate('.', '')
89
+ // verifyCreate's package.json assertion is only meaningful if create asked
90
+ // npm to add the dependency - the stub writes what that command writes.
91
+ ];
132
92
  case 4:
133
93
  _a.sent();
94
+ // verifyCreate's package.json assertion is only meaningful if create asked
95
+ // npm to add the dependency - the stub writes what that command writes.
96
+ expect(test_1.npmCommands).toContain('npm i @sasjs/core --save');
134
97
  return [2 /*return*/];
135
98
  }
136
99
  });
@@ -301,9 +264,17 @@ var verifyCreateWeb = function (appName, appType) { return __awaiter(void 0, voi
301
264
  return [4 /*yield*/, (0, test_1.verifyFolder)(fileStructure)];
302
265
  case 1:
303
266
  _a.sent();
304
- return [4 /*yield*/, (0, test_1.verifyPackageJsonContent)(appName)];
267
+ return [4 /*yield*/, (0, test_1.verifyPackageJsonContent)(appName)
268
+ // A seed app carries its dependencies in the template's package.json, so the
269
+ // command create issues for it is a plain install - the same trade as above:
270
+ // the stub writes what npm would, and this asserts the CLI asked for it.
271
+ ];
305
272
  case 2:
306
273
  _a.sent();
274
+ // A seed app carries its dependencies in the template's package.json, so the
275
+ // command create issues for it is a plain install - the same trade as above:
276
+ // the stub writes what npm would, and this asserts the CLI asked for it.
277
+ expect(test_1.npmCommands).toContain('npm install');
307
278
  return [2 /*return*/];
308
279
  }
309
280
  });
@@ -357,6 +357,7 @@ describe('utils', function () {
357
357
  return __generator(this, function (_a) {
358
358
  switch (_a.label) {
359
359
  case 0:
360
+ (0, test_1.stubNpm)();
360
361
  reactFolder = 'react-seed-app';
361
362
  reactFolderPath = path_1.default.join(__dirname, reactFolder);
362
363
  sasjsFolderPath = path_1.default.join(reactFolderPath, 'sasjs');
@@ -11,6 +11,36 @@ import { ServiceConfig, JobConfig } from '@sasjs/utils/types/config';
11
11
  * short random suffix make that impossible while keeping the name readable.
12
12
  */
13
13
  export declare const generateUniqueTimestamp: () => string;
14
+ /**
15
+ * Every npm command the stub has answered since it was last installed, in order
16
+ * - so a spec can assert the command the CLI issued, not only the package.json
17
+ * it left behind. `stubNpm` empties it, so one test sees only its own commands.
18
+ */
19
+ export declare const npmCommands: string[];
20
+ /**
21
+ * Answers the npm commands `create` and `init` issue, and runs everything else
22
+ * for real.
23
+ *
24
+ * Scaffolding an app shells out to npm three ways: `npm init` (about 0.6s), an
25
+ * install of @sasjs/core (about 1.3s) and, for a seed app, that app's whole
26
+ * dependency tree (about 3s for minimal, 27s for react). Every spec that
27
+ * creates an app pays all of it, again and again, and every one of those calls
28
+ * needs the registry to answer - so the "mocked" suite is neither fast nor
29
+ * offline.
30
+ *
31
+ * None of it is the CLI's own behaviour. The CLI owns the command it issues and
32
+ * the package.json a project is left with, so the stub answers those three
33
+ * commands with exactly that effect and records them in `npmCommands`; every
34
+ * other command - the template downloads, compiles, builds and docs - still runs
35
+ * for real.
36
+ *
37
+ * Call it where the app is created: from `beforeEach`, or from a helper that
38
+ * runs there. Jest restores spies before each test, so a stub installed in
39
+ * `beforeAll` is gone before the first test body runs - and because `npmCommands`
40
+ * is emptied on installation, a spec asserting on it must install the stub in
41
+ * the same test that creates the app.
42
+ */
43
+ export declare const stubNpm: () => void;
14
44
  export declare const createTestApp: (parentFolder: string, appName: string) => Promise<void>;
15
45
  export declare const createTestJobsApp: (parentFolder: string, appName: string) => Promise<void>;
16
46
  export declare const createTestMinimalApp: (parentFolder: string, appName: string) => Promise<void>;
@@ -10,6 +10,39 @@ var __assign = (this && this.__assign) || function () {
10
10
  };
11
11
  return __assign.apply(this, arguments);
12
12
  };
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
13
46
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
47
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
48
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -75,7 +108,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
75
108
  return (mod && mod.__esModule) ? mod : { "default": mod };
76
109
  };
77
110
  Object.defineProperty(exports, "__esModule", { value: true });
78
- exports.verifyGitNotPresent = exports.verifyCompiledJob = exports.verifyCompiledService = exports.verifyDotFilesNotGenerated = exports.verifyDotFiles = exports.verifyDocs = exports.updateConfig = exports.updateTarget = exports.removeAllTargetsFromConfigs = exports.verifyPackageJsonContent = exports.verifyFolder = exports.mockProcessExit = exports.verifyStep = exports.createTestGlobalTarget = exports.generateTestTarget = exports.removeTestServerFolder = exports.removeTestApp = exports.createTestMinimalApp = exports.createTestJobsApp = exports.createTestApp = exports.generateUniqueTimestamp = void 0;
111
+ exports.verifyGitNotPresent = exports.verifyCompiledJob = exports.verifyCompiledService = exports.verifyDotFilesNotGenerated = exports.verifyDotFiles = exports.verifyDocs = exports.updateConfig = exports.updateTarget = exports.removeAllTargetsFromConfigs = exports.verifyPackageJsonContent = exports.verifyFolder = exports.mockProcessExit = exports.verifyStep = exports.createTestGlobalTarget = exports.generateTestTarget = exports.removeTestServerFolder = exports.removeTestApp = exports.createTestMinimalApp = exports.createTestJobsApp = exports.createTestApp = exports.stubNpm = exports.npmCommands = exports.generateUniqueTimestamp = void 0;
112
+ var fs_1 = __importDefault(require("fs"));
79
113
  var path_1 = __importDefault(require("path"));
80
114
  var dotenv_1 = __importDefault(require("dotenv"));
81
115
  var utils_1 = require("@sasjs/utils");
@@ -89,6 +123,7 @@ var builtFiles_1 = require("./fileStructures/builtFiles");
89
123
  var builtFilesCustom1_1 = require("./fileStructures/builtFilesCustom1");
90
124
  var create_1 = require("../commands/create/create");
91
125
  var setConstants_1 = require("./setConstants");
126
+ var shell = __importStar(require("./shell"));
92
127
  /**
93
128
  * A name for a test app or output folder that two specs cannot collide on.
94
129
  *
@@ -104,11 +139,134 @@ var generateUniqueTimestamp = function () {
104
139
  .slice(2, 7));
105
140
  };
106
141
  exports.generateUniqueTimestamp = generateUniqueTimestamp;
142
+ /**
143
+ * Every npm command the stub has answered since it was last installed, in order
144
+ * - so a spec can assert the command the CLI issued, not only the package.json
145
+ * it left behind. `stubNpm` empties it, so one test sees only its own commands.
146
+ */
147
+ exports.npmCommands = [];
148
+ /** The marker this helper puts on the mock it installs. */
149
+ var stubMarker = Symbol('stubNpm');
150
+ /**
151
+ * Answers the npm commands `create` and `init` issue, and runs everything else
152
+ * for real.
153
+ *
154
+ * Scaffolding an app shells out to npm three ways: `npm init` (about 0.6s), an
155
+ * install of @sasjs/core (about 1.3s) and, for a seed app, that app's whole
156
+ * dependency tree (about 3s for minimal, 27s for react). Every spec that
157
+ * creates an app pays all of it, again and again, and every one of those calls
158
+ * needs the registry to answer - so the "mocked" suite is neither fast nor
159
+ * offline.
160
+ *
161
+ * None of it is the CLI's own behaviour. The CLI owns the command it issues and
162
+ * the package.json a project is left with, so the stub answers those three
163
+ * commands with exactly that effect and records them in `npmCommands`; every
164
+ * other command - the template downloads, compiles, builds and docs - still runs
165
+ * for real.
166
+ *
167
+ * Call it where the app is created: from `beforeEach`, or from a helper that
168
+ * runs there. Jest restores spies before each test, so a stub installed in
169
+ * `beforeAll` is gone before the first test body runs - and because `npmCommands`
170
+ * is emptied on installation, a spec asserting on it must install the stub in
171
+ * the same test that creates the app.
172
+ */
173
+ var stubNpm = function () {
174
+ // Re-install when jest has restored the previous stub: the marker goes with the
175
+ // mock, so its absence is what tells a restored stub from a live one. The
176
+ // marker also distinguishes this stub from a spy a spec installed for its own
177
+ // reasons - a bare `isMockFunction` check cannot, and would leave the npm calls
178
+ // running for real.
179
+ if (shell.exec[stubMarker])
180
+ return;
181
+ exports.npmCommands.length = 0;
182
+ var realExec = shell.exec;
183
+ var stub = jest
184
+ .spyOn(shell, 'exec')
185
+ .mockImplementation(function (command, options) {
186
+ if (options === void 0) { options = {}; }
187
+ var call = npmCall(command);
188
+ if (!call)
189
+ return realExec(command, options);
190
+ exports.npmCommands.push(call.command);
191
+ call.run();
192
+ return { stdout: '', stderr: '', code: 0 };
193
+ });
194
+ stub[stubMarker] = true;
195
+ };
196
+ exports.stubNpm = stubNpm;
197
+ /**
198
+ * Parses one of the CLI's shell commands into the npm call it stands for, or
199
+ * null when it is a command that must really run.
200
+ */
201
+ var npmCall = function (command) {
202
+ // Every npm command is issued as `cd "<folder>" && npm ...`.
203
+ var parsed = /^cd "([^"]+)" && (npm .*)$/.exec(command);
204
+ if (!parsed)
205
+ return null;
206
+ var _a = __read(parsed, 3), folder = _a[1], npm = _a[2];
207
+ if (/^npm init\b/.test(npm))
208
+ return { command: npm, run: function () { return writePackageJson(folder); } };
209
+ if (/^npm i(nstall)? @sasjs\/core\b/.test(npm))
210
+ return { command: npm, run: function () { return addCoreDependency(folder); } };
211
+ // A seed app's own tree. The template's package.json already declares it and
212
+ // no spec reads node_modules, so there is nothing here to install.
213
+ if (/^npm install$/.test(npm))
214
+ return { command: npm, run: function () { } };
215
+ // An npm command this stub does not answer would go to the registry and cost
216
+ // seconds per call, with nothing here to show for it - so say so instead of
217
+ // quietly running it. A new npm call in the CLI means teaching this stub.
218
+ throw new Error("stubNpm does not know how to answer the npm command: ".concat(command));
219
+ };
220
+ /** The package.json `npm init --yes` writes into an otherwise empty folder. */
221
+ var writePackageJson = function (folder) {
222
+ var filePath = path_1.default.join(folder, 'package.json');
223
+ if (fs_1.default.existsSync(filePath))
224
+ return;
225
+ fs_1.default.writeFileSync(filePath, JSON.stringify({
226
+ name: path_1.default.basename(folder),
227
+ version: '1.0.0',
228
+ description: '',
229
+ main: 'index.js',
230
+ scripts: { test: 'echo "Error: no test specified" && exit 1' },
231
+ keywords: [],
232
+ author: '',
233
+ license: 'ISC'
234
+ }, null, 2));
235
+ };
236
+ /** What `npm i @sasjs/core --save` does to package.json and the lockfile. */
237
+ var addCoreDependency = function (folder) {
238
+ var filePath = path_1.default.join(folder, 'package.json');
239
+ var packageJson = fs_1.default.existsSync(filePath)
240
+ ? JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'))
241
+ : {};
242
+ packageJson.dependencies = __assign(__assign({}, (packageJson.dependencies || {})), {
243
+ // The range the CLI itself declares. Any range satisfies the specs, and
244
+ // reading it here means the stub cannot drift from the package it tests.
245
+ '@sasjs/core': cliPackageJson().dependencies['@sasjs/core'] });
246
+ fs_1.default.writeFileSync(filePath, JSON.stringify(packageJson, null, 2));
247
+ // An install leaves a lockfile behind, and specs assert on its presence.
248
+ fs_1.default.writeFileSync(path_1.default.join(folder, 'package-lock.json'), JSON.stringify({
249
+ name: packageJson.name,
250
+ version: packageJson.version,
251
+ lockfileVersion: 3,
252
+ packages: {
253
+ '': {
254
+ name: packageJson.name,
255
+ version: packageJson.version,
256
+ dependencies: packageJson.dependencies
257
+ }
258
+ }
259
+ }, null, 2));
260
+ };
261
+ var cliPackageJson = function () {
262
+ return JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '..', '..', 'package.json'), 'utf8'));
263
+ };
107
264
  var createTestApp = function (parentFolder, appName) { return __awaiter(void 0, void 0, void 0, function () {
108
265
  var _a;
109
266
  return __generator(this, function (_b) {
110
267
  switch (_b.label) {
111
268
  case 0:
269
+ (0, exports.stubNpm)();
112
270
  process.projectDir = parentFolder;
113
271
  return [4 /*yield*/, (0, create_1.create)(appName, '')];
114
272
  case 1:
@@ -132,6 +290,7 @@ var createTestJobsApp = function (parentFolder, appName) { return __awaiter(void
132
290
  return __generator(this, function (_b) {
133
291
  switch (_b.label) {
134
292
  case 0:
293
+ (0, exports.stubNpm)();
135
294
  process.projectDir = parentFolder;
136
295
  return [4 /*yield*/, (0, create_1.create)(appName, 'jobs')];
137
296
  case 1:
@@ -158,6 +317,7 @@ var createTestMinimalApp = function (parentFolder, appName) { return __awaiter(v
158
317
  return __generator(this, function (_b) {
159
318
  switch (_b.label) {
160
319
  case 0:
320
+ (0, exports.stubNpm)();
161
321
  process.projectDir = parentFolder;
162
322
  return [4 /*yield*/, (0, create_1.create)(appName, 'minimal')];
163
323
  case 1:
package/package.json CHANGED
@@ -72,8 +72,8 @@
72
72
  "dependencies": {
73
73
  "@sasjs/adapter": "^5.1.1",
74
74
  "@sasjs/core": "^6.1.1",
75
- "@sasjs/lint": "4.8.1",
76
- "@sasjs/utils": "^4.1.1",
75
+ "@sasjs/lint": "4.9.0",
76
+ "@sasjs/utils": "^4.1.2",
77
77
  "axios": "1.20.0",
78
78
  "chalk": "4.1.2",
79
79
  "dotenv": "18.0.8",
@@ -123,5 +123,5 @@
123
123
  "ws": "8.21.0",
124
124
  "nanoid": "3.3.18"
125
125
  },
126
- "version": "6.4.3"
126
+ "version": "6.4.5"
127
127
  }