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.
- package/.claude/settings.local.json +53 -11
- package/.plop/constants/index.js +0 -7
- package/.plop/generators/actions.js +217 -126
- package/.plop/generators/prompts.js +50 -18
- package/.plop/utils/index.js +19 -5
- package/.vscode/settings.json +6 -0
- package/DEVELOPMENT.md +164 -0
- package/README.md +16 -1
- package/at-builder-0.0.2.vsix +0 -0
- package/bin/constants/config.js +169 -167
- package/bin/index.js +494 -182
- package/bin/services/doctor.js +752 -290
- package/bin/services/logger.js +40 -20
- package/lib/at-deploy.js +379 -145
- package/lib/at-sync.js +455 -0
- package/lib/eslint-flat-config-plugin.js +34 -33
- package/lib/install-checks.js +236 -0
- package/lib/postinstall.js +90 -0
- package/package/package.json +86 -0
- package/package.json +18 -11
- package/puppeteer.js +128 -32
- package/src/constants/config.ts +84 -9
- package/src/index.ts +131 -11
- package/src/services/doctor.ts +377 -39
- package/tsconfig.json +1 -1
- package/webpack.config.js +228 -39
- package/.plop/templates/build-template.hbs +0 -7
- package/.plop/templates/build.config.hbs +0 -7
- package/.plop/templates/observer.hbs +0 -18
package/bin/services/doctor.js
CHANGED
|
@@ -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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
for (
|
|
36
|
-
|
|
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
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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: '
|
|
287
|
+
id: 'legacy-watch-config',
|
|
136
288
|
severity: 'warning',
|
|
137
|
-
message: 'watch-config.json
|
|
138
|
-
suggestion: '
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
+
}); };
|