@sasjs/cli 6.2.4 → 6.2.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.
package/README.md CHANGED
@@ -16,6 +16,7 @@
16
16
 
17
17
  - Scaffold a new SAS App in seconds (`sasjs create myApp -t jobs`)
18
18
  - Compile / Build SAS Jobs, Services & Macros _locally_ and deploy / execute _remotely_, in isolation from other developers (`sasjs cbd`)
19
+ - Compile a single Job, Service or Test without touching the rest of the build (`sasjs compile identify --source sasjs/jobs/daily/load.sas`)
19
20
  - No dependency on the server filesystem
20
21
  - Optionally synchronise a local folder onto the server filesystem using `sasjs fs`
21
22
  - Trigger Viya Jobs & Flows (`sasjs job execute` / `sasjs flow execute`)
@@ -3,7 +3,13 @@ import { TargetCommand } from '../../types/command/targetCommand';
3
3
  export declare class CompileCommand extends TargetCommand {
4
4
  constructor(args: string[]);
5
5
  get source(): string;
6
- get output(): string;
6
+ /**
7
+ * The base folder requested with `--output`, or undefined to let the compile
8
+ * use the build folder for the file's type. The type sub folder, the
9
+ * configured folder's name and the file's own path below it are added by
10
+ * compileSingleFile, so there is one implementation of the destination.
11
+ */
12
+ getOutputPath(): string | undefined;
7
13
  execute(): Promise<ReturnCode>;
8
14
  executeCompile(): Promise<ReturnCode>;
9
15
  executeSingleFileCompile(): Promise<ReturnCode>;
@@ -50,17 +50,12 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
50
50
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
51
  }
52
52
  };
53
- var __importDefault = (this && this.__importDefault) || function (mod) {
54
- return (mod && mod.__esModule) ? mod : { "default": mod };
55
- };
56
53
  Object.defineProperty(exports, "__esModule", { value: true });
57
54
  exports.CompileCommand = void 0;
58
55
  var command_1 = require("../../types/command");
59
56
  var targetCommand_1 = require("../../types/command/targetCommand");
60
57
  var utils_1 = require("../../utils");
61
58
  var compile_1 = require("./compile");
62
- var path_1 = __importDefault(require("path"));
63
- var getDestinationPath_1 = require("./internal/getDestinationPath");
64
59
  var compileSingleFile_1 = require("./compileSingleFile");
65
60
  var utils_2 = require("@sasjs/utils");
66
61
  var CompileSubCommand;
@@ -73,15 +68,23 @@ var CompileSubCommand;
73
68
  var syntax = 'compile [subCommand]';
74
69
  var aliases = ['c'];
75
70
  var usage = 'Usage: sasjs compile [subCommand] [options]';
76
- var description = 'Compiles jobs and services in the project by inlining all dependencies and adds init and term programs as configured in the specified target.';
71
+ var description = 'Compiles jobs and services in the project by inlining all dependencies and adds init and term programs as configured in the specified target. With a subCommand (job, service, test or identify) and --source, compiles a single file to the folder matching its type.';
77
72
  var examples = [
78
73
  {
79
74
  command: 'sasjs compile -t myTarget',
80
- description: ''
75
+ description: 'compiles every job and service in the project'
81
76
  },
82
77
  {
83
78
  command: 'sasjs c -t myTarget',
84
- description: ''
79
+ description: 'the same, using the alias'
80
+ },
81
+ {
82
+ command: 'sasjs compile job --source sasjs/jobs/daily/load.sas -t myTarget',
83
+ description: 'compiles one job'
84
+ },
85
+ {
86
+ command: 'sasjs compile identify --source sasjs/services/admin/users.sas -t myTarget -o /tmp/out',
87
+ description: 'works out the file type and compiles it below /tmp/out'
85
88
  }
86
89
  ];
87
90
  var subCommandParseOptions = {
@@ -110,31 +113,16 @@ var CompileCommand = /** @class */ (function (_super) {
110
113
  enumerable: false,
111
114
  configurable: true
112
115
  });
113
- Object.defineProperty(CompileCommand.prototype, "output", {
114
- get: function () {
115
- var value = this.parsed.output;
116
- var sourcefilePathParts = path_1.default.normalize(this.source).split(path_1.default.sep);
117
- sourcefilePathParts.splice(-1, 1);
118
- var sourceFolderPath = sourcefilePathParts.join(path_1.default.sep);
119
- var leafFolderName = sourceFolderPath.split(path_1.default.sep).pop();
120
- var outputPath;
121
- if (value) {
122
- var internal = [value, "".concat(this.subCommand, "s")];
123
- if (leafFolderName)
124
- internal.push(leafFolderName);
125
- outputPath = (0, utils_2.getAbsolutePath)(internal.join(path_1.default.sep), process.currentDir);
126
- }
127
- else {
128
- outputPath =
129
- this.subCommand === 'job'
130
- ? (0, getDestinationPath_1.getDestinationJobPath)(sourceFolderPath)
131
- : (0, getDestinationPath_1.getDestinationServicePath)(sourceFolderPath);
132
- }
133
- return outputPath;
134
- },
135
- enumerable: false,
136
- configurable: true
137
- });
116
+ /**
117
+ * The base folder requested with `--output`, or undefined to let the compile
118
+ * use the build folder for the file's type. The type sub folder, the
119
+ * configured folder's name and the file's own path below it are added by
120
+ * compileSingleFile, so there is one implementation of the destination.
121
+ */
122
+ CompileCommand.prototype.getOutputPath = function () {
123
+ var value = this.parsed.output;
124
+ return value ? (0, utils_2.getAbsolutePath)(value, process.currentDir) : undefined;
125
+ };
138
126
  CompileCommand.prototype.execute = function () {
139
127
  return __awaiter(this, void 0, void 0, function () {
140
128
  var _a;
@@ -181,16 +169,16 @@ var CompileCommand = /** @class */ (function (_super) {
181
169
  };
182
170
  CompileCommand.prototype.executeSingleFileCompile = function () {
183
171
  return __awaiter(this, void 0, void 0, function () {
184
- var target, output;
172
+ var target;
185
173
  return __generator(this, function (_a) {
186
174
  switch (_a.label) {
187
- case 0: return [4 /*yield*/, this.getTargetInfo()];
175
+ case 0: return [4 /*yield*/, this.getTargetInfo()
176
+ // 'identify' is resolved once, in compileSingleFile, so the command and
177
+ // other callers such as `sasjs run --compile` cannot disagree about it.
178
+ ];
188
179
  case 1:
189
180
  target = (_a.sent()).target;
190
- return [4 /*yield*/, this.output];
191
- case 2:
192
- output = _a.sent();
193
- return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)(target, this.parsed.subCommand, this.source, output)
181
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)(target, this.parsed.subCommand, this.source, this.getOutputPath())
194
182
  .then(function (res) {
195
183
  var _a;
196
184
  (_a = process.logger) === null || _a === void 0 ? void 0 : _a.success("Source has been successfully compiled!\nThe compiled output is located at: ".concat(res.destinationPath));
@@ -200,7 +188,10 @@ var CompileCommand = /** @class */ (function (_super) {
200
188
  (0, utils_1.displayError)(err, 'Error compiling source.');
201
189
  return command_1.ReturnCode.InternalError;
202
190
  })];
203
- case 3: return [2 /*return*/, _a.sent()];
191
+ case 2:
192
+ // 'identify' is resolved once, in compileSingleFile, so the command and
193
+ // other callers such as `sasjs run --compile` cannot disagree about it.
194
+ return [2 /*return*/, _a.sent()];
204
195
  }
205
196
  });
206
197
  });
@@ -4,6 +4,6 @@ export declare enum CompileSingleFileSubCommands {
4
4
  Service = "service",
5
5
  Test = "test"
6
6
  }
7
- export declare function compileSingleFile(target: Target, subCommand: string | undefined, source: string, output: string, insertProgramVar?: boolean, currentFolder?: string): Promise<{
7
+ export declare function compileSingleFile(target: Target, subCommand: string | undefined, source: string, output?: string, insertProgramVar?: boolean, currentFolder?: string): Promise<{
8
8
  destinationPath: string;
9
9
  }>;
@@ -35,6 +35,31 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
35
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
36
  }
37
37
  };
38
+ var __read = (this && this.__read) || function (o, n) {
39
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
40
+ if (!m) return o;
41
+ var i = m.call(o), r, ar = [], e;
42
+ try {
43
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
44
+ }
45
+ catch (error) { e = { error: error }; }
46
+ finally {
47
+ try {
48
+ if (r && !r.done && (m = i["return"])) m.call(i);
49
+ }
50
+ finally { if (e) throw e.error; }
51
+ }
52
+ return ar;
53
+ };
54
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
55
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
56
+ if (ar || !(i in from)) {
57
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
58
+ ar[i] = from[i];
59
+ }
60
+ }
61
+ return to.concat(ar || Array.prototype.slice.call(from));
62
+ };
38
63
  var __importDefault = (this && this.__importDefault) || function (mod) {
39
64
  return (mod && mod.__esModule) ? mod : { "default": mod };
40
65
  };
@@ -55,14 +80,117 @@ var CompileSingleFileSubCommands;
55
80
  var isCompileSingleFileSubCommands = function (command) {
56
81
  return Object.values(CompileSingleFileSubCommands).includes(command);
57
82
  };
83
+ /** The longest configured folder that contains the given folder, if any. */
84
+ var getContainingFolder = function (folders, folder) {
85
+ return folders
86
+ .filter(function (configured) {
87
+ return folder === configured || folder.startsWith(configured + path_1.default.sep);
88
+ })
89
+ .sort(function (a, b) { return b.length - a.length; })[0];
90
+ };
91
+ /** The configured folders that can hold a file of this type. */
92
+ var getConfiguredFolders = function (target, subCommand) { return __awaiter(void 0, void 0, void 0, function () {
93
+ var _a, _b, _c;
94
+ return __generator(this, function (_d) {
95
+ switch (_d.label) {
96
+ case 0:
97
+ if (!(subCommand === CompileSingleFileSubCommands.Service)) return [3 /*break*/, 2];
98
+ return [4 /*yield*/, (0, internal_1.getAllFolders)(target, internal_1.SasFileType.Service)];
99
+ case 1: return [2 /*return*/, _d.sent()];
100
+ case 2:
101
+ if (!(subCommand === CompileSingleFileSubCommands.Job)) return [3 /*break*/, 4];
102
+ return [4 /*yield*/, (0, internal_1.getAllFolders)(target, internal_1.SasFileType.Job)];
103
+ case 3: return [2 /*return*/, _d.sent()];
104
+ case 4:
105
+ _a = [[]];
106
+ return [4 /*yield*/, (0, internal_1.getAllFolders)(target, internal_1.SasFileType.Service)];
107
+ case 5:
108
+ _b = [__spreadArray.apply(void 0, _a.concat([__read.apply(void 0, [(_d.sent())]), false]))];
109
+ return [4 /*yield*/, (0, internal_1.getAllFolders)(target, internal_1.SasFileType.Job)];
110
+ case 6:
111
+ _c = [__spreadArray.apply(void 0, _b.concat([__read.apply(void 0, [(_d.sent())]), false]))];
112
+ return [4 /*yield*/, (0, config_1.getMacroFolders)(target)];
113
+ case 7: return [2 /*return*/, __spreadArray.apply(void 0, _c.concat([__read.apply(void 0, [(_d.sent())]), false]))];
114
+ }
115
+ });
116
+ }); };
117
+ /** A test is filed under tests/services, tests/jobs or tests/macros. */
118
+ var getTestType = function (target, sourceFolder) { return __awaiter(void 0, void 0, void 0, function () {
119
+ var segments, testsIndex, fromPath, byType, _a, fromConfiguredFolders;
120
+ var _b, _c, _d;
121
+ var _e;
122
+ return __generator(this, function (_f) {
123
+ switch (_f.label) {
124
+ case 0:
125
+ segments = sourceFolder.split(path_1.default.sep);
126
+ testsIndex = segments.lastIndexOf('tests');
127
+ if (testsIndex !== -1) {
128
+ fromPath = segments[testsIndex + 1];
129
+ if (['services', 'jobs', 'macros'].includes(fromPath))
130
+ return [2 /*return*/, fromPath];
131
+ }
132
+ _b = {
133
+ type: 'services'
134
+ };
135
+ return [4 /*yield*/, (0, internal_1.getAllFolders)(target, internal_1.SasFileType.Service)];
136
+ case 1:
137
+ _a = [
138
+ (_b.folders = _f.sent(),
139
+ _b)
140
+ ];
141
+ _c = { type: 'jobs' };
142
+ return [4 /*yield*/, (0, internal_1.getAllFolders)(target, internal_1.SasFileType.Job)];
143
+ case 2:
144
+ _a = _a.concat([
145
+ (_c.folders = _f.sent(), _c)
146
+ ]);
147
+ _d = { type: 'macros' };
148
+ return [4 /*yield*/, (0, config_1.getMacroFolders)(target)];
149
+ case 3:
150
+ byType = _a.concat([
151
+ (_d.folders = _f.sent(), _d)
152
+ ]);
153
+ fromConfiguredFolders = (_e = byType.find(function (_a) {
154
+ var folders = _a.folders;
155
+ return getContainingFolder(folders, sourceFolder);
156
+ })) === null || _e === void 0 ? void 0 : _e.type;
157
+ if (!fromConfiguredFolders) {
158
+ throw new Error("Single file compilation failed. Cannot tell which test tree ".concat(sourceFolder, " belongs to - keep the test under a configured folder, or under tests/services, tests/jobs or tests/macros."));
159
+ }
160
+ return [2 /*return*/, fromConfiguredFolders];
161
+ }
162
+ });
163
+ }); };
164
+ /** The folder a file of this type is written under. */
165
+ var getTypeFolderName = function (subCommand, testType) {
166
+ switch (subCommand) {
167
+ case CompileSingleFileSubCommands.Job:
168
+ return 'jobs';
169
+ case CompileSingleFileSubCommands.Service:
170
+ return 'services';
171
+ case CompileSingleFileSubCommands.Test:
172
+ return path_1.default.posix.join('tests', testType);
173
+ default:
174
+ throw new Error("Single file compilation failed. Unsupported sub command: ".concat(subCommand));
175
+ }
176
+ };
177
+ /** The build folder a project compile uses for this type. */
178
+ var getBaseFolder = function (subCommand, testType) {
179
+ var _a = process.sasjsConstants, buildDestinationJobsFolder = _a.buildDestinationJobsFolder, buildDestinationServicesFolder = _a.buildDestinationServicesFolder, buildDestinationTestFolder = _a.buildDestinationTestFolder;
180
+ if (subCommand === CompileSingleFileSubCommands.Job)
181
+ return buildDestinationJobsFolder;
182
+ if (subCommand === CompileSingleFileSubCommands.Service)
183
+ return buildDestinationServicesFolder;
184
+ return path_1.default.join(buildDestinationTestFolder, testType);
185
+ };
58
186
  function compileSingleFile(target_1) {
59
187
  return __awaiter(this, arguments, void 0, function (target, subCommand, source, output, insertProgramVar, currentFolder) {
60
- var commandExample, sourcePath, outputPathParts, leafFolderName, parentOutputFolder, pathExists, sourceFileName, destinationPath, sourceFileNameWithoutExt, macroFolders, programFolders, psMaxOption, programVar, compileTree, sourceFolder, _a;
61
- var _b;
188
+ var commandExample, sourcePath, sourcePathParts, sourceFileName, sourceFileNameWithoutExt, sourceFolder, configuredFolders, configuredFolder, leafFolderName, relativeFolder, testType, _a, typeFolderName, destinationFolder, destinationPath, macroFolders, programFolders, psMaxOption, programFolder, programVar, compileTree, _b;
189
+ var _c;
62
190
  if (subCommand === void 0) { subCommand = 'identify'; }
63
191
  if (insertProgramVar === void 0) { insertProgramVar = false; }
64
- return __generator(this, function (_c) {
65
- switch (_c.label) {
192
+ return __generator(this, function (_d) {
193
+ switch (_d.label) {
66
194
  case 0:
67
195
  if (!isCompileSingleFileSubCommands(subCommand) &&
68
196
  subCommand !== 'identify') {
@@ -76,7 +204,7 @@ function compileSingleFile(target_1) {
76
204
  sourcePath = (0, utils_1.getAbsolutePath)(source, currentFolder || process.currentDir);
77
205
  return [4 /*yield*/, validateSourcePath(sourcePath)];
78
206
  case 1:
79
- if (!(_c.sent())) {
207
+ if (!(_d.sent())) {
80
208
  throw new Error("Provide a valid path to source file (eg '".concat(commandExample, "')"));
81
209
  }
82
210
  if (!(subCommand === 'identify')) return [3 /*break*/, 3];
@@ -84,68 +212,89 @@ function compileSingleFile(target_1) {
84
212
  throw (0, error_1.prefixMessage)(err, 'Single file compilation failed. ');
85
213
  })];
86
214
  case 2:
87
- subCommand = _c.sent();
88
- _c.label = 3;
215
+ subCommand = _d.sent();
216
+ _d.label = 3;
89
217
  case 3:
90
- (_b = process.logger) === null || _b === void 0 ? void 0 : _b.info("Compiling source file:\n- ".concat(sourcePath));
91
- outputPathParts = output.split(path_1.default.sep);
92
- (outputPathParts.pop(), outputPathParts.pop());
93
- leafFolderName = source.split(path_1.default.sep).pop();
94
- parentOutputFolder = outputPathParts.join(path_1.default.sep);
95
- return [4 /*yield*/, (0, utils_1.fileExists)(parentOutputFolder)];
218
+ (_c = process.logger) === null || _c === void 0 ? void 0 : _c.info("Compiling source file:\n- ".concat(sourcePath));
219
+ sourcePathParts = sourcePath.split(path_1.default.sep);
220
+ sourceFileName = sourcePathParts.pop();
221
+ sourceFileNameWithoutExt = sourceFileName.replace(/\.sas$/i, '');
222
+ sourceFolder = sourcePathParts.join(path_1.default.sep);
223
+ return [4 /*yield*/, getConfiguredFolders(target, subCommand)];
96
224
  case 4:
97
- pathExists = _c.sent();
98
- if (!pathExists) return [3 /*break*/, 6];
99
- return [4 /*yield*/, (0, utils_1.deleteFolder)(parentOutputFolder)];
225
+ configuredFolders = _d.sent();
226
+ configuredFolder = getContainingFolder(configuredFolders, sourceFolder);
227
+ leafFolderName = configuredFolder
228
+ ? path_1.default.basename(configuredFolder)
229
+ : configuredFolders.length
230
+ ? ''
231
+ : path_1.default.basename(sourceFolder);
232
+ relativeFolder = configuredFolder
233
+ ? path_1.default.relative(configuredFolder, sourceFolder)
234
+ : '';
235
+ if (!(subCommand === CompileSingleFileSubCommands.Test)) return [3 /*break*/, 6];
236
+ return [4 /*yield*/, getTestType(target, sourceFolder)];
100
237
  case 5:
101
- _c.sent();
102
- _c.label = 6;
103
- case 6: return [4 /*yield*/, (0, utils_1.createFolder)(output)];
238
+ _a = _d.sent();
239
+ return [3 /*break*/, 7];
240
+ case 6:
241
+ _a = undefined;
242
+ _d.label = 7;
104
243
  case 7:
105
- _c.sent();
106
- sourceFileName = sourcePath.split(path_1.default.sep).pop();
107
- destinationPath = path_1.default.join(output, sourceFileName);
108
- return [4 /*yield*/, (0, utils_1.copy)(sourcePath, destinationPath)];
244
+ testType = _a;
245
+ typeFolderName = getTypeFolderName(subCommand, testType);
246
+ destinationFolder = output
247
+ ? path_1.default.join(output, typeFolderName, leafFolderName, relativeFolder)
248
+ : path_1.default.join(getBaseFolder(subCommand, testType), leafFolderName, relativeFolder);
249
+ // Nothing is deleted: the folder is created if missing and the compiled file
250
+ // overwrites its previous copy, so siblings in the same leaf folder survive.
251
+ return [4 /*yield*/, (0, utils_1.createFolder)(destinationFolder)];
109
252
  case 8:
110
- _c.sent();
111
- sourceFileNameWithoutExt = sourceFileName.split('.')[0];
112
- return [4 /*yield*/, (0, config_1.getMacroFolders)(target)];
253
+ // Nothing is deleted: the folder is created if missing and the compiled file
254
+ // overwrites its previous copy, so siblings in the same leaf folder survive.
255
+ _d.sent();
256
+ destinationPath = path_1.default.join(destinationFolder, sourceFileName);
257
+ return [4 /*yield*/, (0, utils_1.copy)(sourcePath, destinationPath)];
113
258
  case 9:
114
- macroFolders = _c.sent();
115
- return [4 /*yield*/, (0, config_1.getProgramFolders)(target)];
259
+ _d.sent();
260
+ return [4 /*yield*/, (0, config_1.getMacroFolders)(target)];
116
261
  case 10:
117
- programFolders = _c.sent();
262
+ macroFolders = _d.sent();
263
+ return [4 /*yield*/, (0, config_1.getProgramFolders)(target)];
264
+ case 11:
265
+ programFolders = _d.sent();
118
266
  psMaxOption = 'options ps=max;';
267
+ programFolder = [typeFolderName, leafFolderName, relativeFolder]
268
+ .filter(Boolean)
269
+ .join('/')
270
+ .split(path_1.default.sep)
271
+ .join('/');
119
272
  programVar = insertProgramVar
120
- ? "%let _program=".concat(target.appLoc, "/").concat(subCommand, "s/").concat(leafFolderName, "/").concat(sourceFileNameWithoutExt, ";\n").concat(psMaxOption)
273
+ ? "%let _program=".concat(target.appLoc, "/").concat(programFolder, "/").concat(sourceFileNameWithoutExt, ";\n").concat(psMaxOption)
121
274
  : "".concat(psMaxOption);
122
275
  compileTree = (0, internal_1.getCompileTree)(target);
123
- sourceFolder = sourcePath
124
- .split(path_1.default.sep)
125
- .slice(0, sourcePath.split(path_1.default.sep).length - 1)
126
- .join(path_1.default.sep);
127
- _a = subCommand;
128
- switch (_a) {
129
- case CompileSingleFileSubCommands.Service: return [3 /*break*/, 11];
130
- case CompileSingleFileSubCommands.Job: return [3 /*break*/, 13];
131
- case CompileSingleFileSubCommands.Test: return [3 /*break*/, 15];
276
+ _b = subCommand;
277
+ switch (_b) {
278
+ case CompileSingleFileSubCommands.Service: return [3 /*break*/, 12];
279
+ case CompileSingleFileSubCommands.Job: return [3 /*break*/, 14];
280
+ case CompileSingleFileSubCommands.Test: return [3 /*break*/, 16];
132
281
  }
133
- return [3 /*break*/, 17];
134
- case 11: return [4 /*yield*/, (0, internal_1.compileFile)(target, destinationPath, macroFolders, programFolders, programVar, compileTree, utils_1.SASJsFileType.service, sourceFolder)];
135
- case 12:
136
- _c.sent();
137
- return [3 /*break*/, 17];
138
- case 13: return [4 /*yield*/, (0, internal_1.compileFile)(target, destinationPath, macroFolders, programFolders, programVar, compileTree, utils_1.SASJsFileType.job, sourceFolder)];
139
- case 14:
140
- _c.sent();
141
- return [3 /*break*/, 17];
142
- case 15: return [4 /*yield*/, (0, internal_1.compileTestFile)(target, sourcePath, programVar, undefined, false, compileTree, destinationPath)];
143
- case 16:
144
- _c.sent();
145
- return [3 /*break*/, 17];
146
- case 17: return [4 /*yield*/, compileTree.saveTree()];
147
- case 18:
148
- _c.sent();
282
+ return [3 /*break*/, 18];
283
+ case 12: return [4 /*yield*/, (0, internal_1.compileFile)(target, destinationPath, macroFolders, programFolders, programVar, compileTree, utils_1.SASJsFileType.service, sourceFolder)];
284
+ case 13:
285
+ _d.sent();
286
+ return [3 /*break*/, 18];
287
+ case 14: return [4 /*yield*/, (0, internal_1.compileFile)(target, destinationPath, macroFolders, programFolders, programVar, compileTree, utils_1.SASJsFileType.job, sourceFolder)];
288
+ case 15:
289
+ _d.sent();
290
+ return [3 /*break*/, 18];
291
+ case 16: return [4 /*yield*/, (0, internal_1.compileTestFile)(target, sourcePath, programVar, undefined, false, compileTree, destinationPath)];
292
+ case 17:
293
+ _d.sent();
294
+ return [3 /*break*/, 18];
295
+ case 18: return [4 /*yield*/, compileTree.saveTree()];
296
+ case 19:
297
+ _d.sent();
149
298
  return [2 /*return*/, { destinationPath: destinationPath }];
150
299
  }
151
300
  });
@@ -77,23 +77,25 @@ var getAllFolders = function (target, type, rootConfig) { return __awaiter(void
77
77
  allFolders = __spreadArray(__spreadArray([], __read((allFolders || [])), false), __read((folders || [])), false);
78
78
  };
79
79
  if (type === SasFileType.Service) {
80
- config = configuration.serviceConfig;
80
+ config = configuration === null || configuration === void 0 ? void 0 : configuration.serviceConfig;
81
81
  folders = config === null || config === void 0 ? void 0 : config.serviceFolders;
82
82
  addFolders(folders);
83
- config = target.serviceConfig;
83
+ config = target === null || target === void 0 ? void 0 : target.serviceConfig;
84
84
  folders = config === null || config === void 0 ? void 0 : config.serviceFolders;
85
85
  }
86
86
  else {
87
- config = configuration.jobConfig;
87
+ config = configuration === null || configuration === void 0 ? void 0 : configuration.jobConfig;
88
88
  folders = config === null || config === void 0 ? void 0 : config.jobFolders;
89
89
  addFolders(folders);
90
- config = target.jobConfig;
90
+ config = target === null || target === void 0 ? void 0 : target.jobConfig;
91
91
  folders = config === null || config === void 0 ? void 0 : config.jobFolders;
92
92
  }
93
93
  addFolders(folders);
94
94
  if (!allFolders)
95
95
  return [2 /*return*/, []];
96
96
  allFolders = allFolders.filter(function (p) { return !!p; });
97
+ if (!allFolders.length)
98
+ return [2 /*return*/, []];
97
99
  buildSourceFolder = process.sasjsConstants.buildSourceFolder;
98
100
  allFolders = allFolders.map(function (sasFile) {
99
101
  return (0, utils_1.getAbsolutePath)(sasFile, buildSourceFolder);
@@ -376,11 +376,9 @@ describe('sasjs compile single file', function () {
376
376
  '-s',
377
377
  './jobs/extract/makedata1.sas'
378
378
  ]);
379
- return [4 /*yield*/, command.output];
380
- case 1:
381
- output = _a.sent();
379
+ output = command.getOutputPath();
382
380
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(target, 'job', command.source, output)).toResolve()];
383
- case 2:
381
+ case 1:
384
382
  _a.sent();
385
383
  expect(compileFile.compileFile).toHaveBeenCalled();
386
384
  return [2 /*return*/];
@@ -400,11 +398,9 @@ describe('sasjs compile single file', function () {
400
398
  '-s',
401
399
  './jobs/extract/makedata1.sas'
402
400
  ]);
403
- return [4 /*yield*/, command.output];
404
- case 1:
405
- output = _a.sent();
401
+ output = command.getOutputPath();
406
402
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(target, 'job', command.source, output)).toResolve()];
407
- case 2:
403
+ case 1:
408
404
  _a.sent();
409
405
  expect(compileFile.compileFile).toHaveBeenCalled();
410
406
  return [2 /*return*/];
@@ -442,11 +438,9 @@ describe('sasjs compile single file', function () {
442
438
  '-s',
443
439
  'sasjs/services/common/example.sas'
444
440
  ]);
445
- return [4 /*yield*/, command.output];
446
- case 1:
447
- output = _a.sent();
441
+ output = command.getOutputPath();
448
442
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(target, 'service', command.source, output)).toResolve()];
449
- case 2:
443
+ case 1:
450
444
  _a.sent();
451
445
  expect(compileFile.compileFile).toHaveBeenCalled();
452
446
  return [2 /*return*/];
@@ -466,11 +460,9 @@ describe('sasjs compile single file', function () {
466
460
  '-s',
467
461
  "".concat(process.projectDir, "/sasjs/services/common/example.sas")
468
462
  ]);
469
- return [4 /*yield*/, command.output];
470
- case 1:
471
- output = _a.sent();
463
+ output = command.getOutputPath();
472
464
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(target, 'service', command.source, output)).toResolve()];
473
- case 2:
465
+ case 1:
474
466
  _a.sent();
475
467
  expect(compileFile.compileFile).toHaveBeenCalled();
476
468
  return [2 /*return*/];
@@ -598,7 +590,7 @@ describe('sasjs compile outside project', function () {
598
590
  '-s',
599
591
  '../services/example1.sas'
600
592
  ]);
601
- output = command.output;
593
+ output = command.getOutputPath();
602
594
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(undefined, 'service', command.source, output)).resolves.toEqual({
603
595
  destinationPath: destinationPath
604
596
  })];
@@ -647,19 +639,17 @@ describe('sasjs compile outside project', function () {
647
639
  '-s',
648
640
  '../services/example1.sas'
649
641
  ]);
650
- return [4 /*yield*/, command.output];
651
- case 2:
652
- output = _a.sent();
642
+ output = command.getOutputPath();
653
643
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(undefined, 'service', command.source, output)).resolves.toEqual({
654
644
  destinationPath: destinationPath
655
645
  })];
656
- case 3:
646
+ case 2:
657
647
  _a.sent();
658
648
  return [4 /*yield*/, expect((0, utils_1.fileExists)(destinationPath)).resolves.toEqual(true)];
659
- case 4:
649
+ case 3:
660
650
  _a.sent();
661
651
  return [4 /*yield*/, (0, utils_1.readFile)(destinationPath)];
662
- case 5:
652
+ case 4:
663
653
  compiledContent = _a.sent();
664
654
  macrosToTest = [
665
655
  'mf_nobs',
@@ -667,7 +657,7 @@ describe('sasjs compile outside project', function () {
667
657
  'yetanothermacro'
668
658
  ];
669
659
  return [4 /*yield*/, (0, test_1.verifyCompiledService)(compiledContent, macrosToTest, false, false)];
670
- case 6:
660
+ case 5:
671
661
  _a.sent();
672
662
  return [2 /*return*/];
673
663
  }
@@ -698,11 +688,9 @@ describe('sasjs compile outside project', function () {
698
688
  '-s',
699
689
  '../services/example1.sas'
700
690
  ]);
701
- return [4 /*yield*/, command.output];
702
- case 3:
703
- output = _a.sent();
691
+ output = command.getOutputPath();
704
692
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(undefined, 'service', command.source, output)).rejects.toEqual("Unable to locate dependencies: ".concat(dependencies.join(', ')))];
705
- case 4:
693
+ case 3:
706
694
  _a.sent();
707
695
  return [2 /*return*/];
708
696
  }
@@ -736,19 +724,17 @@ describe('sasjs compile outside project', function () {
736
724
  '-s',
737
725
  '../services/example1.sas'
738
726
  ]);
739
- return [4 /*yield*/, command.output];
740
- case 4:
741
- output = _a.sent();
727
+ output = command.getOutputPath();
742
728
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(undefined, 'service', command.source, output)).resolves.toEqual({
743
729
  destinationPath: destinationPath
744
730
  })];
745
- case 5:
731
+ case 4:
746
732
  _a.sent();
747
733
  return [4 /*yield*/, expect((0, utils_1.fileExists)(destinationPath)).resolves.toEqual(true)];
748
- case 6:
734
+ case 5:
749
735
  _a.sent();
750
736
  return [4 /*yield*/, (0, utils_1.readFile)(destinationPath)];
751
- case 7:
737
+ case 6:
752
738
  compiledContent = _a.sent();
753
739
  macrosToTest = [
754
740
  'mf_nobs',
@@ -756,7 +742,7 @@ describe('sasjs compile outside project', function () {
756
742
  'yetanothermacro'
757
743
  ];
758
744
  return [4 /*yield*/, (0, test_1.verifyCompiledService)(compiledContent, macrosToTest, false, false)];
759
- case 8:
745
+ case 7:
760
746
  _a.sent();
761
747
  return [2 /*return*/];
762
748
  }
@@ -790,19 +776,17 @@ describe('sasjs compile outside project', function () {
790
776
  '-s',
791
777
  '../services/example1.sas'
792
778
  ]);
793
- return [4 /*yield*/, command.output];
794
- case 4:
795
- output = _a.sent();
779
+ output = command.getOutputPath();
796
780
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(undefined, 'service', command.source, output)).resolves.toEqual({
797
781
  destinationPath: destinationPath
798
782
  })];
799
- case 5:
783
+ case 4:
800
784
  _a.sent();
801
785
  return [4 /*yield*/, expect((0, utils_1.fileExists)(destinationPath)).resolves.toEqual(true)];
802
- case 6:
786
+ case 5:
803
787
  _a.sent();
804
788
  return [4 /*yield*/, (0, utils_1.readFile)(destinationPath)];
805
- case 7:
789
+ case 6:
806
790
  compiledContent = _a.sent();
807
791
  macrosToTest = [
808
792
  'mf_nobs',
@@ -810,7 +794,7 @@ describe('sasjs compile outside project', function () {
810
794
  'yetanothermacro'
811
795
  ];
812
796
  return [4 /*yield*/, (0, test_1.verifyCompiledService)(compiledContent, macrosToTest, false, false)];
813
- case 8:
797
+ case 7:
814
798
  _a.sent();
815
799
  return [2 /*return*/];
816
800
  }
@@ -863,11 +847,9 @@ describe('sasjs compile outside project', function () {
863
847
  '-s',
864
848
  '../services/example1.sas'
865
849
  ]);
866
- return [4 /*yield*/, command.output];
867
- case 1:
868
- output = _a.sent();
850
+ output = command.getOutputPath();
869
851
  return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)(undefined, 'service', command.source, output)).rejects.toEqual("Unable to locate dependencies: ".concat(dependencies.join(', ')))];
870
- case 2:
852
+ case 1:
871
853
  _a.sent();
872
854
  return [2 /*return*/];
873
855
  }
@@ -101,6 +101,8 @@ var path_1 = __importDefault(require("path"));
101
101
  var os_1 = __importDefault(require("os"));
102
102
  var compileModule = __importStar(require("../compile"));
103
103
  var compileSingleFileModule = __importStar(require("../compileSingleFile"));
104
+ var identifySasFileModule = __importStar(require("../internal/identifySasFile"));
105
+ var internal_1 = require("../internal");
104
106
  var compileCommand_1 = require("../compileCommand");
105
107
  var utils_1 = require("@sasjs/utils");
106
108
  var utils_2 = require("../../../utils");
@@ -334,7 +336,7 @@ describe('CompileCommand', function () {
334
336
  expectedTarget[key] = target[key];
335
337
  });
336
338
  delete expectedTarget.getConfig;
337
- expect(compileSingleFileModule.compileSingleFile).toHaveBeenCalledWith(expect.objectContaining(expectedTarget), 'job', path_1.default.join(os_1.default.homedir(), 'test.sas'), expect.anything());
339
+ expect(compileSingleFileModule.compileSingleFile).toHaveBeenCalledWith(expect.objectContaining(expectedTarget), 'job', path_1.default.join(os_1.default.homedir(), 'test.sas'), undefined);
338
340
  return [2 /*return*/];
339
341
  }
340
342
  });
@@ -388,7 +390,7 @@ describe('CompileCommand', function () {
388
390
  }
389
391
  });
390
392
  }); });
391
- it('should return the output path for a job when specified', function () {
393
+ it('should return the output base for a job when specified', function () {
392
394
  var args = __spreadArray(__spreadArray([], __read(defaultArgs), false), [
393
395
  'compile',
394
396
  'job',
@@ -400,10 +402,11 @@ describe('CompileCommand', function () {
400
402
  os_1.default.homedir()
401
403
  ], false);
402
404
  var command = new compileCommand_1.CompileCommand(args);
403
- var output = command.output;
404
- expect(output).toEqual(path_1.default.join(os_1.default.homedir(), 'jobs'));
405
+ // the base only - the type folder and the file's own path are added by
406
+ // compileSingleFile
407
+ expect(command.getOutputPath()).toEqual(os_1.default.homedir());
405
408
  });
406
- it('should return the output path for a service when specified', function () {
409
+ it('should return the output base for a service when specified', function () {
407
410
  var args = __spreadArray(__spreadArray([], __read(defaultArgs), false), [
408
411
  'compile',
409
412
  'service',
@@ -415,10 +418,9 @@ describe('CompileCommand', function () {
415
418
  os_1.default.homedir()
416
419
  ], false);
417
420
  var command = new compileCommand_1.CompileCommand(args);
418
- var output = command.output;
419
- expect(output).toEqual(path_1.default.join(os_1.default.homedir(), 'services'));
421
+ expect(command.getOutputPath()).toEqual(os_1.default.homedir());
420
422
  });
421
- it('should return the output path for a job when not specified', function () {
423
+ it('should leave the destination to the compile when not specified', function () {
422
424
  var args = __spreadArray(__spreadArray([], __read(defaultArgs), false), [
423
425
  'compile',
424
426
  'job',
@@ -427,12 +429,11 @@ describe('CompileCommand', function () {
427
429
  '-s',
428
430
  '/dev/test.sas'
429
431
  ], false);
430
- var buildDestinationJobsFolder = process.sasjsConstants.buildDestinationJobsFolder;
431
432
  var command = new compileCommand_1.CompileCommand(args);
432
- var output = command.output;
433
- expect(output).toEqual(path_1.default.join(buildDestinationJobsFolder, 'dev'));
433
+ // the default for the type lives in compileSingleFile, not here
434
+ expect(command.getOutputPath()).toBeUndefined();
434
435
  });
435
- it('should return the output path for a service when not specified', function () {
436
+ it('should leave the destination to the compile for a service too', function () {
436
437
  var args = __spreadArray(__spreadArray([], __read(defaultArgs), false), [
437
438
  'compile',
438
439
  'service',
@@ -441,11 +442,64 @@ describe('CompileCommand', function () {
441
442
  '-s',
442
443
  '/dev/test.sas'
443
444
  ], false);
444
- var buildDestinationServicesFolder = process.sasjsConstants.buildDestinationServicesFolder;
445
445
  var command = new compileCommand_1.CompileCommand(args);
446
- var output = command.output;
447
- expect(output).toEqual(path_1.default.join(buildDestinationServicesFolder, 'dev'));
446
+ expect(command.getOutputPath()).toBeUndefined();
448
447
  });
448
+ it('should pass identify through for a job source', function () { return __awaiter(void 0, void 0, void 0, function () {
449
+ var args, command;
450
+ return __generator(this, function (_a) {
451
+ switch (_a.label) {
452
+ case 0:
453
+ jest
454
+ .spyOn(identifySasFileModule, 'identifySasFile')
455
+ .mockImplementation(function () { return Promise.resolve(internal_1.SasFileType.Job); });
456
+ args = __spreadArray(__spreadArray([], __read(defaultArgs), false), [
457
+ 'compile',
458
+ 'identify',
459
+ '-t',
460
+ 'test',
461
+ '-s',
462
+ '/dev/test.sas'
463
+ ], false);
464
+ command = new compileCommand_1.CompileCommand(args);
465
+ return [4 /*yield*/, command.execute()
466
+ // the type is left to compileSingleFile, which is the only place that
467
+ // resolves 'identify'
468
+ ];
469
+ case 1:
470
+ _a.sent();
471
+ // the type is left to compileSingleFile, which is the only place that
472
+ // resolves 'identify'
473
+ expect(compileSingleFileModule.compileSingleFile).toHaveBeenCalledWith(expect.anything(), 'identify', '/dev/test.sas', undefined);
474
+ return [2 /*return*/];
475
+ }
476
+ });
477
+ }); });
478
+ it('should pass identify through for a service source', function () { return __awaiter(void 0, void 0, void 0, function () {
479
+ var args, command;
480
+ return __generator(this, function (_a) {
481
+ switch (_a.label) {
482
+ case 0:
483
+ jest
484
+ .spyOn(identifySasFileModule, 'identifySasFile')
485
+ .mockImplementation(function () { return Promise.resolve(internal_1.SasFileType.Service); });
486
+ args = __spreadArray(__spreadArray([], __read(defaultArgs), false), [
487
+ 'compile',
488
+ 'identify',
489
+ '-t',
490
+ 'test',
491
+ '-s',
492
+ '/dev/test.sas'
493
+ ], false);
494
+ command = new compileCommand_1.CompileCommand(args);
495
+ return [4 /*yield*/, command.execute()];
496
+ case 1:
497
+ _a.sent();
498
+ expect(compileSingleFileModule.compileSingleFile).toHaveBeenCalledWith(expect.anything(), 'identify', '/dev/test.sas', undefined);
499
+ return [2 /*return*/];
500
+ }
501
+ });
502
+ }); });
449
503
  });
450
504
  var setupMocks = function () {
451
505
  jest.resetAllMocks();
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
2
13
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
14
  if (k2 === undefined) k2 = k;
4
15
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -68,13 +79,21 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
68
79
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
69
80
  }
70
81
  };
82
+ var __importDefault = (this && this.__importDefault) || function (mod) {
83
+ return (mod && mod.__esModule) ? mod : { "default": mod };
84
+ };
71
85
  Object.defineProperty(exports, "__esModule", { value: true });
86
+ var path_1 = __importDefault(require("path"));
87
+ var fs_1 = __importDefault(require("fs"));
88
+ var os_1 = __importDefault(require("os"));
72
89
  var compileSingleFile_1 = require("../compileSingleFile");
73
90
  var identifySasFileModule = __importStar(require("../internal/identifySasFile"));
74
91
  var fileModule = __importStar(require("@sasjs/utils/file"));
75
92
  var configModule = __importStar(require("../../../utils/config"));
76
93
  var loadDependenciesModule = __importStar(require("../internal/loadDependencies"));
77
94
  var compileTestFileModule = __importStar(require("../internal/compileTestFile"));
95
+ var compileFileModule = __importStar(require("../internal/compileFile"));
96
+ var getAllFoldersModule = __importStar(require("../internal/getAllFolders"));
78
97
  var internal_1 = require("../internal");
79
98
  describe('compileSingleFile', function () {
80
99
  it('should throw an error provided not supported subcommand', function () { return __awaiter(void 0, void 0, void 0, function () {
@@ -140,6 +159,9 @@ describe('compileSingleFile', function () {
140
159
  jest
141
160
  .spyOn(compileTestFileModule, 'compileTestFile')
142
161
  .mockImplementation(function () { return Promise.resolve(); });
162
+ jest
163
+ .spyOn(getAllFoldersModule, 'getAllFolders')
164
+ .mockImplementation(function () { return Promise.resolve(['testCurrentDir']); });
143
165
  jest.spyOn(identifySasFileModule, 'identifySasFile');
144
166
  return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({}, 'identify', testFile, 'testOutput', false, 'testCurrentDir')];
145
167
  case 1:
@@ -169,4 +191,296 @@ describe('compileSingleFile', function () {
169
191
  }
170
192
  });
171
193
  }); });
194
+ describe('destination folder', function () {
195
+ var projectRoot = 'project';
196
+ var originalConstants = process.sasjsConstants;
197
+ var source = path_1.default.join('sasjs', 'jobs', 'daily', 'myjob.sas');
198
+ beforeEach(function () {
199
+ process.sasjsConstants = {
200
+ buildDestinationJobsFolder: path_1.default.join('project', 'sasjsbuild', 'jobs'),
201
+ buildDestinationServicesFolder: path_1.default.join('project', 'sasjsbuild', 'services')
202
+ };
203
+ jest.spyOn(fileModule, 'fileExists').mockResolvedValue(true);
204
+ jest.spyOn(fileModule, 'deleteFolder').mockResolvedValue(undefined);
205
+ jest.spyOn(fileModule, 'createFolder').mockResolvedValue(undefined);
206
+ jest.spyOn(fileModule, 'copy').mockResolvedValue(undefined);
207
+ jest
208
+ .spyOn(configModule, 'getMacroFolders')
209
+ .mockImplementation(function () { return Promise.resolve([]); });
210
+ jest
211
+ .spyOn(configModule, 'getProgramFolders')
212
+ .mockImplementation(function () { return Promise.resolve([]); });
213
+ jest
214
+ .spyOn(loadDependenciesModule, 'getCompileTree')
215
+ .mockImplementation(function () { return ({ saveTree: function () { return Promise.resolve(); } }); });
216
+ jest
217
+ .spyOn(getAllFoldersModule, 'getAllFolders')
218
+ .mockImplementation(function (_target, type) {
219
+ return Promise.resolve(type === 'job'
220
+ ? [path_1.default.join(projectRoot, 'sasjs', 'jobs', 'daily')]
221
+ : [path_1.default.join(projectRoot, 'sasjs', 'services', 'example')]);
222
+ });
223
+ jest
224
+ .spyOn(compileFileModule, 'compileFile')
225
+ .mockImplementation(function () { return Promise.resolve(); });
226
+ jest
227
+ .spyOn(compileTestFileModule, 'compileTestFile')
228
+ .mockImplementation(function () { return Promise.resolve(); });
229
+ });
230
+ afterEach(function () {
231
+ process.sasjsConstants = originalConstants;
232
+ });
233
+ it('should send an identified job to the jobs folder', function () { return __awaiter(void 0, void 0, void 0, function () {
234
+ var destinationPath;
235
+ return __generator(this, function (_a) {
236
+ switch (_a.label) {
237
+ case 0:
238
+ jest
239
+ .spyOn(identifySasFileModule, 'identifySasFile')
240
+ .mockImplementation(function () { return Promise.resolve(internal_1.SasFileType.Job); });
241
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({}, 'identify', source, undefined, false, projectRoot)];
242
+ case 1:
243
+ destinationPath = (_a.sent()).destinationPath;
244
+ expect(destinationPath).toEqual(path_1.default.join('project', 'sasjsbuild', 'jobs', 'daily', 'myjob.sas'));
245
+ return [2 /*return*/];
246
+ }
247
+ });
248
+ }); });
249
+ it('should send an identified service to the services folder', function () { return __awaiter(void 0, void 0, void 0, function () {
250
+ var serviceSource, destinationPath;
251
+ return __generator(this, function (_a) {
252
+ switch (_a.label) {
253
+ case 0:
254
+ jest
255
+ .spyOn(identifySasFileModule, 'identifySasFile')
256
+ .mockImplementation(function () { return Promise.resolve(internal_1.SasFileType.Service); });
257
+ serviceSource = path_1.default.join('sasjs', 'services', 'example', 'myService.sas');
258
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({}, 'identify', serviceSource, undefined, false, projectRoot)];
259
+ case 1:
260
+ destinationPath = (_a.sent()).destinationPath;
261
+ expect(destinationPath).toEqual(path_1.default.join('project', 'sasjsbuild', 'services', 'example', 'myService.sas'));
262
+ return [2 /*return*/];
263
+ }
264
+ });
265
+ }); });
266
+ it('should point _program at the leaf folder of the source', function () { return __awaiter(void 0, void 0, void 0, function () {
267
+ var compileFileSpy, programVar;
268
+ return __generator(this, function (_a) {
269
+ switch (_a.label) {
270
+ case 0:
271
+ compileFileSpy = jest
272
+ .spyOn(compileFileModule, 'compileFile')
273
+ .mockImplementation(function () { return Promise.resolve(); });
274
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({ appLoc: '/Public/app' }, 'job', source, undefined, true, projectRoot)];
275
+ case 1:
276
+ _a.sent();
277
+ programVar = compileFileSpy.mock.calls[0][4];
278
+ expect(programVar).toContain('%let _program=/Public/app/jobs/daily/myjob;');
279
+ return [2 /*return*/];
280
+ }
281
+ });
282
+ }); });
283
+ it('should file a test under tests/<where the test lives>', function () { return __awaiter(void 0, void 0, void 0, function () {
284
+ var serviceTest, destinationPath;
285
+ return __generator(this, function (_a) {
286
+ switch (_a.label) {
287
+ case 0:
288
+ serviceTest = path_1.default.join('sasjs', 'services', 'example', 'check.test.sas');
289
+ process.sasjsConstants = __assign(__assign({}, process.sasjsConstants), { buildDestinationTestFolder: path_1.default.join('project', 'sasjsbuild', 'tests') });
290
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({}, 'test', serviceTest, undefined, false, projectRoot)];
291
+ case 1:
292
+ destinationPath = (_a.sent()).destinationPath;
293
+ expect(destinationPath).toEqual(path_1.default.join('project', 'sasjsbuild', 'tests', 'services', 'example', 'check.test.sas'));
294
+ return [2 /*return*/];
295
+ }
296
+ });
297
+ }); });
298
+ it('should take the test kind from a tests/<type> path', function () { return __awaiter(void 0, void 0, void 0, function () {
299
+ var destinationPath;
300
+ return __generator(this, function (_a) {
301
+ switch (_a.label) {
302
+ case 0:
303
+ process.sasjsConstants = __assign(__assign({}, process.sasjsConstants), { buildDestinationTestFolder: path_1.default.join('project', 'sasjsbuild', 'tests') });
304
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({}, 'test', path_1.default.join('sasjs', 'tests', 'jobs', 'load.test.sas'), undefined, false, projectRoot)];
305
+ case 1:
306
+ destinationPath = (_a.sent()).destinationPath;
307
+ expect(destinationPath).toEqual(path_1.default.join('project', 'sasjsbuild', 'tests', 'jobs', 'load.test.sas'));
308
+ return [2 /*return*/];
309
+ }
310
+ });
311
+ }); });
312
+ it('should write below the output base when one is given', function () { return __awaiter(void 0, void 0, void 0, function () {
313
+ var destinationPath;
314
+ return __generator(this, function (_a) {
315
+ switch (_a.label) {
316
+ case 0: return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({}, 'job', source, path_1.default.join('/tmp', 'out'), false, projectRoot)];
317
+ case 1:
318
+ destinationPath = (_a.sent()).destinationPath;
319
+ expect(destinationPath).toEqual(path_1.default.join('/tmp', 'out', 'jobs', 'daily', 'myjob.sas'));
320
+ return [2 /*return*/];
321
+ }
322
+ });
323
+ }); });
324
+ it('should keep a dotted file name in _program', function () { return __awaiter(void 0, void 0, void 0, function () {
325
+ var compileFileSpy;
326
+ return __generator(this, function (_a) {
327
+ switch (_a.label) {
328
+ case 0:
329
+ compileFileSpy = jest
330
+ .spyOn(compileFileModule, 'compileFile')
331
+ .mockImplementation(function () { return Promise.resolve(); });
332
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({ appLoc: '/Public/app' }, 'job', path_1.default.join('sasjs', 'jobs', 'daily', 'load.daily.sas'), undefined, true, projectRoot)];
333
+ case 1:
334
+ _a.sent();
335
+ expect(compileFileSpy.mock.calls[0][4]).toContain('%let _program=/Public/app/jobs/daily/load.daily;');
336
+ return [2 /*return*/];
337
+ }
338
+ });
339
+ }); });
340
+ it('should refuse a sub command it does not know', function () { return __awaiter(void 0, void 0, void 0, function () {
341
+ return __generator(this, function (_a) {
342
+ switch (_a.label) {
343
+ case 0:
344
+ jest
345
+ .spyOn(identifySasFileModule, 'identifySasFile')
346
+ .mockImplementation(function () { return Promise.resolve('nonsense'); });
347
+ return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)({}, 'identify', source, undefined, false, projectRoot)).rejects.toThrow('Single file compilation failed. Unsupported sub command: nonsense')];
348
+ case 1:
349
+ _a.sent();
350
+ return [2 /*return*/];
351
+ }
352
+ });
353
+ }); });
354
+ it('should refuse a test it cannot file under any tree', function () { return __awaiter(void 0, void 0, void 0, function () {
355
+ return __generator(this, function (_a) {
356
+ switch (_a.label) {
357
+ case 0: return [4 /*yield*/, expect((0, compileSingleFile_1.compileSingleFile)({}, 'test', path_1.default.join('elsewhere', 'loose.test.sas'), undefined, false, projectRoot)).rejects.toThrow(/Cannot tell which test tree/)];
358
+ case 1:
359
+ _a.sent();
360
+ return [2 /*return*/];
361
+ }
362
+ });
363
+ }); });
364
+ it('should delete nothing, so sibling compiled files survive', function () { return __awaiter(void 0, void 0, void 0, function () {
365
+ var deleteFolderSpy, createFolderSpy;
366
+ return __generator(this, function (_a) {
367
+ switch (_a.label) {
368
+ case 0:
369
+ deleteFolderSpy = jest.spyOn(fileModule, 'deleteFolder');
370
+ createFolderSpy = jest.spyOn(fileModule, 'createFolder');
371
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({}, 'job', source, undefined, false, projectRoot)];
372
+ case 1:
373
+ _a.sent();
374
+ expect(deleteFolderSpy).not.toHaveBeenCalled();
375
+ // the folder is created if missing (mkdir is recursive and idempotent)
376
+ expect(createFolderSpy).toHaveBeenCalledWith(path_1.default.join('project', 'sasjsbuild', 'jobs', 'daily'));
377
+ return [2 /*return*/];
378
+ }
379
+ });
380
+ }); });
381
+ });
382
+ describe('sibling files on disk', function () {
383
+ var originalConstants = process.sasjsConstants;
384
+ var root;
385
+ beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () {
386
+ return __generator(this, function (_a) {
387
+ switch (_a.label) {
388
+ case 0:
389
+ jest.restoreAllMocks();
390
+ return [4 /*yield*/, fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'sasjs-single-'))];
391
+ case 1:
392
+ root = _a.sent();
393
+ process.sasjsConstants = {
394
+ buildDestinationJobsFolder: path_1.default.join(root, 'sasjsbuild', 'jobs'),
395
+ buildDestinationServicesFolder: path_1.default.join(root, 'sasjsbuild', 'services')
396
+ };
397
+ jest
398
+ .spyOn(configModule, 'getMacroFolders')
399
+ .mockImplementation(function () { return Promise.resolve([]); });
400
+ jest
401
+ .spyOn(configModule, 'getProgramFolders')
402
+ .mockImplementation(function () { return Promise.resolve([]); });
403
+ jest
404
+ .spyOn(loadDependenciesModule, 'getCompileTree')
405
+ .mockImplementation(function () { return ({ saveTree: function () { return Promise.resolve(); } }); });
406
+ jest
407
+ .spyOn(getAllFoldersModule, 'getAllFolders')
408
+ .mockImplementation(function () {
409
+ return Promise.resolve([path_1.default.join(root, 'sasjs', 'jobs', 'daily')]);
410
+ });
411
+ jest
412
+ .spyOn(compileFileModule, 'compileFile')
413
+ .mockImplementation(function () { return Promise.resolve(); });
414
+ return [2 /*return*/];
415
+ }
416
+ });
417
+ }); });
418
+ afterEach(function () { return __awaiter(void 0, void 0, void 0, function () {
419
+ return __generator(this, function (_a) {
420
+ switch (_a.label) {
421
+ case 0:
422
+ process.sasjsConstants = originalConstants;
423
+ return [4 /*yield*/, fs_1.default.promises.rm(root, { recursive: true, force: true })];
424
+ case 1:
425
+ _a.sent();
426
+ return [2 /*return*/];
427
+ }
428
+ });
429
+ }); });
430
+ it('should keep a sibling compiled file in the same leaf folder', function () { return __awaiter(void 0, void 0, void 0, function () {
431
+ var sourceFolder, written;
432
+ return __generator(this, function (_a) {
433
+ switch (_a.label) {
434
+ case 0:
435
+ sourceFolder = path_1.default.join(root, 'sasjs', 'jobs', 'daily');
436
+ return [4 /*yield*/, fs_1.default.promises.mkdir(sourceFolder, { recursive: true })];
437
+ case 1:
438
+ _a.sent();
439
+ return [4 /*yield*/, fs_1.default.promises.writeFile(path_1.default.join(sourceFolder, 'first.sas'), '/**\n @file first.sas\n**/\n')];
440
+ case 2:
441
+ _a.sent();
442
+ return [4 /*yield*/, fs_1.default.promises.writeFile(path_1.default.join(sourceFolder, 'second.sas'), '/**\n @file second.sas\n**/\n')];
443
+ case 3:
444
+ _a.sent();
445
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({}, 'job', path_1.default.join(sourceFolder, 'first.sas'))];
446
+ case 4:
447
+ _a.sent();
448
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({}, 'job', path_1.default.join(sourceFolder, 'second.sas'))];
449
+ case 5:
450
+ _a.sent();
451
+ return [4 /*yield*/, fs_1.default.promises.readdir(path_1.default.join(root, 'sasjsbuild', 'jobs', 'daily'))];
452
+ case 6:
453
+ written = _a.sent();
454
+ expect(written.sort()).toEqual(['first.sas', 'second.sas']);
455
+ return [2 /*return*/];
456
+ }
457
+ });
458
+ }); });
459
+ it('should point _program at the folder the file is written to', function () { return __awaiter(void 0, void 0, void 0, function () {
460
+ var compileFileSpy, sourceFile, _a;
461
+ return __generator(this, function (_b) {
462
+ switch (_b.label) {
463
+ case 0:
464
+ compileFileSpy = jest.spyOn(compileFileModule, 'compileFile');
465
+ sourceFile = path_1.default.join(root, 'loose.sas');
466
+ return [4 /*yield*/, fs_1.default.promises.writeFile(sourceFile, '/**\n @file loose.sas\n**/\n')];
467
+ case 1:
468
+ _b.sent();
469
+ return [4 /*yield*/, (0, compileSingleFile_1.compileSingleFile)({ appLoc: '/Public/app' }, 'job', sourceFile, undefined, true)
470
+ // not below a configured folder, so it lands in the type folder itself
471
+ ];
472
+ case 2:
473
+ _b.sent();
474
+ // not below a configured folder, so it lands in the type folder itself
475
+ _a = expect;
476
+ return [4 /*yield*/, fs_1.default.promises.readFile(path_1.default.join(root, 'sasjsbuild', 'jobs', 'loose.sas'), 'utf8')];
477
+ case 3:
478
+ // not below a configured folder, so it lands in the type folder itself
479
+ _a.apply(void 0, [_b.sent()]).toBeDefined();
480
+ expect(compileFileSpy.mock.calls[0][4]).toContain('%let _program=/Public/app/jobs/loose;');
481
+ return [2 /*return*/];
482
+ }
483
+ });
484
+ }); });
485
+ });
172
486
  });
@@ -92,9 +92,12 @@ function printHelpText() {
92
92
  },
93
93
  {
94
94
  name: 'compile',
95
- title: 'compile <targetName>',
95
+ title: 'compile [subCommand]',
96
96
  description: [
97
- "compiles the services specified in the ".concat(chalk_1.default.cyanBright('serviceFolders'), " property of the 'serviceConfig' in your target and common configuration.")
97
+ "compiles the services specified in the ".concat(chalk_1.default.cyanBright('serviceFolders'), " property of the 'serviceConfig' in your target and common configuration."),
98
+ "A single file is compiled by naming its type as a sub command - ".concat(chalk_1.default.cyanBright('job'), ", ").concat(chalk_1.default.cyanBright('service'), ", ").concat(chalk_1.default.cyanBright('test'), " or ").concat(chalk_1.default.cyanBright('identify'), ", which works the type out from the file itself - together with ").concat(chalk_1.default.cyanBright('--source'), " (or ").concat(chalk_1.default.cyanBright('-s'), ")."),
99
+ "The compiled file is written to the ".concat(chalk_1.default.cyanBright('jobs'), " or ").concat(chalk_1.default.cyanBright('services'), " folder of sasjsbuild for its type, or below ").concat(chalk_1.default.cyanBright('--output'), " (or ").concat(chalk_1.default.cyanBright('-o'), ") when given."),
100
+ "command example: sasjs compile identify --source sasjs/jobs/daily/load.sas --target myTarget"
98
101
  ]
99
102
  },
100
103
  {
@@ -72,7 +72,6 @@ var utils_1 = require("@sasjs/utils");
72
72
  var __1 = require("../");
73
73
  var utils_2 = require("../../utils/");
74
74
  var axios_1 = __importDefault(require("axios"));
75
- var internal_1 = require("../compile/internal");
76
75
  var saveLog_1 = require("../../utils/saveLog");
77
76
  var parseSourceFile_1 = require("../../utils/parseSourceFile");
78
77
  /**
@@ -84,7 +83,7 @@ var parseSourceFile_1 = require("../../utils/parseSourceFile");
84
83
  */
85
84
  function runSasCode(target_1, filePath_1) {
86
85
  return __awaiter(this, arguments, void 0, function (target, filePath, compile, logFile, source) {
87
- var isTempFile, sourcefilePathParts, sourceFolderPath, sasFilePath, sasFileContent, linesToExecute, macroVars, macroVarStatements, _a;
86
+ var isTempFile, sasFilePath, sasFileContent, linesToExecute, macroVars, macroVarStatements, _a;
88
87
  var _b;
89
88
  var _c;
90
89
  if (compile === void 0) { compile = false; }
@@ -101,10 +100,8 @@ function runSasCode(target_1, filePath_1) {
101
100
  case 2:
102
101
  if (!compile) return [3 /*break*/, 5];
103
102
  if (!/\.sas$/i.test(filePath)) return [3 /*break*/, 4];
104
- sourcefilePathParts = path_1.default.normalize(filePath).split(path_1.default.sep);
105
- sourcefilePathParts.splice(-1, 1);
106
- sourceFolderPath = sourcefilePathParts.join(path_1.default.sep);
107
- return [4 /*yield*/, (0, __1.compileSingleFile)(target, 'identify', filePath, (0, internal_1.getDestinationServicePath)(sourceFolderPath), true)];
103
+ ;
104
+ return [4 /*yield*/, (0, __1.compileSingleFile)(target, 'identify', filePath, undefined, true)];
108
105
  case 3:
109
106
  (filePath = (_d.sent()).destinationPath);
110
107
  (_c = process.logger) === null || _c === void 0 ? void 0 : _c.success("File Compiled and placed at: ".concat(filePath, " ."));
package/package.json CHANGED
@@ -126,5 +126,5 @@
126
126
  "peerDependencies": {
127
127
  "@sasjs/lint": "^4.4.0"
128
128
  },
129
- "version": "6.2.4"
129
+ "version": "6.2.5"
130
130
  }