at-builder 1.2.2 → 1.2.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 +2 -1
- package/bin/constants/config.js +53 -0
- package/bin/index.js +76 -1
- package/bin/services/doctor.js +346 -0
- package/lib/at-deploy.js +309 -0
- package/package.json +6 -4
- package/src/constants/config.ts +55 -0
- package/src/index.ts +86 -1
- package/src/services/doctor.ts +383 -0
- package/test-validation.js +21 -0
- package/tsconfig.json +1 -1
- package/webpack.config.js +34 -1
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import logger from "./logger";
|
|
4
|
+
|
|
5
|
+
export interface DiagnosticIssue {
|
|
6
|
+
id: string;
|
|
7
|
+
severity: 'error' | 'warning';
|
|
8
|
+
message: string;
|
|
9
|
+
suggestion?: string;
|
|
10
|
+
fixable: boolean;
|
|
11
|
+
file?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Run comprehensive diagnostics on the project
|
|
16
|
+
*/
|
|
17
|
+
export const runDiagnostics = async (projectPath: string, verbose: boolean = false): Promise<DiagnosticIssue[]> => {
|
|
18
|
+
const issues: DiagnosticIssue[] = [];
|
|
19
|
+
|
|
20
|
+
if (verbose) logger.info("runDiagnostics", `Running diagnostics on ${projectPath}`);
|
|
21
|
+
|
|
22
|
+
// Check for required files
|
|
23
|
+
await checkEnvFile(projectPath, issues);
|
|
24
|
+
await checkAdobeConfig(projectPath, issues);
|
|
25
|
+
await checkWatchConfig(projectPath, issues);
|
|
26
|
+
await checkPackageJson(projectPath, issues);
|
|
27
|
+
await checkActivitiesFolder(projectPath, issues);
|
|
28
|
+
|
|
29
|
+
// Check environment variables
|
|
30
|
+
await checkEnvVariables(projectPath, issues);
|
|
31
|
+
|
|
32
|
+
// Check dependencies
|
|
33
|
+
await checkDependencies(projectPath, issues);
|
|
34
|
+
|
|
35
|
+
return issues;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Attempt to fix the provided issues
|
|
40
|
+
*/
|
|
41
|
+
export const fixIssues = async (issues: DiagnosticIssue[], projectPath: string, verbose: boolean = false): Promise<number> => {
|
|
42
|
+
let fixedCount = 0;
|
|
43
|
+
|
|
44
|
+
for (const issue of issues) {
|
|
45
|
+
if (!issue.fixable) continue;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
if (verbose) logger.info("fixIssues", `Attempting to fix: ${issue.id}`);
|
|
49
|
+
|
|
50
|
+
const success = await fixIssue(issue, projectPath, verbose);
|
|
51
|
+
if (success) {
|
|
52
|
+
console.log(`✅ Fixed: ${issue.message}`);
|
|
53
|
+
fixedCount++;
|
|
54
|
+
} else {
|
|
55
|
+
console.log(`❌ Could not fix: ${issue.message}`);
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.log(`❌ Error fixing ${issue.id}: ${error.message}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return fixedCount;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Fix a specific issue
|
|
67
|
+
*/
|
|
68
|
+
const fixIssue = async (issue: DiagnosticIssue, projectPath: string, verbose: boolean): Promise<boolean> => {
|
|
69
|
+
switch (issue.id) {
|
|
70
|
+
case 'missing-env':
|
|
71
|
+
return await createEnvFile(projectPath);
|
|
72
|
+
case 'missing-adobe-config':
|
|
73
|
+
return await createAdobeConfig(projectPath);
|
|
74
|
+
case 'missing-watch-config':
|
|
75
|
+
return await createWatchConfig(projectPath);
|
|
76
|
+
case 'missing-activities-folder':
|
|
77
|
+
return await createActivitiesFolder(projectPath);
|
|
78
|
+
case 'missing-package-json':
|
|
79
|
+
return await createPackageJson(projectPath);
|
|
80
|
+
default:
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Check if .env file exists and has required variables
|
|
87
|
+
*/
|
|
88
|
+
const checkEnvFile = async (projectPath: string, issues: DiagnosticIssue[]): Promise<void> => {
|
|
89
|
+
const envPath = path.join(projectPath, '.env');
|
|
90
|
+
|
|
91
|
+
if (!fs.existsSync(envPath)) {
|
|
92
|
+
issues.push({
|
|
93
|
+
id: 'missing-env',
|
|
94
|
+
severity: 'error',
|
|
95
|
+
message: '.env file is missing',
|
|
96
|
+
suggestion: 'Create .env file with required environment variables',
|
|
97
|
+
fixable: true,
|
|
98
|
+
file: '.env'
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Check if .env has required variables
|
|
104
|
+
const envContent = fs.readFileSync(envPath, 'utf8');
|
|
105
|
+
const requiredVars = [
|
|
106
|
+
'ACTIVITIES_BASE_FOLDER',
|
|
107
|
+
'ACTIVITY_FOLDER_NAME',
|
|
108
|
+
'ADOBE_CLIENT_ID',
|
|
109
|
+
'ADOBE_CLIENT_SECRET'
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
const missingVars = requiredVars.filter(varName => !envContent.includes(varName));
|
|
113
|
+
|
|
114
|
+
if (missingVars.length > 0) {
|
|
115
|
+
issues.push({
|
|
116
|
+
id: 'incomplete-env',
|
|
117
|
+
severity: 'warning',
|
|
118
|
+
message: `.env file missing variables: ${missingVars.join(', ')}`,
|
|
119
|
+
suggestion: 'Add missing environment variables to .env file',
|
|
120
|
+
fixable: true,
|
|
121
|
+
file: '.env'
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check if adobe.config.js exists
|
|
128
|
+
*/
|
|
129
|
+
const checkAdobeConfig = async (projectPath: string, issues: DiagnosticIssue[]): Promise<void> => {
|
|
130
|
+
const configPath = path.join(projectPath, 'adobe.config.js');
|
|
131
|
+
|
|
132
|
+
if (!fs.existsSync(configPath)) {
|
|
133
|
+
issues.push({
|
|
134
|
+
id: 'missing-adobe-config',
|
|
135
|
+
severity: 'error',
|
|
136
|
+
message: 'adobe.config.js file is missing',
|
|
137
|
+
suggestion: 'Create Adobe Target API configuration file',
|
|
138
|
+
fixable: true,
|
|
139
|
+
file: 'adobe.config.js'
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Check if watch-config.json exists
|
|
146
|
+
*/
|
|
147
|
+
const checkWatchConfig = async (projectPath: string, issues: DiagnosticIssue[]): Promise<void> => {
|
|
148
|
+
const configPath = path.join(projectPath, 'watch-config.json');
|
|
149
|
+
|
|
150
|
+
if (!fs.existsSync(configPath)) {
|
|
151
|
+
issues.push({
|
|
152
|
+
id: 'missing-watch-config',
|
|
153
|
+
severity: 'warning',
|
|
154
|
+
message: 'watch-config.json file is missing',
|
|
155
|
+
suggestion: 'Create build configuration file',
|
|
156
|
+
fixable: true,
|
|
157
|
+
file: 'watch-config.json'
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if package.json exists
|
|
164
|
+
*/
|
|
165
|
+
const checkPackageJson = async (projectPath: string, issues: DiagnosticIssue[]): Promise<void> => {
|
|
166
|
+
const packagePath = path.join(projectPath, 'package.json');
|
|
167
|
+
|
|
168
|
+
if (!fs.existsSync(packagePath)) {
|
|
169
|
+
issues.push({
|
|
170
|
+
id: 'missing-package-json',
|
|
171
|
+
severity: 'error',
|
|
172
|
+
message: 'package.json file is missing',
|
|
173
|
+
suggestion: 'Initialize npm project with package.json',
|
|
174
|
+
fixable: true,
|
|
175
|
+
file: 'package.json'
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check if Activities folder exists
|
|
182
|
+
*/
|
|
183
|
+
const checkActivitiesFolder = async (projectPath: string, issues: DiagnosticIssue[]): Promise<void> => {
|
|
184
|
+
// Try to read ACTIVITIES_BASE_FOLDER from .env, fallback to default
|
|
185
|
+
let activitiesFolder = 'Activities';
|
|
186
|
+
const envPath = path.join(projectPath, '.env');
|
|
187
|
+
|
|
188
|
+
if (fs.existsSync(envPath)) {
|
|
189
|
+
const envContent = fs.readFileSync(envPath, 'utf8');
|
|
190
|
+
const match = envContent.match(/ACTIVITIES_BASE_FOLDER=["']?([^"'\n\r]+)["']?/);
|
|
191
|
+
if (match) {
|
|
192
|
+
activitiesFolder = match[1];
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const activitiesPath = path.join(projectPath, activitiesFolder);
|
|
197
|
+
|
|
198
|
+
if (!fs.existsSync(activitiesPath)) {
|
|
199
|
+
issues.push({
|
|
200
|
+
id: 'missing-activities-folder',
|
|
201
|
+
severity: 'warning',
|
|
202
|
+
message: `${activitiesFolder} folder is missing`,
|
|
203
|
+
suggestion: `Create ${activitiesFolder} folder for your activities`,
|
|
204
|
+
fixable: true,
|
|
205
|
+
file: activitiesFolder
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Check environment variables content
|
|
212
|
+
*/
|
|
213
|
+
const checkEnvVariables = async (projectPath: string, issues: DiagnosticIssue[]): Promise<void> => {
|
|
214
|
+
const envPath = path.join(projectPath, '.env');
|
|
215
|
+
if (!fs.existsSync(envPath)) return;
|
|
216
|
+
|
|
217
|
+
const envContent = fs.readFileSync(envPath, 'utf8');
|
|
218
|
+
|
|
219
|
+
// Check if ACTIVITY_FOLDER_NAME is empty
|
|
220
|
+
if (envContent.includes('ACTIVITY_FOLDER_NAME=""') || envContent.includes('ACTIVITY_FOLDER_NAME=\'\'')) {
|
|
221
|
+
issues.push({
|
|
222
|
+
id: 'empty-activity-folder-name',
|
|
223
|
+
severity: 'warning',
|
|
224
|
+
message: 'ACTIVITY_FOLDER_NAME is empty',
|
|
225
|
+
suggestion: 'Set ACTIVITY_FOLDER_NAME to your activity folder name',
|
|
226
|
+
fixable: false
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Check if Adobe credentials are empty
|
|
231
|
+
if (envContent.includes('ADOBE_CLIENT_ID=""') || envContent.includes('ADOBE_CLIENT_ID=\'\'')) {
|
|
232
|
+
issues.push({
|
|
233
|
+
id: 'empty-adobe-client-id',
|
|
234
|
+
severity: 'warning',
|
|
235
|
+
message: 'ADOBE_CLIENT_ID is empty',
|
|
236
|
+
suggestion: 'Set your Adobe Target API client ID',
|
|
237
|
+
fixable: false
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (envContent.includes('ADOBE_CLIENT_SECRET=""') || envContent.includes('ADOBE_CLIENT_SECRET=\'\'')) {
|
|
242
|
+
issues.push({
|
|
243
|
+
id: 'empty-adobe-client-secret',
|
|
244
|
+
severity: 'warning',
|
|
245
|
+
message: 'ADOBE_CLIENT_SECRET is empty',
|
|
246
|
+
suggestion: 'Set your Adobe Target API client secret',
|
|
247
|
+
fixable: false
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Check dependencies
|
|
254
|
+
*/
|
|
255
|
+
const checkDependencies = async (projectPath: string, issues: DiagnosticIssue[]): Promise<void> => {
|
|
256
|
+
const packagePath = path.join(projectPath, 'package.json');
|
|
257
|
+
if (!fs.existsSync(packagePath)) return;
|
|
258
|
+
|
|
259
|
+
const nodeModulesPath = path.join(projectPath, 'node_modules');
|
|
260
|
+
|
|
261
|
+
if (!fs.existsSync(nodeModulesPath)) {
|
|
262
|
+
issues.push({
|
|
263
|
+
id: 'missing-node-modules',
|
|
264
|
+
severity: 'warning',
|
|
265
|
+
message: 'node_modules folder is missing',
|
|
266
|
+
suggestion: 'Run "npm install" to install dependencies',
|
|
267
|
+
fixable: false
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// Fix functions
|
|
273
|
+
|
|
274
|
+
const createEnvFile = async (projectPath: string): Promise<boolean> => {
|
|
275
|
+
const envPath = path.join(projectPath, '.env');
|
|
276
|
+
const envContent = `ACTIVITIES_BASE_FOLDER="Activities"
|
|
277
|
+
ACTIVITY_FOLDER_NAME=""
|
|
278
|
+
PUPPETEER_LANDING_PAGE=""
|
|
279
|
+
TARGET_URL=""
|
|
280
|
+
LOGIN_URL=""
|
|
281
|
+
VARIATION="Variation-1"
|
|
282
|
+
NODE_ENV="development"
|
|
283
|
+
VERBOSE=false
|
|
284
|
+
|
|
285
|
+
# Adobe Target Deployment Configuration
|
|
286
|
+
ADOBE_CLIENT_ID=""
|
|
287
|
+
ADOBE_CLIENT_SECRET=""`;
|
|
288
|
+
|
|
289
|
+
try {
|
|
290
|
+
fs.writeFileSync(envPath, envContent, 'utf8');
|
|
291
|
+
return true;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const createAdobeConfig = async (projectPath: string): Promise<boolean> => {
|
|
298
|
+
const configPath = path.join(projectPath, 'adobe.config.js');
|
|
299
|
+
const configContent = `/**
|
|
300
|
+
* Adobe Target API Configuration
|
|
301
|
+
*
|
|
302
|
+
* Configuration constants for Adobe Target API integration.
|
|
303
|
+
* These values are used by the deployment script to connect to Adobe Target.
|
|
304
|
+
*/
|
|
305
|
+
|
|
306
|
+
module.exports = {
|
|
307
|
+
// Adobe Target API base URL
|
|
308
|
+
BASE_URL: 'https://mc.adobe.io/target/activities/',
|
|
309
|
+
|
|
310
|
+
// Adobe IMS (Identity Management Services) token endpoint
|
|
311
|
+
IMS_TOKEN_URL: 'https://ims-na1.adobelogin.com/ims/token/v1',
|
|
312
|
+
|
|
313
|
+
// Required scopes for Adobe Target API access
|
|
314
|
+
IMS_SCOPE: 'openid,target_sdk'
|
|
315
|
+
};`;
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
fs.writeFileSync(configPath, configContent, 'utf8');
|
|
319
|
+
return true;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const createWatchConfig = async (projectPath: string): Promise<boolean> => {
|
|
326
|
+
const configPath = path.join(projectPath, 'watch-config.json');
|
|
327
|
+
const configContent = {
|
|
328
|
+
"VARIATION": "Variation-1"
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
try {
|
|
332
|
+
fs.writeFileSync(configPath, JSON.stringify(configContent, null, 2), 'utf8');
|
|
333
|
+
return true;
|
|
334
|
+
} catch (error) {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
const createActivitiesFolder = async (projectPath: string): Promise<boolean> => {
|
|
340
|
+
// Try to read ACTIVITIES_BASE_FOLDER from .env, fallback to default
|
|
341
|
+
let activitiesFolder = 'Activities';
|
|
342
|
+
const envPath = path.join(projectPath, '.env');
|
|
343
|
+
|
|
344
|
+
if (fs.existsSync(envPath)) {
|
|
345
|
+
const envContent = fs.readFileSync(envPath, 'utf8');
|
|
346
|
+
const match = envContent.match(/ACTIVITIES_BASE_FOLDER=["']?([^"'\n\r]+)["']?/);
|
|
347
|
+
if (match) {
|
|
348
|
+
activitiesFolder = match[1];
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const activitiesPath = path.join(projectPath, activitiesFolder);
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
fs.mkdirSync(activitiesPath, { recursive: true });
|
|
356
|
+
return true;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const createPackageJson = async (projectPath: string): Promise<boolean> => {
|
|
363
|
+
const packagePath = path.join(projectPath, 'package.json');
|
|
364
|
+
const packageContent = {
|
|
365
|
+
"name": path.basename(projectPath),
|
|
366
|
+
"version": "1.0.0",
|
|
367
|
+
"description": "",
|
|
368
|
+
"main": "index.js",
|
|
369
|
+
"scripts": {
|
|
370
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
371
|
+
},
|
|
372
|
+
"keywords": [],
|
|
373
|
+
"author": "",
|
|
374
|
+
"license": "ISC"
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
try {
|
|
378
|
+
fs.writeFileSync(packagePath, JSON.stringify(packageContent, null, 2), 'utf8');
|
|
379
|
+
return true;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Test validation logic
|
|
2
|
+
const { spawn } = require('child_process');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
console.log('Testing build command without .env file...');
|
|
6
|
+
|
|
7
|
+
// Test without .env file
|
|
8
|
+
const testDir = path.join(__dirname, 'test-empty');
|
|
9
|
+
require('fs').mkdirSync(testDir, { recursive: true });
|
|
10
|
+
|
|
11
|
+
const webpack = spawn('node', [path.join(__dirname, 'bin/index.js'), 'build'], {
|
|
12
|
+
cwd: testDir,
|
|
13
|
+
env: { ...process.env, ACTIVITY_FOLDER_NAME: '' },
|
|
14
|
+
stdio: 'inherit'
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
webpack.on('exit', (code) => {
|
|
18
|
+
console.log(`Build process exited with code: ${code}`);
|
|
19
|
+
// Clean up
|
|
20
|
+
require('fs').rmSync(testDir, { recursive: true, force: true });
|
|
21
|
+
});
|
package/tsconfig.json
CHANGED
package/webpack.config.js
CHANGED
|
@@ -74,7 +74,40 @@ var traversePath = function (dir) {
|
|
|
74
74
|
|
|
75
75
|
// console.log("\x1b[33m%s\x1b[0m", `${process.env.ACTIVITY_FOLDER_NAME}`);
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
// Validate required environment variables
|
|
78
|
+
if (!process.env.ACTIVITY_FOLDER_NAME || process.env.ACTIVITY_FOLDER_NAME.trim() === '') {
|
|
79
|
+
console.error('\x1b[31m%s\x1b[0m', '❌ Error: ACTIVITY_FOLDER_NAME environment variable is required but not set.');
|
|
80
|
+
console.error('\x1b[33m%s\x1b[0m', '💡 Please set ACTIVITY_FOLDER_NAME in your .env file or run "atb doctor --fix" to check your configuration.');
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Use configurable activities folder name from environment
|
|
85
|
+
const ACTIVITIES_BASE_FOLDER = process.env.ACTIVITIES_BASE_FOLDER || 'Activities';
|
|
86
|
+
const ACTIVITY_FOLDER = process.env.ACTIVITY_FOLDER_NAME.trim();
|
|
87
|
+
|
|
88
|
+
console.log('\x1b[36m%s\x1b[0m', `📦 Building activity: ${ACTIVITY_FOLDER}`);
|
|
89
|
+
console.log('\x1b[36m%s\x1b[0m', `📁 Activities folder: ${ACTIVITIES_BASE_FOLDER}`);
|
|
90
|
+
|
|
91
|
+
// Check if the activity folder exists
|
|
92
|
+
const activityPath = path.join(PWD, ACTIVITIES_BASE_FOLDER, ACTIVITY_FOLDER);
|
|
93
|
+
if (!fs.existsSync(activityPath)) {
|
|
94
|
+
console.error('\x1b[31m%s\x1b[0m', `❌ Error: Activity folder not found: ${activityPath}`);
|
|
95
|
+
console.error('\x1b[33m%s\x1b[0m', '💡 Please check your ACTIVITY_FOLDER_NAME or create the activity folder first.');
|
|
96
|
+
console.error('\x1b[33m%s\x1b[0m', '💡 Run "atb new" to create a new activity or "atb doctor" to diagnose issues.');
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
var files = traversePath(activityPath.toString());
|
|
101
|
+
|
|
102
|
+
// Check if we found any files to build
|
|
103
|
+
if (!files || files.length === 0) {
|
|
104
|
+
console.error('\x1b[31m%s\x1b[0m', `❌ Error: No buildable files found in ${activityPath}`);
|
|
105
|
+
console.error('\x1b[33m%s\x1b[0m', '💡 Please ensure your activity folder contains variations (folders starting with "V") with .js or .ts files.');
|
|
106
|
+
console.error('\x1b[33m%s\x1b[0m', '💡 Expected structure: Activities/your-activity/Variation-1/index.js');
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log('\x1b[36m%s\x1b[0m', `🔍 Found ${files.length} file(s) to build`);
|
|
78
111
|
|
|
79
112
|
//Create entry object which is needed for webpack config
|
|
80
113
|
var entries = {};
|