@sasjs/cli 6.4.2 → 6.4.4
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.
- package/build/commands/create/spec/create.spec.js +17 -46
- package/build/commands/help/help.js +2 -1
- package/build/commands/init/init.d.ts +15 -0
- package/build/commands/init/init.js +82 -12
- package/build/commands/init/initCommand.js +9 -2
- package/build/commands/init/spec/init.spec.js +238 -49
- package/build/commands/init/spec/initCommand.spec.js +22 -0
- package/build/commands/init/spec/initFiles.js +5 -0
- package/build/types/command/returnCode.d.ts +2 -1
- package/build/types/command/returnCode.js +4 -0
- package/build/utils/spec/utils.spec.js +1 -0
- package/build/utils/test.d.ts +30 -0
- package/build/utils/test.js +161 -1
- package/package.json +2 -2
|
@@ -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
|
-
|
|
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
|
});
|
|
@@ -52,7 +52,8 @@ function printHelpText() {
|
|
|
52
52
|
description: [
|
|
53
53
|
"Creates the 'sasjs' folder and doxy subfolder (with content files + configuration) for docs",
|
|
54
54
|
"- Inserted in the current working directory.",
|
|
55
|
-
"- If an existing NPM project, package.json is updated with the @sasjs/core dependency."
|
|
55
|
+
"- If an existing NPM project, package.json is updated with the @sasjs/core dependency.",
|
|
56
|
+
"- Aborts without changing anything if this folder already contains sasjs/sasjsconfig.json."
|
|
56
57
|
]
|
|
57
58
|
},
|
|
58
59
|
{
|
|
@@ -1,7 +1,22 @@
|
|
|
1
|
+
export declare class AlreadyInitialisedError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
1
4
|
export declare function init(): Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Creates the macro folder that the generated `macroFolders` points at.
|
|
7
|
+
* `sasjs compile` fails with ENOENT when that folder is absent, so an
|
|
8
|
+
* initialised project compiles before the user has written a macro.
|
|
9
|
+
* The folder carries a `.gitkeep` because git does not track empty directories -
|
|
10
|
+
* without it the folder disappears on clone and compilation breaks again.
|
|
11
|
+
* @param {string} parentFolderName- the name of the project folder.
|
|
12
|
+
*/
|
|
13
|
+
export declare const createMacroFolder: (parentFolderName: string) => Promise<void>;
|
|
2
14
|
/**
|
|
3
15
|
* Creates a SASjs configuration file.
|
|
4
16
|
* Its name will be of the form 'sasjsconfig.json'
|
|
17
|
+
* The target's `serverUrl` is empty rather than a placeholder URL: an empty
|
|
18
|
+
* value reads as "not configured yet", while any non-empty placeholder has to
|
|
19
|
+
* pass URL validation every time the config is read.
|
|
5
20
|
* @param {string} parentFolderName- the name of the project folder.
|
|
6
21
|
*/
|
|
7
22
|
export declare const createConfigFile: (parentFolderName: string) => Promise<void>;
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __extends = (this && this.__extends) || (function () {
|
|
3
|
+
var extendStatics = function (d, b) {
|
|
4
|
+
extendStatics = Object.setPrototypeOf ||
|
|
5
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
7
|
+
return extendStatics(d, b);
|
|
8
|
+
};
|
|
9
|
+
return function (d, b) {
|
|
10
|
+
if (typeof b !== "function" && b !== null)
|
|
11
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
12
|
+
extendStatics(d, b);
|
|
13
|
+
function __() { this.constructor = d; }
|
|
14
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
15
|
+
};
|
|
16
|
+
})();
|
|
2
17
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
18
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
19
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -39,49 +54,104 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
39
54
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
55
|
};
|
|
41
56
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.createConfigFile = void 0;
|
|
57
|
+
exports.createConfigFile = exports.createMacroFolder = exports.AlreadyInitialisedError = void 0;
|
|
43
58
|
exports.init = init;
|
|
44
59
|
var path_1 = __importDefault(require("path"));
|
|
45
60
|
var utils_1 = require("../../utils/utils");
|
|
46
61
|
var utils_2 = require("@sasjs/utils");
|
|
47
62
|
var createLintConfigFile_1 = require("../shared/createLintConfigFile");
|
|
63
|
+
var AlreadyInitialisedError = /** @class */ (function (_super) {
|
|
64
|
+
__extends(AlreadyInitialisedError, _super);
|
|
65
|
+
function AlreadyInitialisedError(message) {
|
|
66
|
+
var _this = _super.call(this, message) || this;
|
|
67
|
+
_this.name = 'AlreadyInitialisedError';
|
|
68
|
+
// The build targets ES5, where extending a built-in does not repair the
|
|
69
|
+
// prototype chain - without this, `instanceof` is false at runtime.
|
|
70
|
+
Object.setPrototypeOf(_this, AlreadyInitialisedError.prototype);
|
|
71
|
+
return _this;
|
|
72
|
+
}
|
|
73
|
+
return AlreadyInitialisedError;
|
|
74
|
+
}(Error));
|
|
75
|
+
exports.AlreadyInitialisedError = AlreadyInitialisedError;
|
|
48
76
|
function init() {
|
|
49
77
|
return __awaiter(this, void 0, void 0, function () {
|
|
50
|
-
var parentFolderName, lintConfigPath;
|
|
78
|
+
var parentFolderName, existingConfigPath, lintConfigPath;
|
|
51
79
|
var _a;
|
|
52
80
|
return __generator(this, function (_b) {
|
|
53
81
|
switch (_b.label) {
|
|
54
82
|
case 0:
|
|
55
83
|
(_a = process.logger) === null || _a === void 0 ? void 0 : _a.info('Initialising SASjs...');
|
|
56
84
|
parentFolderName = '.';
|
|
57
|
-
|
|
85
|
+
existingConfigPath = path_1.default.join(process.projectDir, parentFolderName, 'sasjs', 'sasjsconfig.json');
|
|
86
|
+
return [4 /*yield*/, (0, utils_2.fileExists)(existingConfigPath)];
|
|
58
87
|
case 1:
|
|
88
|
+
if (_b.sent()) {
|
|
89
|
+
throw new AlreadyInitialisedError('This folder is already a SASjs project (sasjs/sasjsconfig.json exists). Aborting without making changes.');
|
|
90
|
+
}
|
|
91
|
+
return [4 /*yield*/, (0, utils_1.setupNpmProject)(parentFolderName)];
|
|
92
|
+
case 2:
|
|
59
93
|
_b.sent();
|
|
60
94
|
return [4 /*yield*/, (0, utils_1.setupGitIgnore)(parentFolderName)];
|
|
61
|
-
case
|
|
95
|
+
case 3:
|
|
62
96
|
_b.sent();
|
|
63
97
|
return [4 /*yield*/, (0, utils_1.setupDoxygen)(parentFolderName)];
|
|
64
|
-
case
|
|
98
|
+
case 4:
|
|
65
99
|
_b.sent();
|
|
66
100
|
return [4 /*yield*/, (0, exports.createConfigFile)(parentFolderName)];
|
|
67
|
-
case
|
|
101
|
+
case 5:
|
|
102
|
+
_b.sent();
|
|
103
|
+
return [4 /*yield*/, (0, exports.createMacroFolder)(parentFolderName)];
|
|
104
|
+
case 6:
|
|
68
105
|
_b.sent();
|
|
69
106
|
lintConfigPath = path_1.default.join(process.projectDir, parentFolderName, '.sasjslint');
|
|
70
107
|
return [4 /*yield*/, (0, utils_2.fileExists)(lintConfigPath)];
|
|
71
|
-
case
|
|
72
|
-
if (!!(_b.sent())) return [3 /*break*/,
|
|
108
|
+
case 7:
|
|
109
|
+
if (!!(_b.sent())) return [3 /*break*/, 9];
|
|
73
110
|
return [4 /*yield*/, (0, createLintConfigFile_1.createLintConfigFile)(parentFolderName)];
|
|
74
|
-
case
|
|
111
|
+
case 8:
|
|
75
112
|
_b.sent();
|
|
76
|
-
_b.label =
|
|
77
|
-
case
|
|
113
|
+
_b.label = 9;
|
|
114
|
+
case 9: return [2 /*return*/];
|
|
78
115
|
}
|
|
79
116
|
});
|
|
80
117
|
});
|
|
81
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Creates the macro folder that the generated `macroFolders` points at.
|
|
121
|
+
* `sasjs compile` fails with ENOENT when that folder is absent, so an
|
|
122
|
+
* initialised project compiles before the user has written a macro.
|
|
123
|
+
* The folder carries a `.gitkeep` because git does not track empty directories -
|
|
124
|
+
* without it the folder disappears on clone and compilation breaks again.
|
|
125
|
+
* @param {string} parentFolderName- the name of the project folder.
|
|
126
|
+
*/
|
|
127
|
+
var createMacroFolder = function (parentFolderName) { return __awaiter(void 0, void 0, void 0, function () {
|
|
128
|
+
var macroFolderPath, gitKeepPath;
|
|
129
|
+
return __generator(this, function (_a) {
|
|
130
|
+
switch (_a.label) {
|
|
131
|
+
case 0:
|
|
132
|
+
macroFolderPath = path_1.default.join(process.projectDir, parentFolderName, 'sasjs', 'macros');
|
|
133
|
+
return [4 /*yield*/, (0, utils_2.createFolder)(macroFolderPath)];
|
|
134
|
+
case 1:
|
|
135
|
+
_a.sent();
|
|
136
|
+
gitKeepPath = path_1.default.join(macroFolderPath, '.gitkeep');
|
|
137
|
+
return [4 /*yield*/, (0, utils_2.fileExists)(gitKeepPath)];
|
|
138
|
+
case 2:
|
|
139
|
+
if (!!(_a.sent())) return [3 /*break*/, 4];
|
|
140
|
+
return [4 /*yield*/, (0, utils_2.createFile)(gitKeepPath, '')];
|
|
141
|
+
case 3:
|
|
142
|
+
_a.sent();
|
|
143
|
+
_a.label = 4;
|
|
144
|
+
case 4: return [2 /*return*/];
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}); };
|
|
148
|
+
exports.createMacroFolder = createMacroFolder;
|
|
82
149
|
/**
|
|
83
150
|
* Creates a SASjs configuration file.
|
|
84
151
|
* Its name will be of the form 'sasjsconfig.json'
|
|
152
|
+
* The target's `serverUrl` is empty rather than a placeholder URL: an empty
|
|
153
|
+
* value reads as "not configured yet", while any non-empty placeholder has to
|
|
154
|
+
* pass URL validation every time the config is read.
|
|
85
155
|
* @param {string} parentFolderName- the name of the project folder.
|
|
86
156
|
*/
|
|
87
157
|
var createConfigFile = function (parentFolderName) { return __awaiter(void 0, void 0, void 0, function () {
|
|
@@ -97,7 +167,7 @@ var createConfigFile = function (parentFolderName) { return __awaiter(void 0, vo
|
|
|
97
167
|
{
|
|
98
168
|
name: 'mytarget',
|
|
99
169
|
serverType: 'SASJS',
|
|
100
|
-
serverUrl: '
|
|
170
|
+
serverUrl: '',
|
|
101
171
|
appLoc: '/Public/apps/myapp'
|
|
102
172
|
}
|
|
103
173
|
]
|
|
@@ -85,8 +85,15 @@ var InitCommand = /** @class */ (function (_super) {
|
|
|
85
85
|
return command_1.ReturnCode.Success;
|
|
86
86
|
})
|
|
87
87
|
.catch(function (err) {
|
|
88
|
-
var _a;
|
|
89
|
-
|
|
88
|
+
var _a, _b;
|
|
89
|
+
// Refusing an already-initialised folder is an expected outcome, not a
|
|
90
|
+
// crash: report it on one line, and exit with a code a script can tell
|
|
91
|
+
// apart from a genuine failure.
|
|
92
|
+
if (err instanceof init_1.AlreadyInitialisedError) {
|
|
93
|
+
(_a = process.logger) === null || _a === void 0 ? void 0 : _a.error(err.message);
|
|
94
|
+
return command_1.ReturnCode.AlreadyInitialised;
|
|
95
|
+
}
|
|
96
|
+
(_b = process.logger) === null || _b === void 0 ? void 0 : _b.error('Error initialising SASjs: ', err);
|
|
90
97
|
return command_1.ReturnCode.InternalError;
|
|
91
98
|
})];
|
|
92
99
|
case 1: return [2 /*return*/, _a.sent()];
|
|
@@ -44,9 +44,11 @@ var path_1 = __importDefault(require("path"));
|
|
|
44
44
|
var test_1 = require("../../../utils/test");
|
|
45
45
|
var utils_1 = require("@sasjs/utils");
|
|
46
46
|
var initFiles_1 = require("./initFiles");
|
|
47
|
-
var create_1 = require("../../create/create");
|
|
48
47
|
var init_1 = require("../init");
|
|
49
48
|
var utils_2 = require("../../../utils");
|
|
49
|
+
var config_1 = require("../../../utils/config");
|
|
50
|
+
var compile_1 = require("../../compile/compile");
|
|
51
|
+
var create_1 = require("../../create/create");
|
|
50
52
|
describe('sasjs init', function () {
|
|
51
53
|
beforeAll(function () {
|
|
52
54
|
dotenv_1.default.config();
|
|
@@ -56,103 +58,290 @@ describe('sasjs init', function () {
|
|
|
56
58
|
switch (_a.label) {
|
|
57
59
|
case 0:
|
|
58
60
|
if (!process.projectDir) return [3 /*break*/, 2];
|
|
59
|
-
return [4 /*yield*/, (0, utils_1.deleteFolder)(process.projectDir)
|
|
61
|
+
return [4 /*yield*/, (0, utils_1.deleteFolder)(process.projectDir)
|
|
62
|
+
// The compile spec sets these; leaving them set would hand later specs a
|
|
63
|
+
// configuration and build folders belonging to a deleted project.
|
|
64
|
+
];
|
|
60
65
|
case 1:
|
|
61
66
|
_a.sent();
|
|
62
67
|
_a.label = 2;
|
|
63
|
-
case 2:
|
|
68
|
+
case 2:
|
|
69
|
+
// The compile spec sets these; leaving them set would hand later specs a
|
|
70
|
+
// configuration and build folders belonging to a deleted project.
|
|
71
|
+
process.currentDir = '';
|
|
72
|
+
process.sasjsConfig = undefined;
|
|
73
|
+
return [2 /*return*/];
|
|
64
74
|
}
|
|
65
75
|
});
|
|
66
76
|
}); });
|
|
67
|
-
it('should initialise
|
|
68
|
-
var appName;
|
|
77
|
+
it('should initialise in an empty current folder', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
69
78
|
return __generator(this, function (_a) {
|
|
70
79
|
switch (_a.label) {
|
|
71
|
-
case 0:
|
|
72
|
-
appName = "test-app-init-".concat((0, test_1.generateUniqueTimestamp)());
|
|
73
|
-
process.projectDir = path_1.default.join(__dirname, appName);
|
|
74
|
-
return [4 /*yield*/, (0, utils_2.setConstants)()];
|
|
80
|
+
case 0: return [4 /*yield*/, setupProjectFolder('test-app-init-')];
|
|
75
81
|
case 1:
|
|
76
82
|
_a.sent();
|
|
77
|
-
return [4 /*yield*/, (0,
|
|
83
|
+
return [4 /*yield*/, expect((0, init_1.init)()).toResolve()];
|
|
78
84
|
case 2:
|
|
79
85
|
_a.sent();
|
|
80
|
-
return [4 /*yield*/,
|
|
86
|
+
return [4 /*yield*/, verifyInit()];
|
|
81
87
|
case 3:
|
|
82
88
|
_a.sent();
|
|
89
|
+
return [2 /*return*/];
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}); });
|
|
93
|
+
it('should add SASjs to an existing npm project', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
94
|
+
var packageJsonPath, existingPackageJson, packageJson, _a, _b;
|
|
95
|
+
return __generator(this, function (_c) {
|
|
96
|
+
switch (_c.label) {
|
|
97
|
+
case 0: return [4 /*yield*/, setupProjectFolder('test-app-init-npm-')];
|
|
98
|
+
case 1:
|
|
99
|
+
_c.sent();
|
|
100
|
+
packageJsonPath = path_1.default.join(process.projectDir, 'package.json');
|
|
101
|
+
existingPackageJson = {
|
|
102
|
+
name: 'my-existing-project',
|
|
103
|
+
version: '1.0.0',
|
|
104
|
+
scripts: { build: 'exit 0' }
|
|
105
|
+
};
|
|
106
|
+
return [4 /*yield*/, (0, utils_1.createFile)(packageJsonPath, JSON.stringify(existingPackageJson, null, 2))];
|
|
107
|
+
case 2:
|
|
108
|
+
_c.sent();
|
|
83
109
|
return [4 /*yield*/, expect((0, init_1.init)()).toResolve()];
|
|
84
|
-
case
|
|
85
|
-
|
|
110
|
+
case 3:
|
|
111
|
+
_c.sent();
|
|
86
112
|
return [4 /*yield*/, verifyInit()];
|
|
113
|
+
case 4:
|
|
114
|
+
_c.sent();
|
|
115
|
+
_b = (_a = JSON).parse;
|
|
116
|
+
return [4 /*yield*/, (0, utils_1.readFile)(packageJsonPath)];
|
|
87
117
|
case 5:
|
|
88
|
-
_a.sent();
|
|
118
|
+
packageJson = _b.apply(_a, [_c.sent()]);
|
|
119
|
+
expect(packageJson.name).toEqual('my-existing-project');
|
|
120
|
+
expect(packageJson.scripts.build).toEqual('exit 0');
|
|
89
121
|
return [2 /*return*/];
|
|
90
122
|
}
|
|
91
123
|
});
|
|
92
124
|
}); });
|
|
93
|
-
it(
|
|
94
|
-
var
|
|
95
|
-
return __generator(this, function (
|
|
96
|
-
switch (
|
|
97
|
-
case 0:
|
|
98
|
-
appName = "test-app-init-sasonly-".concat((0, test_1.generateUniqueTimestamp)());
|
|
99
|
-
process.projectDir = path_1.default.join(__dirname, appName);
|
|
100
|
-
return [4 /*yield*/, (0, utils_2.setConstants)()];
|
|
125
|
+
it('should produce a project that compiles straight away', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
126
|
+
var _a, target;
|
|
127
|
+
return __generator(this, function (_b) {
|
|
128
|
+
switch (_b.label) {
|
|
129
|
+
case 0: return [4 /*yield*/, setupProjectFolder('test-app-init-compile-')];
|
|
101
130
|
case 1:
|
|
102
|
-
|
|
103
|
-
return [4 /*yield*/, (0,
|
|
131
|
+
_b.sent();
|
|
132
|
+
return [4 /*yield*/, expect((0, init_1.init)()).toResolve()
|
|
133
|
+
// Reading the target validates its serverUrl, and compile() reads every
|
|
134
|
+
// folder the config names - the two things that stopped a freshly
|
|
135
|
+
// initialised project from compiling.
|
|
136
|
+
// compile() reads process.sasjsConfig and the build folders, which the CLI
|
|
137
|
+
// sets up from its target command - do the same from a test.
|
|
138
|
+
];
|
|
104
139
|
case 2:
|
|
105
|
-
|
|
140
|
+
_b.sent();
|
|
141
|
+
// Reading the target validates its serverUrl, and compile() reads every
|
|
142
|
+
// folder the config names - the two things that stopped a freshly
|
|
143
|
+
// initialised project from compiling.
|
|
144
|
+
// compile() reads process.sasjsConfig and the build folders, which the CLI
|
|
145
|
+
// sets up from its target command - do the same from a test.
|
|
146
|
+
process.currentDir = process.projectDir;
|
|
147
|
+
_a = process;
|
|
148
|
+
return [4 /*yield*/, (0, config_1.getLocalConfig)()];
|
|
149
|
+
case 3:
|
|
150
|
+
_a.sasjsConfig = _b.sent();
|
|
151
|
+
return [4 /*yield*/, (0, utils_2.setConstants)()];
|
|
152
|
+
case 4:
|
|
153
|
+
_b.sent();
|
|
154
|
+
return [4 /*yield*/, (0, config_1.findTargetInConfiguration)('mytarget')];
|
|
155
|
+
case 5:
|
|
156
|
+
target = (_b.sent()).target;
|
|
157
|
+
return [4 /*yield*/, expect((0, compile_1.compile)(target)).toResolve()];
|
|
158
|
+
case 6:
|
|
159
|
+
_b.sent();
|
|
160
|
+
return [4 /*yield*/, expect((0, utils_1.fileExists)(path_1.default.join(process.projectDir, 'sasjsbuild'))).resolves.toEqual(true)];
|
|
161
|
+
case 7:
|
|
162
|
+
_b.sent();
|
|
163
|
+
return [2 /*return*/];
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}); });
|
|
167
|
+
it('should abort over a template scaffold that ships its own config', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
168
|
+
var configPath, templateConfig, _a, _b, error, _c, _d, _e;
|
|
169
|
+
return __generator(this, function (_f) {
|
|
170
|
+
switch (_f.label) {
|
|
171
|
+
case 0: return [4 /*yield*/, setupProjectFolder('test-app-init-sasonly-')
|
|
172
|
+
// The templates carry their own sasjs/sasjsconfig.json, so they reach the
|
|
173
|
+
// guard by a different route than createFileStructure does.
|
|
174
|
+
];
|
|
175
|
+
case 1:
|
|
176
|
+
_f.sent();
|
|
177
|
+
// The templates carry their own sasjs/sasjsconfig.json, so they reach the
|
|
178
|
+
// guard by a different route than createFileStructure does.
|
|
106
179
|
return [4 /*yield*/, expect((0, create_1.create)('.', 'sasonly')).toResolve()];
|
|
180
|
+
case 2:
|
|
181
|
+
// The templates carry their own sasjs/sasjsconfig.json, so they reach the
|
|
182
|
+
// guard by a different route than createFileStructure does.
|
|
183
|
+
_f.sent();
|
|
184
|
+
configPath = path_1.default.join(process.projectDir, 'sasjs', 'sasjsconfig.json');
|
|
185
|
+
_b = (_a = JSON).parse;
|
|
186
|
+
return [4 /*yield*/, (0, utils_1.readFile)(configPath)];
|
|
107
187
|
case 3:
|
|
108
|
-
_a.sent();
|
|
109
|
-
return [4 /*yield*/,
|
|
188
|
+
templateConfig = _b.apply(_a, [_f.sent()]);
|
|
189
|
+
return [4 /*yield*/, (0, init_1.init)().catch(function (err) { return err; })];
|
|
110
190
|
case 4:
|
|
111
|
-
|
|
112
|
-
|
|
191
|
+
error = _f.sent();
|
|
192
|
+
expect(error).toBeInstanceOf(init_1.AlreadyInitialisedError);
|
|
193
|
+
_c = expect;
|
|
194
|
+
_e = (_d = JSON).parse;
|
|
195
|
+
return [4 /*yield*/, (0, utils_1.readFile)(configPath)];
|
|
113
196
|
case 5:
|
|
114
|
-
|
|
197
|
+
_c.apply(void 0, [_e.apply(_d, [_f.sent()])]).toEqual(templateConfig);
|
|
115
198
|
return [2 /*return*/];
|
|
116
199
|
}
|
|
117
200
|
});
|
|
118
201
|
}); });
|
|
119
|
-
it('should
|
|
120
|
-
var
|
|
121
|
-
return __generator(this, function (
|
|
122
|
-
switch (
|
|
123
|
-
case 0:
|
|
124
|
-
appName = "test-app-init-.-".concat((0, test_1.generateUniqueTimestamp)());
|
|
125
|
-
process.projectDir = path_1.default.join(__dirname, appName);
|
|
126
|
-
return [4 /*yield*/, (0, utils_2.setConstants)()];
|
|
202
|
+
it('should abort over a project sasjs create has just scaffolded', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
203
|
+
var configPath, createdConfig, _a, _b, error, _c, _d, _e;
|
|
204
|
+
return __generator(this, function (_f) {
|
|
205
|
+
switch (_f.label) {
|
|
206
|
+
case 0: return [4 /*yield*/, setupProjectFolder('test-app-init-created-')];
|
|
127
207
|
case 1:
|
|
128
|
-
|
|
129
|
-
return [4 /*yield*/, (0,
|
|
208
|
+
_f.sent();
|
|
209
|
+
return [4 /*yield*/, expect((0, create_1.create)('.', '')).toResolve()
|
|
210
|
+
// create() writes a fuller config than init does, so running init over it
|
|
211
|
+
// must not replace that configuration.
|
|
212
|
+
];
|
|
130
213
|
case 2:
|
|
131
|
-
|
|
132
|
-
|
|
214
|
+
_f.sent();
|
|
215
|
+
configPath = path_1.default.join(process.projectDir, 'sasjs', 'sasjsconfig.json');
|
|
216
|
+
_b = (_a = JSON).parse;
|
|
217
|
+
return [4 /*yield*/, (0, utils_1.readFile)(configPath)];
|
|
133
218
|
case 3:
|
|
134
|
-
_a.sent();
|
|
135
|
-
|
|
219
|
+
createdConfig = _b.apply(_a, [_f.sent()]);
|
|
220
|
+
expect(createdConfig.defaultTarget).not.toEqual('mytarget');
|
|
221
|
+
return [4 /*yield*/, (0, init_1.init)().catch(function (err) { return err; })];
|
|
136
222
|
case 4:
|
|
137
|
-
|
|
223
|
+
error = _f.sent();
|
|
224
|
+
expect(error).toBeInstanceOf(init_1.AlreadyInitialisedError);
|
|
225
|
+
_c = expect;
|
|
226
|
+
_e = (_d = JSON).parse;
|
|
227
|
+
return [4 /*yield*/, (0, utils_1.readFile)(configPath)];
|
|
228
|
+
case 5:
|
|
229
|
+
_c.apply(void 0, [_e.apply(_d, [_f.sent()])]).toEqual(createdConfig);
|
|
230
|
+
return [2 /*return*/];
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}); });
|
|
234
|
+
it('should abort without changes when the folder is already a SASjs project', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
235
|
+
var sasjsFolderPath, configPath, existingConfig, error, _a, _b, _c;
|
|
236
|
+
return __generator(this, function (_d) {
|
|
237
|
+
switch (_d.label) {
|
|
238
|
+
case 0: return [4 /*yield*/, setupProjectFolder('test-app-init-existing-')];
|
|
239
|
+
case 1:
|
|
240
|
+
_d.sent();
|
|
241
|
+
sasjsFolderPath = path_1.default.join(process.projectDir, 'sasjs');
|
|
242
|
+
configPath = path_1.default.join(sasjsFolderPath, 'sasjsconfig.json');
|
|
243
|
+
existingConfig = {
|
|
244
|
+
defaultTarget: 'myTarget',
|
|
245
|
+
targets: [
|
|
246
|
+
{
|
|
247
|
+
name: 'myTarget',
|
|
248
|
+
serverType: 'SAS9',
|
|
249
|
+
serverUrl: 'https://my.server.com',
|
|
250
|
+
appLoc: '/User Folders/my app'
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
};
|
|
254
|
+
return [4 /*yield*/, (0, utils_1.createFolder)(sasjsFolderPath)];
|
|
255
|
+
case 2:
|
|
256
|
+
_d.sent();
|
|
257
|
+
return [4 /*yield*/, (0, utils_1.createFile)(configPath, JSON.stringify(existingConfig, null, 2))];
|
|
258
|
+
case 3:
|
|
259
|
+
_d.sent();
|
|
260
|
+
return [4 /*yield*/, (0, init_1.init)().catch(function (err) { return err; })];
|
|
261
|
+
case 4:
|
|
262
|
+
error = _d.sent();
|
|
263
|
+
expect(error).toBeInstanceOf(init_1.AlreadyInitialisedError);
|
|
264
|
+
expect(error.message).toMatch(/already a SASjs project \(sasjs\/sasjsconfig\.json exists\)/);
|
|
265
|
+
// Nothing is written before the abort, so the existing project is untouched.
|
|
266
|
+
_a = expect;
|
|
267
|
+
_c = (_b = JSON).parse;
|
|
268
|
+
return [4 /*yield*/, (0, utils_1.readFile)(configPath)];
|
|
269
|
+
case 5:
|
|
270
|
+
// Nothing is written before the abort, so the existing project is untouched.
|
|
271
|
+
_a.apply(void 0, [_c.apply(_b, [_d.sent()])]).toEqual(existingConfig);
|
|
272
|
+
return [4 /*yield*/, expect((0, utils_1.fileExists)(path_1.default.join(process.projectDir, 'package.json'))).resolves.toEqual(false)];
|
|
273
|
+
case 6:
|
|
274
|
+
_d.sent();
|
|
275
|
+
return [4 /*yield*/, expect((0, utils_1.fileExists)(path_1.default.join(process.projectDir, '.gitignore'))).resolves.toEqual(false)];
|
|
276
|
+
case 7:
|
|
277
|
+
_d.sent();
|
|
278
|
+
return [4 /*yield*/, expect((0, utils_1.fileExists)(path_1.default.join(sasjsFolderPath, 'doxy'))).resolves.toEqual(false)];
|
|
279
|
+
case 8:
|
|
280
|
+
_d.sent();
|
|
138
281
|
return [2 /*return*/];
|
|
139
282
|
}
|
|
140
283
|
});
|
|
141
284
|
}); });
|
|
142
285
|
});
|
|
143
|
-
var
|
|
144
|
-
var gitIgnoreFilePath, gitIgnoreContent;
|
|
286
|
+
var setupProjectFolder = function (prefix) { return __awaiter(void 0, void 0, void 0, function () {
|
|
145
287
|
return __generator(this, function (_a) {
|
|
146
288
|
switch (_a.label) {
|
|
147
|
-
case 0:
|
|
289
|
+
case 0:
|
|
290
|
+
process.projectDir = path_1.default.join(__dirname, "".concat(prefix).concat((0, test_1.generateUniqueTimestamp)()));
|
|
291
|
+
return [4 /*yield*/, (0, utils_2.setConstants)()];
|
|
148
292
|
case 1:
|
|
149
293
|
_a.sent();
|
|
294
|
+
return [4 /*yield*/, (0, utils_1.createFolder)(process.projectDir)];
|
|
295
|
+
case 2:
|
|
296
|
+
_a.sent();
|
|
297
|
+
return [2 /*return*/];
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}); };
|
|
301
|
+
var verifyInit = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
302
|
+
var gitIgnoreFilePath, gitIgnoreContent, configPath, config, _a, _b, macroFolderPath, lintConfigPath, packageJson, _c, _d;
|
|
303
|
+
return __generator(this, function (_e) {
|
|
304
|
+
switch (_e.label) {
|
|
305
|
+
case 0: return [4 /*yield*/, (0, test_1.verifyFolder)(initFiles_1.initFiles)];
|
|
306
|
+
case 1:
|
|
307
|
+
_e.sent();
|
|
150
308
|
gitIgnoreFilePath = path_1.default.join(process.projectDir, '.gitignore');
|
|
151
309
|
return [4 /*yield*/, (0, utils_1.readFile)(gitIgnoreFilePath)];
|
|
152
310
|
case 2:
|
|
153
|
-
gitIgnoreContent =
|
|
311
|
+
gitIgnoreContent = _e.sent();
|
|
154
312
|
expect(gitIgnoreContent.match(/^sasjsbuild/gm).length).toEqual(1);
|
|
155
313
|
expect(gitIgnoreContent.match(/^node_modules/gm).length).toEqual(1);
|
|
314
|
+
configPath = path_1.default.join(process.projectDir, 'sasjs', 'sasjsconfig.json');
|
|
315
|
+
_b = (_a = JSON).parse;
|
|
316
|
+
return [4 /*yield*/, (0, utils_1.readFile)(configPath)];
|
|
317
|
+
case 3:
|
|
318
|
+
config = _b.apply(_a, [_e.sent()]);
|
|
319
|
+
expect(config.$schema).toEqual('https://cli.sasjs.io/sasjsconfig-schema.json');
|
|
320
|
+
expect(config.macroFolders).toEqual(['sasjs/macros']);
|
|
321
|
+
expect(config.defaultTarget).toEqual('mytarget');
|
|
322
|
+
expect(config.targets.length).toEqual(1);
|
|
323
|
+
expect(config.targets[0]).toEqual({
|
|
324
|
+
name: 'mytarget',
|
|
325
|
+
serverType: 'SASJS',
|
|
326
|
+
serverUrl: '',
|
|
327
|
+
appLoc: '/Public/apps/myapp'
|
|
328
|
+
});
|
|
329
|
+
macroFolderPath = path_1.default.join(process.projectDir, 'sasjs', 'macros');
|
|
330
|
+
return [4 /*yield*/, expect((0, utils_1.fileExists)(macroFolderPath)).resolves.toEqual(true)];
|
|
331
|
+
case 4:
|
|
332
|
+
_e.sent();
|
|
333
|
+
return [4 /*yield*/, expect((0, utils_1.fileExists)(path_1.default.join(macroFolderPath, '.gitkeep'))).resolves.toEqual(true)];
|
|
334
|
+
case 5:
|
|
335
|
+
_e.sent();
|
|
336
|
+
lintConfigPath = path_1.default.join(process.projectDir, '.sasjslint');
|
|
337
|
+
return [4 /*yield*/, expect((0, utils_1.fileExists)(lintConfigPath)).resolves.toEqual(true)];
|
|
338
|
+
case 6:
|
|
339
|
+
_e.sent();
|
|
340
|
+
_d = (_c = JSON).parse;
|
|
341
|
+
return [4 /*yield*/, (0, utils_1.readFile)(path_1.default.join(process.projectDir, 'package.json'))];
|
|
342
|
+
case 7:
|
|
343
|
+
packageJson = _d.apply(_c, [_e.sent()]);
|
|
344
|
+
expect(packageJson.dependencies['@sasjs/core']).toBeDefined();
|
|
156
345
|
return [2 /*return*/];
|
|
157
346
|
}
|
|
158
347
|
});
|
|
@@ -146,6 +146,28 @@ describe('InitCommand', function () {
|
|
|
146
146
|
}
|
|
147
147
|
});
|
|
148
148
|
}); });
|
|
149
|
+
it('should report an already-initialised folder on one line', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
150
|
+
var message, args, command, returnCode;
|
|
151
|
+
return __generator(this, function (_a) {
|
|
152
|
+
switch (_a.label) {
|
|
153
|
+
case 0:
|
|
154
|
+
message = 'This folder is already a SASjs project (sasjs/sasjsconfig.json exists). Aborting without making changes.';
|
|
155
|
+
jest
|
|
156
|
+
.spyOn(initModule, 'init')
|
|
157
|
+
.mockImplementation(function () {
|
|
158
|
+
return Promise.reject(new initModule.AlreadyInitialisedError(message));
|
|
159
|
+
});
|
|
160
|
+
args = __spreadArray(__spreadArray([], __read(defaultArgs), false), ['init'], false);
|
|
161
|
+
command = new initCommand_1.InitCommand(args);
|
|
162
|
+
return [4 /*yield*/, command.execute()];
|
|
163
|
+
case 1:
|
|
164
|
+
returnCode = _a.sent();
|
|
165
|
+
expect(returnCode).toEqual(command_1.ReturnCode.AlreadyInitialised);
|
|
166
|
+
expect(process.logger.error).toHaveBeenCalledWith(message);
|
|
167
|
+
return [2 /*return*/];
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}); });
|
|
149
171
|
});
|
|
150
172
|
var setupMocks = function () {
|
|
151
173
|
jest.resetAllMocks();
|
|
@@ -7,4 +7,8 @@ var ReturnCode;
|
|
|
7
7
|
ReturnCode[ReturnCode["InvalidCommand"] = 1] = "InvalidCommand";
|
|
8
8
|
ReturnCode[ReturnCode["InternalError"] = 2] = "InternalError";
|
|
9
9
|
ReturnCode[ReturnCode["LintError"] = 3] = "LintError";
|
|
10
|
+
// `init` refusing a folder that is already a SASjs project. Distinct from
|
|
11
|
+
// InvalidCommand, which also covers unparseable arguments, so a script can
|
|
12
|
+
// tell a refusal from a bad invocation.
|
|
13
|
+
ReturnCode[ReturnCode["AlreadyInitialised"] = 4] = "AlreadyInitialised";
|
|
10
14
|
})(ReturnCode || (exports.ReturnCode = ReturnCode = {}));
|
|
@@ -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');
|
package/build/utils/test.d.ts
CHANGED
|
@@ -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>;
|
package/build/utils/test.js
CHANGED
|
@@ -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
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@sasjs/adapter": "^5.1.1",
|
|
74
74
|
"@sasjs/core": "^6.1.1",
|
|
75
75
|
"@sasjs/lint": "4.8.1",
|
|
76
|
-
"@sasjs/utils": "^4.1.
|
|
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.
|
|
126
|
+
"version": "6.4.4"
|
|
127
127
|
}
|