at-builder 1.2.8 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,342 +1,804 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
39
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
40
+ if (ar || !(i in from)) {
41
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
42
+ ar[i] = from[i];
43
+ }
44
+ }
45
+ return to.concat(ar || Array.prototype.slice.call(from));
46
+ };
2
47
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
48
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
49
  };
5
50
  Object.defineProperty(exports, "__esModule", { value: true });
6
51
  exports.fixIssues = exports.runDiagnostics = void 0;
7
- const path_1 = __importDefault(require("path"));
8
- const fs_1 = __importDefault(require("fs"));
9
- const logger_1 = __importDefault(require("./logger"));
52
+ var path_1 = __importDefault(require("path"));
53
+ var fs_1 = __importDefault(require("fs"));
54
+ var logger_1 = __importDefault(require("./logger"));
55
+ var config_1 = require("../constants/config");
56
+ // lib/install-checks.js is hand-written runtime JS (not TS-compiled). The
57
+ // relative path resolves correctly from both src/services/doctor.ts (source)
58
+ // and bin/services/doctor.js (compiled output) because src/ and bin/ have
59
+ // parallel structure. Typed inline since the module isn't part of the TS graph.
60
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
61
+ var installChecks = require("../../lib/install-checks");
10
62
  /**
11
63
  * Run comprehensive diagnostics on the project
12
64
  */
13
- const runDiagnostics = async (projectPath, verbose = false) => {
14
- const issues = [];
15
- if (verbose)
16
- logger_1.default.info("runDiagnostics", `Running diagnostics on ${projectPath}`);
17
- // Check for required files
18
- await checkEnvFile(projectPath, issues);
19
- await checkAdobeConfig(projectPath, issues);
20
- await checkWatchConfig(projectPath, issues);
21
- await checkPackageJson(projectPath, issues);
22
- await checkActivitiesFolder(projectPath, issues);
23
- // Check environment variables
24
- await checkEnvVariables(projectPath, issues);
25
- // Check dependencies
26
- await checkDependencies(projectPath, issues);
27
- return issues;
65
+ var runDiagnostics = function (projectPath_1) {
66
+ var args_1 = [];
67
+ for (var _i = 1; _i < arguments.length; _i++) {
68
+ args_1[_i - 1] = arguments[_i];
69
+ }
70
+ return __awaiter(void 0, __spreadArray([projectPath_1], args_1, true), void 0, function (projectPath, verbose) {
71
+ var issues;
72
+ if (verbose === void 0) { verbose = false; }
73
+ return __generator(this, function (_a) {
74
+ switch (_a.label) {
75
+ case 0:
76
+ issues = [];
77
+ if (verbose)
78
+ logger_1.default.info("runDiagnostics", "Running diagnostics on ".concat(projectPath));
79
+ // Check for required files
80
+ return [4 /*yield*/, checkEnvFile(projectPath, issues)];
81
+ case 1:
82
+ // Check for required files
83
+ _a.sent();
84
+ return [4 /*yield*/, checkAdobeConfig(projectPath, issues)];
85
+ case 2:
86
+ _a.sent();
87
+ return [4 /*yield*/, checkWatchConfig(projectPath, issues)];
88
+ case 3:
89
+ _a.sent();
90
+ return [4 /*yield*/, checkGitignore(projectPath, issues)];
91
+ case 4:
92
+ _a.sent();
93
+ return [4 /*yield*/, checkPackageJson(projectPath, issues)];
94
+ case 5:
95
+ _a.sent();
96
+ return [4 /*yield*/, checkActivitiesFolder(projectPath, issues)];
97
+ case 6:
98
+ _a.sent();
99
+ // Check environment variables
100
+ return [4 /*yield*/, checkEnvVariables(projectPath, issues)];
101
+ case 7:
102
+ // Check environment variables
103
+ _a.sent();
104
+ // Check dependencies
105
+ return [4 /*yield*/, checkDependencies(projectPath, issues)];
106
+ case 8:
107
+ // Check dependencies
108
+ _a.sent();
109
+ // Check build.config.json content for every activity
110
+ return [4 /*yield*/, checkBuildConfigs(projectPath, issues)];
111
+ case 9:
112
+ // Check build.config.json content for every activity
113
+ _a.sent();
114
+ // Check install environment (PATH, atb shim, exec bit). Mirrors the
115
+ // postinstall validator so users who installed with --ignore-scripts
116
+ // (or who dismissed the postinstall warning) can still self-diagnose.
117
+ return [4 /*yield*/, checkInstallEnv(issues)];
118
+ case 10:
119
+ // Check install environment (PATH, atb shim, exec bit). Mirrors the
120
+ // postinstall validator so users who installed with --ignore-scripts
121
+ // (or who dismissed the postinstall warning) can still self-diagnose.
122
+ _a.sent();
123
+ return [2 /*return*/, issues];
124
+ }
125
+ });
126
+ });
28
127
  };
29
128
  exports.runDiagnostics = runDiagnostics;
30
129
  /**
31
130
  * Attempt to fix the provided issues
32
131
  */
33
- const fixIssues = async (issues, projectPath, verbose = false) => {
34
- let fixedCount = 0;
35
- for (const issue of issues) {
36
- if (!issue.fixable)
37
- continue;
38
- try {
39
- if (verbose)
40
- logger_1.default.info("fixIssues", `Attempting to fix: ${issue.id}`);
41
- const success = await fixIssue(issue, projectPath, verbose);
42
- if (success) {
43
- console.log(`✅ Fixed: ${issue.message}`);
44
- fixedCount++;
45
- }
46
- else {
47
- console.log(`❌ Could not fix: ${issue.message}`);
48
- }
49
- }
50
- catch (error) {
51
- console.log(`❌ Error fixing ${issue.id}: ${error.message}`);
52
- }
132
+ var fixIssues = function (issues_1, projectPath_1) {
133
+ var args_1 = [];
134
+ for (var _i = 2; _i < arguments.length; _i++) {
135
+ args_1[_i - 2] = arguments[_i];
53
136
  }
54
- return fixedCount;
137
+ return __awaiter(void 0, __spreadArray([issues_1, projectPath_1], args_1, true), void 0, function (issues, projectPath, verbose) {
138
+ var fixedCount, _a, issues_2, issue, success, error_1;
139
+ if (verbose === void 0) { verbose = false; }
140
+ return __generator(this, function (_b) {
141
+ switch (_b.label) {
142
+ case 0:
143
+ fixedCount = 0;
144
+ _a = 0, issues_2 = issues;
145
+ _b.label = 1;
146
+ case 1:
147
+ if (!(_a < issues_2.length)) return [3 /*break*/, 6];
148
+ issue = issues_2[_a];
149
+ if (!issue.fixable)
150
+ return [3 /*break*/, 5];
151
+ _b.label = 2;
152
+ case 2:
153
+ _b.trys.push([2, 4, , 5]);
154
+ if (verbose)
155
+ logger_1.default.info("fixIssues", "Attempting to fix: ".concat(issue.id));
156
+ return [4 /*yield*/, fixIssue(issue, projectPath, verbose)];
157
+ case 3:
158
+ success = _b.sent();
159
+ if (success) {
160
+ console.log("\u2705 Fixed: ".concat(issue.message));
161
+ fixedCount++;
162
+ }
163
+ else {
164
+ console.log("\u274C Could not fix: ".concat(issue.message));
165
+ }
166
+ return [3 /*break*/, 5];
167
+ case 4:
168
+ error_1 = _b.sent();
169
+ console.log("\u274C Error fixing ".concat(issue.id, ": ").concat(error_1.message));
170
+ return [3 /*break*/, 5];
171
+ case 5:
172
+ _a++;
173
+ return [3 /*break*/, 1];
174
+ case 6: return [2 /*return*/, fixedCount];
175
+ }
176
+ });
177
+ });
55
178
  };
56
179
  exports.fixIssues = fixIssues;
57
180
  /**
58
181
  * Fix a specific issue
59
182
  */
60
- const fixIssue = async (issue, projectPath, verbose) => {
61
- switch (issue.id) {
62
- case 'missing-env':
63
- return await createEnvFile(projectPath);
64
- case 'missing-adobe-config':
65
- return await createAdobeConfig(projectPath);
66
- case 'missing-watch-config':
67
- return await createWatchConfig(projectPath);
68
- case 'missing-activities-folder':
69
- return await createActivitiesFolder(projectPath);
70
- case 'missing-package-json':
71
- return await createPackageJson(projectPath);
72
- default:
73
- return false;
74
- }
75
- };
183
+ var fixIssue = function (issue, projectPath, verbose) { return __awaiter(void 0, void 0, void 0, function () {
184
+ var _a;
185
+ return __generator(this, function (_b) {
186
+ switch (_b.label) {
187
+ case 0:
188
+ _a = issue.id;
189
+ switch (_a) {
190
+ case 'missing-env': return [3 /*break*/, 1];
191
+ case 'missing-adobe-config': return [3 /*break*/, 3];
192
+ case 'legacy-watch-config': return [3 /*break*/, 5];
193
+ case 'missing-gitignore': return [3 /*break*/, 7];
194
+ case 'missing-activities-folder': return [3 /*break*/, 9];
195
+ case 'missing-package-json': return [3 /*break*/, 11];
196
+ }
197
+ return [3 /*break*/, 13];
198
+ case 1: return [4 /*yield*/, createEnvFile(projectPath)];
199
+ case 2: return [2 /*return*/, _b.sent()];
200
+ case 3: return [4 /*yield*/, createAdobeConfig(projectPath)];
201
+ case 4: return [2 /*return*/, _b.sent()];
202
+ case 5: return [4 /*yield*/, migrateWatchConfig(projectPath)];
203
+ case 6: return [2 /*return*/, _b.sent()];
204
+ case 7: return [4 /*yield*/, createGitignore(projectPath)];
205
+ case 8: return [2 /*return*/, _b.sent()];
206
+ case 9: return [4 /*yield*/, createActivitiesFolder(projectPath)];
207
+ case 10: return [2 /*return*/, _b.sent()];
208
+ case 11: return [4 /*yield*/, createPackageJson(projectPath)];
209
+ case 12: return [2 /*return*/, _b.sent()];
210
+ case 13: return [2 /*return*/, false];
211
+ }
212
+ });
213
+ }); };
76
214
  /**
77
215
  * Check if .env file exists and has required variables
78
216
  */
79
- const checkEnvFile = async (projectPath, issues) => {
80
- const envPath = path_1.default.join(projectPath, '.env');
81
- if (!fs_1.default.existsSync(envPath)) {
82
- issues.push({
83
- id: 'missing-env',
84
- severity: 'error',
85
- message: '.env file is missing',
86
- suggestion: 'Create .env file with required environment variables',
87
- fixable: true,
88
- file: '.env'
89
- });
90
- return;
91
- }
92
- // Check if .env has required variables
93
- const envContent = fs_1.default.readFileSync(envPath, 'utf8');
94
- const requiredVars = [
95
- 'ACTIVITIES_BASE_FOLDER',
96
- 'ACTIVITY_FOLDER_NAME',
97
- 'ADOBE_CLIENT_ID',
98
- 'ADOBE_CLIENT_SECRET'
99
- ];
100
- const missingVars = requiredVars.filter(varName => !envContent.includes(varName));
101
- if (missingVars.length > 0) {
102
- issues.push({
103
- id: 'incomplete-env',
104
- severity: 'warning',
105
- message: `.env file missing variables: ${missingVars.join(', ')}`,
106
- suggestion: 'Add missing environment variables to .env file',
107
- fixable: true,
108
- file: '.env'
109
- });
110
- }
111
- };
217
+ var checkEnvFile = function (projectPath, issues) { return __awaiter(void 0, void 0, void 0, function () {
218
+ var envPath, envContent, requiredVars, missingVars;
219
+ return __generator(this, function (_a) {
220
+ envPath = path_1.default.join(projectPath, '.env');
221
+ if (!fs_1.default.existsSync(envPath)) {
222
+ issues.push({
223
+ id: 'missing-env',
224
+ severity: 'error',
225
+ message: '.env file is missing',
226
+ suggestion: 'Create .env file with required environment variables',
227
+ fixable: true,
228
+ file: '.env'
229
+ });
230
+ return [2 /*return*/];
231
+ }
232
+ envContent = fs_1.default.readFileSync(envPath, 'utf8');
233
+ requiredVars = [
234
+ 'ACTIVITIES_BASE_FOLDER',
235
+ 'ACTIVITY_FOLDER_NAME',
236
+ 'ADOBE_CLIENT_ID',
237
+ 'ADOBE_CLIENT_SECRET'
238
+ ];
239
+ missingVars = requiredVars.filter(function (varName) { return !envContent.includes(varName); });
240
+ if (missingVars.length > 0) {
241
+ issues.push({
242
+ id: 'incomplete-env',
243
+ severity: 'warning',
244
+ message: ".env file missing variables: ".concat(missingVars.join(', ')),
245
+ suggestion: 'Add missing environment variables to .env file',
246
+ fixable: true,
247
+ file: '.env'
248
+ });
249
+ }
250
+ return [2 /*return*/];
251
+ });
252
+ }); };
112
253
  /**
113
254
  * Check if adobe.config.js exists
114
255
  */
115
- const checkAdobeConfig = async (projectPath, issues) => {
116
- const configPath = path_1.default.join(projectPath, 'adobe.config.js');
117
- if (!fs_1.default.existsSync(configPath)) {
118
- issues.push({
119
- id: 'missing-adobe-config',
120
- severity: 'error',
121
- message: 'adobe.config.js file is missing',
122
- suggestion: 'Create Adobe Target API configuration file',
123
- fixable: true,
124
- file: 'adobe.config.js'
125
- });
126
- }
127
- };
256
+ var checkAdobeConfig = function (projectPath, issues) { return __awaiter(void 0, void 0, void 0, function () {
257
+ var configPath;
258
+ return __generator(this, function (_a) {
259
+ configPath = path_1.default.join(projectPath, 'adobe.config.js');
260
+ if (!fs_1.default.existsSync(configPath)) {
261
+ issues.push({
262
+ id: 'missing-adobe-config',
263
+ severity: 'error',
264
+ message: 'adobe.config.js file is missing',
265
+ suggestion: 'Create Adobe Target API configuration file',
266
+ fixable: true,
267
+ file: 'adobe.config.js'
268
+ });
269
+ }
270
+ return [2 /*return*/];
271
+ });
272
+ }); };
128
273
  /**
129
- * Check if watch-config.json exists
274
+ * Flag a legacy watch-config.json. As of this release VARIATION/PAGE live in
275
+ * .env; watch-config.json is supported as a fallback (puppeteer.js prefers it
276
+ * if present with a deprecation warning) but new projects don't get one.
277
+ *
278
+ * The fix migrates VARIATION/PAGE into .env and deletes watch-config.json.
130
279
  */
131
- const checkWatchConfig = async (projectPath, issues) => {
132
- const configPath = path_1.default.join(projectPath, 'watch-config.json');
133
- if (!fs_1.default.existsSync(configPath)) {
280
+ var checkWatchConfig = function (projectPath, issues) { return __awaiter(void 0, void 0, void 0, function () {
281
+ var configPath;
282
+ return __generator(this, function (_a) {
283
+ configPath = path_1.default.join(projectPath, 'watch-config.json');
284
+ if (!fs_1.default.existsSync(configPath))
285
+ return [2 /*return*/];
134
286
  issues.push({
135
- id: 'missing-watch-config',
287
+ id: 'legacy-watch-config',
136
288
  severity: 'warning',
137
- message: 'watch-config.json file is missing',
138
- suggestion: 'Create build configuration file',
289
+ message: 'watch-config.json is deprecated — VARIATION/PAGE now live in .env',
290
+ suggestion: 'Run "atb doctor --fix" to migrate values into .env and delete watch-config.json',
139
291
  fixable: true,
140
292
  file: 'watch-config.json'
141
293
  });
142
- }
143
- };
294
+ return [2 /*return*/];
295
+ });
296
+ }); };
297
+ /**
298
+ * Check if .gitignore exists. Flags as a warning (not blocking) but fixable —
299
+ * `atb doctor --fix` writes the default template covering .env, .deploy-lock,
300
+ * dist/, etc. Does not modify an existing .gitignore.
301
+ */
302
+ var checkGitignore = function (projectPath, issues) { return __awaiter(void 0, void 0, void 0, function () {
303
+ var gitignorePath;
304
+ return __generator(this, function (_a) {
305
+ gitignorePath = path_1.default.join(projectPath, '.gitignore');
306
+ if (!fs_1.default.existsSync(gitignorePath)) {
307
+ issues.push({
308
+ id: 'missing-gitignore',
309
+ severity: 'warning',
310
+ message: '.gitignore file is missing',
311
+ suggestion: 'Create .gitignore with at-builder defaults (.env, .deploy-lock, dist/, etc.)',
312
+ fixable: true,
313
+ file: '.gitignore'
314
+ });
315
+ }
316
+ return [2 /*return*/];
317
+ });
318
+ }); };
144
319
  /**
145
320
  * Check if package.json exists
146
321
  */
147
- const checkPackageJson = async (projectPath, issues) => {
148
- const packagePath = path_1.default.join(projectPath, 'package.json');
149
- if (!fs_1.default.existsSync(packagePath)) {
150
- issues.push({
151
- id: 'missing-package-json',
152
- severity: 'error',
153
- message: 'package.json file is missing',
154
- suggestion: 'Initialize npm project with package.json',
155
- fixable: true,
156
- file: 'package.json'
157
- });
158
- }
322
+ var checkPackageJson = function (projectPath, issues) { return __awaiter(void 0, void 0, void 0, function () {
323
+ var packagePath;
324
+ return __generator(this, function (_a) {
325
+ packagePath = path_1.default.join(projectPath, 'package.json');
326
+ if (!fs_1.default.existsSync(packagePath)) {
327
+ issues.push({
328
+ id: 'missing-package-json',
329
+ severity: 'error',
330
+ message: 'package.json file is missing',
331
+ suggestion: 'Initialize npm project with package.json',
332
+ fixable: true,
333
+ file: 'package.json'
334
+ });
335
+ }
336
+ return [2 /*return*/];
337
+ });
338
+ }); };
339
+ /**
340
+ * Resolve the configured activities folder name. Reads ACTIVITIES_BASE_FOLDER
341
+ * from the consumer .env (matching webpack/at-deploy/at-sync resolution), falls
342
+ * back to the default "Activities".
343
+ */
344
+ var resolveActivitiesFolderName = function (projectPath) {
345
+ var envPath = path_1.default.join(projectPath, '.env');
346
+ if (!fs_1.default.existsSync(envPath))
347
+ return 'Activities';
348
+ var envContent = fs_1.default.readFileSync(envPath, 'utf8');
349
+ var match = envContent.match(/ACTIVITIES_BASE_FOLDER=["']?([^"'\n\r]+)["']?/);
350
+ return match ? match[1] : 'Activities';
159
351
  };
160
352
  /**
161
353
  * Check if Activities folder exists
162
354
  */
163
- const checkActivitiesFolder = async (projectPath, issues) => {
164
- // Try to read ACTIVITIES_BASE_FOLDER from .env, fallback to default
165
- let activitiesFolder = 'Activities';
166
- const envPath = path_1.default.join(projectPath, '.env');
167
- if (fs_1.default.existsSync(envPath)) {
168
- const envContent = fs_1.default.readFileSync(envPath, 'utf8');
169
- const match = envContent.match(/ACTIVITIES_BASE_FOLDER=["']?([^"'\n\r]+)["']?/);
170
- if (match) {
171
- activitiesFolder = match[1];
355
+ var checkActivitiesFolder = function (projectPath, issues) { return __awaiter(void 0, void 0, void 0, function () {
356
+ var activitiesFolder, activitiesPath;
357
+ return __generator(this, function (_a) {
358
+ activitiesFolder = resolveActivitiesFolderName(projectPath);
359
+ activitiesPath = path_1.default.join(projectPath, activitiesFolder);
360
+ if (!fs_1.default.existsSync(activitiesPath)) {
361
+ issues.push({
362
+ id: 'missing-activities-folder',
363
+ severity: 'warning',
364
+ message: "".concat(activitiesFolder, " folder is missing"),
365
+ suggestion: "Create ".concat(activitiesFolder, " folder for your activities"),
366
+ fixable: true,
367
+ file: activitiesFolder
368
+ });
172
369
  }
173
- }
174
- const activitiesPath = path_1.default.join(projectPath, activitiesFolder);
175
- if (!fs_1.default.existsSync(activitiesPath)) {
176
- issues.push({
177
- id: 'missing-activities-folder',
178
- severity: 'warning',
179
- message: `${activitiesFolder} folder is missing`,
180
- suggestion: `Create ${activitiesFolder} folder for your activities`,
181
- fixable: true,
182
- file: activitiesFolder
183
- });
184
- }
185
- };
370
+ return [2 /*return*/];
371
+ });
372
+ }); };
373
+ /**
374
+ * Validate every shared/build.config.json under the activities folder.
375
+ *
376
+ * Catches the deploy-time errors before deploy:
377
+ * - missing or invalid activityType (must be "ab" or "xt")
378
+ * - null id (deploy will fail when it tries to GET the activity)
379
+ * - multi-page variation values without an activityInfo.pages map
380
+ * - variation/page folders referenced in config but absent on disk
381
+ *
382
+ * Issues are not auto-fixable (they're content problems requiring human
383
+ * judgment), so each one is reported with a clear suggestion.
384
+ */
385
+ var checkBuildConfigs = function (projectPath, issues) { return __awaiter(void 0, void 0, void 0, function () {
386
+ var activitiesFolder, activitiesPath, activityDirs, _i, activityDirs_1, activityDir, activityRoot, configCandidates, configPath, relConfig, parsed, activityInfo, activityType, variations, variationEntries, isMultiPage, pages, _a, variationEntries_1, _b, variationKey, variationValue, pagesMap, _c, _d, _e, pageName, subPath, folderAbs, _f, variationEntries_2, variationKey, folderAbs;
387
+ return __generator(this, function (_g) {
388
+ activitiesFolder = resolveActivitiesFolderName(projectPath);
389
+ activitiesPath = path_1.default.join(projectPath, activitiesFolder);
390
+ if (!fs_1.default.existsSync(activitiesPath))
391
+ return [2 /*return*/]; // already flagged elsewhere
392
+ activityDirs = fs_1.default.readdirSync(activitiesPath, { withFileTypes: true })
393
+ .filter(function (d) { return d.isDirectory() && !d.name.startsWith('.'); });
394
+ for (_i = 0, activityDirs_1 = activityDirs; _i < activityDirs_1.length; _i++) {
395
+ activityDir = activityDirs_1[_i];
396
+ activityRoot = path_1.default.join(activitiesPath, activityDir.name);
397
+ configCandidates = [
398
+ path_1.default.join(activityRoot, 'shared', 'build.config.json'),
399
+ path_1.default.join(activityRoot, 'Shared', 'build.config.json')
400
+ ];
401
+ configPath = configCandidates.find(function (p) { return fs_1.default.existsSync(p); });
402
+ if (!configPath)
403
+ continue; // missing build.config is its own concern
404
+ relConfig = path_1.default.relative(projectPath, configPath);
405
+ parsed = void 0;
406
+ try {
407
+ parsed = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
408
+ }
409
+ catch (err) {
410
+ issues.push({
411
+ id: "invalid-build-config-json:".concat(activityDir.name),
412
+ severity: 'error',
413
+ message: "".concat(relConfig, " is not valid JSON"),
414
+ suggestion: "Open ".concat(relConfig, " and fix the JSON syntax. Error: ").concat(err.message),
415
+ fixable: false,
416
+ file: relConfig
417
+ });
418
+ continue;
419
+ }
420
+ activityInfo = (parsed && parsed.activityInfo);
421
+ if (!activityInfo || typeof activityInfo !== 'object') {
422
+ issues.push({
423
+ id: "missing-activity-info:".concat(activityDir.name),
424
+ severity: 'error',
425
+ message: "".concat(relConfig, " is missing activityInfo"),
426
+ suggestion: 'Re-run "atb new" or restore activityInfo manually',
427
+ fixable: false,
428
+ file: relConfig
429
+ });
430
+ continue;
431
+ }
432
+ activityType = activityInfo.activityType;
433
+ if (!activityType) {
434
+ issues.push({
435
+ id: "missing-activity-type:".concat(activityDir.name),
436
+ severity: 'warning',
437
+ message: "".concat(relConfig, " is missing activityType"),
438
+ suggestion: 'Add `"activityType": "ab"` (or "xt") to activityInfo',
439
+ fixable: false,
440
+ file: relConfig
441
+ });
442
+ }
443
+ else if (!['ab', 'xt'].includes(String(activityType).toLowerCase())) {
444
+ issues.push({
445
+ id: "invalid-activity-type:".concat(activityDir.name),
446
+ severity: 'error',
447
+ message: "".concat(relConfig, " has invalid activityType \"").concat(activityType, "\""),
448
+ suggestion: 'activityType must be "ab" or "xt"',
449
+ fixable: false,
450
+ file: relConfig
451
+ });
452
+ }
453
+ // id check (warning only — null is fine until first deploy)
454
+ if (activityInfo.id === null || activityInfo.id === undefined) {
455
+ issues.push({
456
+ id: "unset-activity-id:".concat(activityDir.name),
457
+ severity: 'warning',
458
+ message: "".concat(relConfig, " has no activity id (deploy will fail until set)"),
459
+ suggestion: 'Set activityInfo.id once the activity exists in Adobe Target, or run "atb sync"',
460
+ fixable: false,
461
+ file: relConfig
462
+ });
463
+ }
464
+ variations = activityInfo.variations;
465
+ if (!variations || (Array.isArray(variations) && variations.length === 0) || (typeof variations === 'object' && !Array.isArray(variations) && Object.keys(variations).length === 0)) {
466
+ issues.push({
467
+ id: "missing-variations:".concat(activityDir.name),
468
+ severity: 'error',
469
+ message: "".concat(relConfig, " has no variations"),
470
+ suggestion: 'Add at least one variation to activityInfo.variations',
471
+ fixable: false,
472
+ file: relConfig
473
+ });
474
+ continue;
475
+ }
476
+ variationEntries = Array.isArray(variations)
477
+ ? []
478
+ : Object.entries(variations);
479
+ isMultiPage = variationEntries.some(function (_a) {
480
+ var v = _a[1];
481
+ return typeof v === 'object' && v !== null && 'pages' in v;
482
+ });
483
+ if (isMultiPage) {
484
+ pages = activityInfo.pages;
485
+ if (!pages || typeof pages !== 'object' || Object.keys(pages).length === 0) {
486
+ issues.push({
487
+ id: "multi-page-missing-pages:".concat(activityDir.name),
488
+ severity: 'error',
489
+ message: "".concat(relConfig, " uses multi-page variations but has no activityInfo.pages map"),
490
+ suggestion: 'Add `"pages": { "<pageName>": <locationLocalId>, ... }` or run "atb sync" to populate it from Adobe Target',
491
+ fixable: false,
492
+ file: relConfig
493
+ });
494
+ }
495
+ // Each multi-page variation: pages.<page> should map to a folder that exists
496
+ for (_a = 0, variationEntries_1 = variationEntries; _a < variationEntries_1.length; _a++) {
497
+ _b = variationEntries_1[_a], variationKey = _b[0], variationValue = _b[1];
498
+ if (typeof variationValue !== 'object' || variationValue === null || !('pages' in variationValue))
499
+ continue;
500
+ pagesMap = variationValue.pages || {};
501
+ for (_c = 0, _d = Object.entries(pagesMap); _c < _d.length; _c++) {
502
+ _e = _d[_c], pageName = _e[0], subPath = _e[1];
503
+ if (typeof subPath !== 'string')
504
+ continue;
505
+ folderAbs = path_1.default.join(activityRoot, subPath);
506
+ if (!fs_1.default.existsSync(folderAbs)) {
507
+ issues.push({
508
+ id: "missing-page-folder:".concat(activityDir.name, ":").concat(variationKey, ":").concat(pageName),
509
+ severity: 'warning',
510
+ message: "".concat(relConfig, ": variation \"").concat(variationKey, "\" \u2192 page \"").concat(pageName, "\" expects folder \"").concat(subPath, "\" but it doesn't exist"),
511
+ suggestion: 'Run "atb sync --scaffold" to auto-create missing variation folders, or create them manually',
512
+ fixable: false,
513
+ file: relConfig
514
+ });
515
+ }
516
+ }
517
+ }
518
+ }
519
+ else {
520
+ // Single-page: each variation key should map to a folder under the activity root
521
+ for (_f = 0, variationEntries_2 = variationEntries; _f < variationEntries_2.length; _f++) {
522
+ variationKey = variationEntries_2[_f][0];
523
+ folderAbs = path_1.default.join(activityRoot, variationKey);
524
+ if (!fs_1.default.existsSync(folderAbs)) {
525
+ issues.push({
526
+ id: "missing-variation-folder:".concat(activityDir.name, ":").concat(variationKey),
527
+ severity: 'warning',
528
+ message: "".concat(relConfig, ": variation \"").concat(variationKey, "\" has no folder at ").concat(path_1.default.relative(projectPath, folderAbs)),
529
+ suggestion: 'Create the folder, run "atb new" to scaffold variations, or remove the entry from build.config.json',
530
+ fixable: false,
531
+ file: relConfig
532
+ });
533
+ }
534
+ }
535
+ }
536
+ }
537
+ return [2 /*return*/];
538
+ });
539
+ }); };
186
540
  /**
187
541
  * Check environment variables content
188
542
  */
189
- const checkEnvVariables = async (projectPath, issues) => {
190
- const envPath = path_1.default.join(projectPath, '.env');
191
- if (!fs_1.default.existsSync(envPath))
192
- return;
193
- const envContent = fs_1.default.readFileSync(envPath, 'utf8');
194
- // Check if ACTIVITY_FOLDER_NAME is empty
195
- if (envContent.includes('ACTIVITY_FOLDER_NAME=""') || envContent.includes('ACTIVITY_FOLDER_NAME=\'\'')) {
196
- issues.push({
197
- id: 'empty-activity-folder-name',
198
- severity: 'warning',
199
- message: 'ACTIVITY_FOLDER_NAME is empty',
200
- suggestion: 'Set ACTIVITY_FOLDER_NAME to your activity folder name',
201
- fixable: false
202
- });
203
- }
204
- // Check if Adobe credentials are empty
205
- if (envContent.includes('ADOBE_CLIENT_ID=""') || envContent.includes('ADOBE_CLIENT_ID=\'\'')) {
206
- issues.push({
207
- id: 'empty-adobe-client-id',
208
- severity: 'warning',
209
- message: 'ADOBE_CLIENT_ID is empty',
210
- suggestion: 'Set your Adobe Target API client ID',
211
- fixable: false
212
- });
213
- }
214
- if (envContent.includes('ADOBE_CLIENT_SECRET=""') || envContent.includes('ADOBE_CLIENT_SECRET=\'\'')) {
215
- issues.push({
216
- id: 'empty-adobe-client-secret',
217
- severity: 'warning',
218
- message: 'ADOBE_CLIENT_SECRET is empty',
219
- suggestion: 'Set your Adobe Target API client secret',
220
- fixable: false
221
- });
222
- }
223
- };
543
+ var checkEnvVariables = function (projectPath, issues) { return __awaiter(void 0, void 0, void 0, function () {
544
+ var envPath, envContent, tenantMatch, tenantValue;
545
+ return __generator(this, function (_a) {
546
+ envPath = path_1.default.join(projectPath, '.env');
547
+ if (!fs_1.default.existsSync(envPath))
548
+ return [2 /*return*/];
549
+ envContent = fs_1.default.readFileSync(envPath, 'utf8');
550
+ // Check if ACTIVITY_FOLDER_NAME is empty
551
+ if (envContent.includes('ACTIVITY_FOLDER_NAME=""') || envContent.includes('ACTIVITY_FOLDER_NAME=\'\'')) {
552
+ issues.push({
553
+ id: 'empty-activity-folder-name',
554
+ severity: 'warning',
555
+ message: 'ACTIVITY_FOLDER_NAME is empty',
556
+ suggestion: 'Set ACTIVITY_FOLDER_NAME to your activity folder name',
557
+ fixable: false
558
+ });
559
+ }
560
+ // Check if Adobe credentials are empty
561
+ if (envContent.includes('ADOBE_CLIENT_ID=""') || envContent.includes('ADOBE_CLIENT_ID=\'\'')) {
562
+ issues.push({
563
+ id: 'empty-adobe-client-id',
564
+ severity: 'warning',
565
+ message: 'ADOBE_CLIENT_ID is empty',
566
+ suggestion: 'Set your Adobe Target API client ID',
567
+ fixable: false
568
+ });
569
+ }
570
+ if (envContent.includes('ADOBE_CLIENT_SECRET=""') || envContent.includes('ADOBE_CLIENT_SECRET=\'\'')) {
571
+ issues.push({
572
+ id: 'empty-adobe-client-secret',
573
+ severity: 'warning',
574
+ message: 'ADOBE_CLIENT_SECRET is empty',
575
+ suggestion: 'Set your Adobe Target API client secret',
576
+ fixable: false
577
+ });
578
+ }
579
+ tenantMatch = envContent.match(/^ADOBE_TENANT=(.*)$/m);
580
+ tenantValue = tenantMatch ? tenantMatch[1].trim().replace(/^["']|["']$/g, '') : '';
581
+ if (!tenantValue) {
582
+ issues.push({
583
+ id: 'empty-adobe-tenant',
584
+ severity: 'warning',
585
+ message: 'ADOBE_TENANT is missing or empty',
586
+ suggestion: 'Set ADOBE_TENANT to your AT tenant slug (the segment after mc.adobe.io/ in the AT URL)',
587
+ fixable: false
588
+ });
589
+ }
590
+ return [2 /*return*/];
591
+ });
592
+ }); };
224
593
  /**
225
594
  * Check dependencies
226
595
  */
227
- const checkDependencies = async (projectPath, issues) => {
228
- const packagePath = path_1.default.join(projectPath, 'package.json');
229
- if (!fs_1.default.existsSync(packagePath))
230
- return;
231
- const nodeModulesPath = path_1.default.join(projectPath, 'node_modules');
232
- if (!fs_1.default.existsSync(nodeModulesPath)) {
233
- issues.push({
234
- id: 'missing-node-modules',
235
- severity: 'warning',
236
- message: 'node_modules folder is missing',
237
- suggestion: 'Run "npm install" to install dependencies',
238
- fixable: false
239
- });
240
- }
241
- };
596
+ var checkDependencies = function (projectPath, issues) { return __awaiter(void 0, void 0, void 0, function () {
597
+ var packagePath, nodeModulesPath;
598
+ return __generator(this, function (_a) {
599
+ packagePath = path_1.default.join(projectPath, 'package.json');
600
+ if (!fs_1.default.existsSync(packagePath))
601
+ return [2 /*return*/];
602
+ nodeModulesPath = path_1.default.join(projectPath, 'node_modules');
603
+ if (!fs_1.default.existsSync(nodeModulesPath)) {
604
+ issues.push({
605
+ id: 'missing-node-modules',
606
+ severity: 'warning',
607
+ message: 'node_modules folder is missing',
608
+ suggestion: 'Run "npm install" to install dependencies',
609
+ fixable: false
610
+ });
611
+ }
612
+ return [2 /*return*/];
613
+ });
614
+ }); };
615
+ /**
616
+ * Validate that the at-builder global install is healthy:
617
+ * - global npm bin is on PATH
618
+ * - the `atb` shim exists in the global bin
619
+ * - on POSIX, the shim and the package's bin/index.js are executable
620
+ * (auto-chmods 755 if missing the bit)
621
+ *
622
+ * Same checks as lib/postinstall.js, just surfaced through `atb doctor` for
623
+ * users who installed with --ignore-scripts or dismissed the postinstall
624
+ * warning. Issues are flagged but not auto-fixable here — the suggested
625
+ * commands need to run in the user's shell, not in this Node process.
626
+ */
627
+ var checkInstallEnv = function (issues) { return __awaiter(void 0, void 0, void 0, function () {
628
+ var result, _i, _a, problem;
629
+ return __generator(this, function (_b) {
630
+ try {
631
+ result = installChecks.checkInstallEnvironment();
632
+ }
633
+ catch (err) {
634
+ // Don't let a bug in install-checks block the rest of doctor.
635
+ logger_1.default.error("checkInstallEnv", "Skipped: ".concat(err.message));
636
+ return [2 /*return*/];
637
+ }
638
+ for (_i = 0, _a = result.problems; _i < _a.length; _i++) {
639
+ problem = _a[_i];
640
+ issues.push({
641
+ id: 'install-env',
642
+ severity: 'warning',
643
+ message: problem,
644
+ suggestion: result.isWin
645
+ ? "On Windows: ensure ".concat(result.globalBin || 'your npm global bin (npm config get prefix)', " is on PATH, then reinstall: npm i -g at-builder")
646
+ : "On macOS/Linux: chmod +x \"".concat(result.shimPath || 'atb shim', "\" and ensure ").concat(result.globalBin || '$(npm config get prefix)/bin', " is on PATH; then run: hash -r"),
647
+ fixable: false
648
+ });
649
+ }
650
+ return [2 /*return*/];
651
+ });
652
+ }); };
242
653
  // Fix functions
243
- const createEnvFile = async (projectPath) => {
244
- const envPath = path_1.default.join(projectPath, '.env');
245
- const envContent = `ACTIVITIES_BASE_FOLDER="Activities"
246
- ACTIVITY_FOLDER_NAME=""
247
- PUPPETEER_LANDING_PAGE=""
248
- TARGET_URL=""
249
- LOGIN_URL=""
250
- VARIATION="Variation-1"
251
- NODE_ENV="development"
252
- VERBOSE=false
253
-
254
- # Adobe Target Deployment Configuration
255
- ADOBE_CLIENT_ID=""
256
- ADOBE_CLIENT_SECRET=""`;
257
- try {
258
- fs_1.default.writeFileSync(envPath, envContent, 'utf8');
259
- return true;
260
- }
261
- catch (error) {
262
- return false;
263
- }
264
- };
265
- const createAdobeConfig = async (projectPath) => {
266
- const configPath = path_1.default.join(projectPath, 'adobe.config.js');
267
- const configContent = `/**
268
- * Adobe Target API Configuration
269
- *
270
- * Configuration constants for Adobe Target API integration.
271
- * These values are used by the deployment script to connect to Adobe Target.
654
+ var createEnvFile = function (projectPath) { return __awaiter(void 0, void 0, void 0, function () {
655
+ var envPath, envContent;
656
+ return __generator(this, function (_a) {
657
+ envPath = path_1.default.join(projectPath, '.env');
658
+ envContent = "ACTIVITIES_BASE_FOLDER=\"Activities\"\nACTIVITY_FOLDER_NAME=\"\"\nPUPPETEER_LANDING_PAGE=\"\"\nTARGET_URL=\"\"\nLOGIN_URL=\"\"\n\n# Dev-server selection (used by `atb dev --browser`).\n# Edit and save while puppeteer is running to hot-swap the previewed bundle.\n# PAGE is only meaningful for multi-page activities \u2014 leave empty otherwise.\nVARIATION=\"Variation-1\"\nPAGE=\"\"\n\nNODE_ENV=\"development\"\nVERBOSE=false\n\n# Adobe Target Deployment Configuration\n# ADOBE_TENANT is your AT tenant slug \u2014 find it in the AT URL after \"mc.adobe.io/\".\nADOBE_TENANT=\"\"\nADOBE_CLIENT_ID=\"\"\nADOBE_CLIENT_SECRET=\"\"";
659
+ try {
660
+ fs_1.default.writeFileSync(envPath, envContent, 'utf8');
661
+ return [2 /*return*/, true];
662
+ }
663
+ catch (error) {
664
+ return [2 /*return*/, false];
665
+ }
666
+ return [2 /*return*/];
667
+ });
668
+ }); };
669
+ var createAdobeConfig = function (projectPath) { return __awaiter(void 0, void 0, void 0, function () {
670
+ var configPath, configContent;
671
+ return __generator(this, function (_a) {
672
+ configPath = path_1.default.join(projectPath, 'adobe.config.js');
673
+ configContent = "/**\n * Adobe Target API Configuration\n *\n * Used by at-sync.js and at-deploy.js. BASE_URL is the activities root \u2014\n * callers append `${activityType}/${activityId}` (e.g. ab/12345, xt/67890).\n *\n * ADOBE_TENANT comes from the consumer .env. Both at-sync and at-deploy load\n * dotenv before requiring this file, so process.env is populated by the time\n * BASE_URL is built.\n */\n\nconst TENANT = process.env.ADOBE_TENANT || 'YOUR_TENANT';\n\nmodule.exports = {\n BASE_URL: `https://mc.adobe.io/${TENANT}/target/activities/`,\n IMS_TOKEN_URL: 'https://ims-na1.adobelogin.com/ims/token/v3',\n IMS_SCOPE: 'openid,AdobeID,target_sdk,additional_info.projectedProductContext'\n};";
674
+ try {
675
+ fs_1.default.writeFileSync(configPath, configContent, 'utf8');
676
+ return [2 /*return*/, true];
677
+ }
678
+ catch (error) {
679
+ return [2 /*return*/, false];
680
+ }
681
+ return [2 /*return*/];
682
+ });
683
+ }); };
684
+ /**
685
+ * Migrate VARIATION/PAGE from a legacy watch-config.json into .env, then
686
+ * delete the watch-config.json. Idempotent: existing .env entries are
687
+ * overwritten so the migrated values win (matching puppeteer's runtime
688
+ * precedence — watch-config.json was the source of truth).
272
689
  */
273
-
274
- module.exports = {
275
- BASE_URL_NEW: 'https://mc.adobe.io/ups/target/',
276
- BASE_URL: 'https://mc.adobe.io/ups/target/activities/ab/',
277
- IMS_TOKEN_URL: 'https://ims-na1.adobelogin.com/ims/token/v3',
278
- IMS_SCOPE: 'openid,AdobeID,target_sdk,additional_info.projectedProductContext'
279
- };`;
280
- try {
281
- fs_1.default.writeFileSync(configPath, configContent, 'utf8');
282
- return true;
283
- }
284
- catch (error) {
285
- return false;
286
- }
287
- };
288
- const createWatchConfig = async (projectPath) => {
289
- const configPath = path_1.default.join(projectPath, 'watch-config.json');
290
- const configContent = {
291
- "VARIATION": "Variation-1"
292
- };
293
- try {
294
- fs_1.default.writeFileSync(configPath, JSON.stringify(configContent, null, 2), 'utf8');
295
- return true;
296
- }
297
- catch (error) {
298
- return false;
299
- }
300
- };
301
- const createActivitiesFolder = async (projectPath) => {
302
- // Try to read ACTIVITIES_BASE_FOLDER from .env, fallback to default
303
- let activitiesFolder = 'Activities';
304
- const envPath = path_1.default.join(projectPath, '.env');
305
- if (fs_1.default.existsSync(envPath)) {
306
- const envContent = fs_1.default.readFileSync(envPath, 'utf8');
307
- const match = envContent.match(/ACTIVITIES_BASE_FOLDER=["']?([^"'\n\r]+)["']?/);
308
- if (match) {
309
- activitiesFolder = match[1];
690
+ var migrateWatchConfig = function (projectPath) { return __awaiter(void 0, void 0, void 0, function () {
691
+ var configPath, envPath, watchCfg, variation, page, envContent;
692
+ return __generator(this, function (_a) {
693
+ configPath = path_1.default.join(projectPath, 'watch-config.json');
694
+ envPath = path_1.default.join(projectPath, '.env');
695
+ if (!fs_1.default.existsSync(configPath))
696
+ return [2 /*return*/, true]; // nothing to migrate
697
+ try {
698
+ watchCfg = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
310
699
  }
700
+ catch (err) {
701
+ console.error("Failed to parse watch-config.json: ".concat(err.message));
702
+ return [2 /*return*/, false];
703
+ }
704
+ variation = (watchCfg.VARIATION || '').trim();
705
+ page = (watchCfg.PAGE || '').trim();
706
+ if (!fs_1.default.existsSync(envPath)) {
707
+ // No .env yet — synthesize a minimal one with just the migrated keys.
708
+ // The user can add the rest via `atb init` or by editing manually.
709
+ fs_1.default.writeFileSync(envPath, "VARIATION=\"".concat(variation, "\"\nPAGE=\"").concat(page, "\"\n"), 'utf8');
710
+ }
711
+ else {
712
+ envContent = fs_1.default.readFileSync(envPath, 'utf8');
713
+ envContent = upsertEnvLine(envContent, 'VARIATION', variation);
714
+ envContent = upsertEnvLine(envContent, 'PAGE', page);
715
+ fs_1.default.writeFileSync(envPath, envContent, 'utf8');
716
+ }
717
+ try {
718
+ fs_1.default.unlinkSync(configPath);
719
+ }
720
+ catch (err) {
721
+ console.error("Migrated values into .env, but failed to delete watch-config.json: ".concat(err.message));
722
+ return [2 /*return*/, false];
723
+ }
724
+ console.log("\u2713 Migrated VARIATION=\"".concat(variation, "\" PAGE=\"").concat(page, "\" from watch-config.json into .env"));
725
+ return [2 /*return*/, true];
726
+ });
727
+ }); };
728
+ /**
729
+ * Insert or replace a `KEY="value"` line in a .env file body. Preserves
730
+ * surrounding lines; appends if the key wasn't present.
731
+ */
732
+ var upsertEnvLine = function (envContent, key, value) {
733
+ var line = "".concat(key, "=\"").concat(value, "\"");
734
+ var re = new RegExp("^".concat(key, "=.*$"), 'm');
735
+ if (re.test(envContent)) {
736
+ return envContent.replace(re, line);
311
737
  }
312
- const activitiesPath = path_1.default.join(projectPath, activitiesFolder);
313
- try {
314
- fs_1.default.mkdirSync(activitiesPath, { recursive: true });
315
- return true;
316
- }
317
- catch (error) {
318
- return false;
319
- }
320
- };
321
- const createPackageJson = async (projectPath) => {
322
- const packagePath = path_1.default.join(projectPath, 'package.json');
323
- const packageContent = {
324
- "name": path_1.default.basename(projectPath),
325
- "version": "1.0.0",
326
- "description": "",
327
- "main": "index.js",
328
- "scripts": {
329
- "test": "echo \"Error: no test specified\" && exit 1"
330
- },
331
- "keywords": [],
332
- "author": "",
333
- "license": "ISC"
334
- };
335
- try {
336
- fs_1.default.writeFileSync(packagePath, JSON.stringify(packageContent, null, 2), 'utf8');
337
- return true;
338
- }
339
- catch (error) {
340
- return false;
341
- }
738
+ if (!envContent.endsWith('\n'))
739
+ envContent += '\n';
740
+ return envContent + line + '\n';
342
741
  };
742
+ var createGitignore = function (projectPath) { return __awaiter(void 0, void 0, void 0, function () {
743
+ var gitignorePath;
744
+ return __generator(this, function (_a) {
745
+ gitignorePath = path_1.default.join(projectPath, '.gitignore');
746
+ try {
747
+ fs_1.default.writeFileSync(gitignorePath, config_1.GITIGNORE_TEMPLATE, 'utf8');
748
+ return [2 /*return*/, true];
749
+ }
750
+ catch (error) {
751
+ return [2 /*return*/, false];
752
+ }
753
+ return [2 /*return*/];
754
+ });
755
+ }); };
756
+ var createActivitiesFolder = function (projectPath) { return __awaiter(void 0, void 0, void 0, function () {
757
+ var activitiesFolder, envPath, envContent, match, activitiesPath;
758
+ return __generator(this, function (_a) {
759
+ activitiesFolder = 'Activities';
760
+ envPath = path_1.default.join(projectPath, '.env');
761
+ if (fs_1.default.existsSync(envPath)) {
762
+ envContent = fs_1.default.readFileSync(envPath, 'utf8');
763
+ match = envContent.match(/ACTIVITIES_BASE_FOLDER=["']?([^"'\n\r]+)["']?/);
764
+ if (match) {
765
+ activitiesFolder = match[1];
766
+ }
767
+ }
768
+ activitiesPath = path_1.default.join(projectPath, activitiesFolder);
769
+ try {
770
+ fs_1.default.mkdirSync(activitiesPath, { recursive: true });
771
+ return [2 /*return*/, true];
772
+ }
773
+ catch (error) {
774
+ return [2 /*return*/, false];
775
+ }
776
+ return [2 /*return*/];
777
+ });
778
+ }); };
779
+ var createPackageJson = function (projectPath) { return __awaiter(void 0, void 0, void 0, function () {
780
+ var packagePath, packageContent;
781
+ return __generator(this, function (_a) {
782
+ packagePath = path_1.default.join(projectPath, 'package.json');
783
+ packageContent = {
784
+ "name": path_1.default.basename(projectPath),
785
+ "version": "1.0.0",
786
+ "description": "",
787
+ "main": "index.js",
788
+ "scripts": {
789
+ "test": "echo \"Error: no test specified\" && exit 1"
790
+ },
791
+ "keywords": [],
792
+ "author": "",
793
+ "license": "ISC"
794
+ };
795
+ try {
796
+ fs_1.default.writeFileSync(packagePath, JSON.stringify(packageContent, null, 2), 'utf8');
797
+ return [2 /*return*/, true];
798
+ }
799
+ catch (error) {
800
+ return [2 /*return*/, false];
801
+ }
802
+ return [2 /*return*/];
803
+ });
804
+ }); };