at-builder 1.4.4 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/bin/constants/config.js +1 -1
- package/bin/index.js +153 -66
- package/bin/services/telemetry.js +320 -0
- package/package.json +12 -1
- package/.claude/settings.local.json +0 -77
- package/.plop/index.js +0 -5
- package/.vscode/settings.json +0 -6
- package/CustomWrapperPlugin.js +0 -61
- package/DEVELOPMENT.md +0 -164
- package/at-builder-0.0.2.vsix +0 -0
- package/package/package.json +0 -86
- package/src/constants/config.ts +0 -321
- package/src/index.ts +0 -387
- package/src/services/doctor.ts +0 -724
- package/src/services/logger.ts +0 -84
package/package/package.json
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "at-builder",
|
|
3
|
-
"version": "1.3.0",
|
|
4
|
-
"main": "bin/index.js",
|
|
5
|
-
"bin": {
|
|
6
|
-
"atb": "bin/index.js"
|
|
7
|
-
},
|
|
8
|
-
"scripts": {
|
|
9
|
-
"build:atb": "tsc",
|
|
10
|
-
"build:atb:dev": "tsc -w",
|
|
11
|
-
"atb:build:prod": "cross-env NODE_ENV=production webpack",
|
|
12
|
-
"atb:build:dev": "webpack -- -w",
|
|
13
|
-
"atb:build:dev:puppeteer": "webpack -- -w & npm run atb:puppeteer",
|
|
14
|
-
"atb:puppeteer": "node puppeteer.js $b",
|
|
15
|
-
"atb:plop:new:activity": "plop page",
|
|
16
|
-
"atb:build:deploy": "node lib/at-deploy.js",
|
|
17
|
-
"atb:build:sync": "node lib/at-sync.js"
|
|
18
|
-
},
|
|
19
|
-
"author": "Upendra Sengar <upendrasengar456@gmail.com>",
|
|
20
|
-
"license": "MIT",
|
|
21
|
-
"dependencies": {
|
|
22
|
-
"@babel/core": "^7.26.9",
|
|
23
|
-
"@babel/eslint-parser": "^7.26.8",
|
|
24
|
-
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
25
|
-
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
|
26
|
-
"@babel/plugin-transform-runtime": "^7.18.9",
|
|
27
|
-
"@babel/preset-env": "^7.18.9",
|
|
28
|
-
"@babel/preset-react": "^7.18.6",
|
|
29
|
-
"@eslint/js": "^9.20.0",
|
|
30
|
-
"@types/node": "^22.13.2",
|
|
31
|
-
"async": "^3.2.3",
|
|
32
|
-
"axios": "^1.12.2",
|
|
33
|
-
"babel-loader": "^9.2.1",
|
|
34
|
-
"babel-plugin-transform-async-to-generator": "^6.24.1",
|
|
35
|
-
"build": "^0.1.4",
|
|
36
|
-
"chokidar": "^4.0.3",
|
|
37
|
-
"cli-color": "^2.0.3",
|
|
38
|
-
"commander": "^13.1.0",
|
|
39
|
-
"cross-env": "^7.0.3",
|
|
40
|
-
"css-loader": "^7.1.2",
|
|
41
|
-
"dotenv": "16.4.5",
|
|
42
|
-
"eslint": "^9.20.1",
|
|
43
|
-
"eslint-webpack-plugin": "^4.2.0",
|
|
44
|
-
"globals": "^15.15.0",
|
|
45
|
-
"inquirer": "^12.4.1",
|
|
46
|
-
"kleur": "^4.1.5",
|
|
47
|
-
"plop": "^4.0.1",
|
|
48
|
-
"postcss": "^8.4.12",
|
|
49
|
-
"postcss-loader": "^8.1.1",
|
|
50
|
-
"postcss-preset-env": "^10.1.4",
|
|
51
|
-
"puppeteer": "^24.2.0",
|
|
52
|
-
"querystring": "^0.2.1",
|
|
53
|
-
"readline": "^1.3.0",
|
|
54
|
-
"sass": "^1.53.0",
|
|
55
|
-
"sass-loader": "^16.0.4",
|
|
56
|
-
"style-loader": "^4.0.0",
|
|
57
|
-
"terser-webpack-plugin": "^5.3.3",
|
|
58
|
-
"ts-loader": "^9.3.1",
|
|
59
|
-
"typescript": "^5.7.3",
|
|
60
|
-
"typescript-eslint": "^8.24.1",
|
|
61
|
-
"webpack": "^5.72.0",
|
|
62
|
-
"webpack-cli": "^6.0.1",
|
|
63
|
-
"wrapper-webpack-plugin": "^2.1.0"
|
|
64
|
-
},
|
|
65
|
-
"description": "[](https://www.npmjs.com/package/at-builder) [](LICENSE)",
|
|
66
|
-
"directories": {
|
|
67
|
-
"lib": "lib",
|
|
68
|
-
"test": "test"
|
|
69
|
-
},
|
|
70
|
-
"devDependencies": {
|
|
71
|
-
"@babel/runtime": "^7.29.2"
|
|
72
|
-
},
|
|
73
|
-
"repository": {
|
|
74
|
-
"type": "git",
|
|
75
|
-
"url": "git+https://github.com/upesenga/at-builder.git"
|
|
76
|
-
},
|
|
77
|
-
"keywords": [],
|
|
78
|
-
"bugs": {
|
|
79
|
-
"url": "https://github.com/upesenga/at-builder/issues"
|
|
80
|
-
},
|
|
81
|
-
"homepage": "https://github.com/upesenga/at-builder#readme",
|
|
82
|
-
"engines": {
|
|
83
|
-
"node": ">=16.0.0"
|
|
84
|
-
},
|
|
85
|
-
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
|
|
86
|
-
}
|
package/src/constants/config.ts
DELETED
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import clc from "cli-color";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Reads and returns the version from package.json
|
|
7
|
-
* @returns {Promise<string>} The version of the package
|
|
8
|
-
*/
|
|
9
|
-
export const getVersion = async () => {
|
|
10
|
-
const packageJSONPath = path.resolve(__dirname, "../../package.json");
|
|
11
|
-
try {
|
|
12
|
-
const content = await fs.promises.readFile(packageJSONPath, { encoding: "utf8" });
|
|
13
|
-
const config = JSON.parse(content);
|
|
14
|
-
return config.version;
|
|
15
|
-
} catch (error) {
|
|
16
|
-
console.error(clc.red("Error reading package.json or parsing JSON"));
|
|
17
|
-
process.exit(1); // Exit the process if package.json is not found or malformed
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
exports.getVersion = getVersion;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Helper function for formatting colorized text
|
|
25
|
-
* @param {string} text The text to format
|
|
26
|
-
* @param {string} color The color for the text
|
|
27
|
-
* @param {boolean} bold Whether to make the text bold
|
|
28
|
-
* @param {boolean} underline Whether to underline the text
|
|
29
|
-
* @returns {string} The formatted text
|
|
30
|
-
*/
|
|
31
|
-
const formatText = (text: string, color: string = "white", bold: boolean = false, underline: boolean = false): string => {
|
|
32
|
-
let formattedText = text;
|
|
33
|
-
|
|
34
|
-
// Apply color
|
|
35
|
-
const colorFn = clc[color as keyof typeof clc];
|
|
36
|
-
if (typeof colorFn === 'function') {
|
|
37
|
-
formattedText = colorFn(text);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Apply formatting
|
|
41
|
-
if (bold) formattedText = clc.bold(formattedText);
|
|
42
|
-
if (underline) formattedText = clc.underline(formattedText);
|
|
43
|
-
|
|
44
|
-
return formattedText;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Returns help information with commands and usage
|
|
49
|
-
* @returns {Promise<string>} The help text
|
|
50
|
-
*/
|
|
51
|
-
export const getHelpInfo = async () => {
|
|
52
|
-
const version = await getVersion();
|
|
53
|
-
|
|
54
|
-
return `
|
|
55
|
-
${formatText(`🎯 at-builder`, 'cyan', true)} ${formatText(`v${version}`, 'gray')}
|
|
56
|
-
|
|
57
|
-
${formatText("Adobe Target Activity Development CLI", 'white', true)}
|
|
58
|
-
|
|
59
|
-
A streamlined command-line tool for creating, building, and deploying Adobe Target
|
|
60
|
-
A/B testing activities with modern web technologies.
|
|
61
|
-
|
|
62
|
-
${formatText("USAGE", 'yellow', true)}
|
|
63
|
-
${formatText("atb", 'cyan')} ${formatText("<command> [options]", 'gray')}
|
|
64
|
-
|
|
65
|
-
${formatText("COMMANDS", 'yellow', true)}
|
|
66
|
-
${formatText("init", 'cyan', true)} Initialize project with .env configuration and templates
|
|
67
|
-
${formatText("new", 'cyan', true)} Create a new Adobe Target activity with variations
|
|
68
|
-
${formatText("build", 'cyan', true)} Build activity for development
|
|
69
|
-
${formatText("build --prod", 'cyan', true)} Build for production deployment
|
|
70
|
-
${formatText("dev", 'cyan', true)} Start development server with file watching
|
|
71
|
-
${formatText("dev --browser", 'cyan', true)} Start development server and open in browser
|
|
72
|
-
${formatText("deploy", 'cyan', true)} Deploy activity to Adobe Target
|
|
73
|
-
${formatText("deploy --dry-run", 'cyan', true)} Deploy in dry-run mode without actual deployment
|
|
74
|
-
${formatText("deploy --force", 'cyan', true)} Override the 60s post-deploy cooldown lock
|
|
75
|
-
${formatText("sync", 'cyan', true)} Sync build.config.json with the AT activity (pages, experiences, names)
|
|
76
|
-
${formatText("sync --scaffold", 'cyan', true)} Sync and auto-create any missing variation folders with boilerplate
|
|
77
|
-
${formatText("doctor", 'cyan', true)} Diagnose and fix project configuration issues
|
|
78
|
-
${formatText("doctor --fix", 'cyan', true)} Automatically fix detected configuration issues
|
|
79
|
-
${formatText("install-extension", 'cyan', true)} Install the at-builder extension from the Marketplace (default: VSCode)
|
|
80
|
-
${formatText("install-extension --editor agy", 'cyan', true)} Install into Antigravity IDE (also: cursor, codium, etc.)
|
|
81
|
-
|
|
82
|
-
${formatText("GLOBAL OPTIONS", 'yellow', true)}
|
|
83
|
-
${formatText("-v, --verbose", 'green')} Enable detailed logging
|
|
84
|
-
${formatText("-V, --version", 'green')} Display version information
|
|
85
|
-
${formatText("-h, --help", 'green')} Show help information
|
|
86
|
-
|
|
87
|
-
${formatText("EXAMPLES", 'yellow', true)}
|
|
88
|
-
${formatText("# Initialize new project", 'gray')}
|
|
89
|
-
${formatText("atb init", 'white')}
|
|
90
|
-
|
|
91
|
-
${formatText("# Create new activity", 'gray')}
|
|
92
|
-
${formatText("atb new", 'white')}
|
|
93
|
-
|
|
94
|
-
${formatText("# Development build with hot reload", 'gray')}
|
|
95
|
-
${formatText("atb build", 'white')}
|
|
96
|
-
|
|
97
|
-
${formatText("# Production build for Adobe Target deployment", 'gray')}
|
|
98
|
-
${formatText("atb build --prod", 'white')}
|
|
99
|
-
|
|
100
|
-
${formatText("# Development server with browser", 'gray')}
|
|
101
|
-
${formatText("atb dev --browser", 'white')}
|
|
102
|
-
|
|
103
|
-
${formatText("# Deploy to Adobe Target", 'gray')}
|
|
104
|
-
${formatText("atb deploy", 'white')}
|
|
105
|
-
|
|
106
|
-
${formatText("# Deploy in dry-run mode", 'gray')}
|
|
107
|
-
${formatText("atb deploy --dry-run", 'white')}
|
|
108
|
-
|
|
109
|
-
${formatText("# Sync build.config.json from Adobe Target", 'gray')}
|
|
110
|
-
${formatText("atb sync", 'white')}
|
|
111
|
-
|
|
112
|
-
${formatText("# Sync and scaffold missing variation folders", 'gray')}
|
|
113
|
-
${formatText("atb sync --scaffold", 'white')}
|
|
114
|
-
|
|
115
|
-
${formatText("# Check project configuration", 'gray')}
|
|
116
|
-
${formatText("atb doctor", 'white')}
|
|
117
|
-
|
|
118
|
-
${formatText("# Auto-fix configuration issues", 'gray')}
|
|
119
|
-
${formatText("atb doctor --fix", 'white')}
|
|
120
|
-
|
|
121
|
-
${formatText("WORKFLOW", 'yellow', true)}
|
|
122
|
-
${formatText("1.", 'cyan')} Run ${formatText("atb init", 'white')} to set up project configuration
|
|
123
|
-
${formatText("2.", 'cyan')} Run ${formatText("atb new", 'white')} to create activity templates
|
|
124
|
-
${formatText("3.", 'cyan')} Develop variations in ${formatText("/Activities/{name}/Variation-*/", 'gray')}
|
|
125
|
-
${formatText("4.", 'cyan')} Run ${formatText("atb build", 'white')} for development testing
|
|
126
|
-
${formatText("5.", 'cyan')} Run ${formatText("atb build --prod", 'white')} for Adobe Target deployment
|
|
127
|
-
${formatText("6.", 'cyan')} Run ${formatText("atb deploy", 'white')} to deploy to Adobe Target
|
|
128
|
-
|
|
129
|
-
${formatText("SUPPORT", 'yellow', true)}
|
|
130
|
-
Repository: ${formatText("https://github.com/upesenga/at-builder", 'blue')}
|
|
131
|
-
Issues: ${formatText("https://github.com/upesenga/at-builder/issues", 'blue')}
|
|
132
|
-
License: ${formatText("MIT", 'green')}
|
|
133
|
-
`;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
export const setupEnv = async (basePath) => {
|
|
138
|
-
// Path to the .env file
|
|
139
|
-
const envPath = path.join(basePath, '.env');
|
|
140
|
-
|
|
141
|
-
// Check if the .env file exists
|
|
142
|
-
if (!fs.existsSync(envPath)) {
|
|
143
|
-
// Define the content of the .env file
|
|
144
|
-
const envContent = `
|
|
145
|
-
ACTIVITIES_BASE_FOLDER="Activities"
|
|
146
|
-
ACTIVITY_FOLDER_NAME=""
|
|
147
|
-
PUPPETEER_LANDING_PAGE=""
|
|
148
|
-
TARGET_URL=""
|
|
149
|
-
LOGIN_URL=""
|
|
150
|
-
|
|
151
|
-
# Dev-server selection (used by \`atb dev --browser\`).
|
|
152
|
-
# Edit and save while puppeteer is running to hot-swap the previewed bundle.
|
|
153
|
-
# PAGE is only meaningful for multi-page activities — leave empty otherwise.
|
|
154
|
-
VARIATION="Variation-1"
|
|
155
|
-
PAGE=""
|
|
156
|
-
|
|
157
|
-
NODE_ENV="development"
|
|
158
|
-
VERBOSE=false
|
|
159
|
-
|
|
160
|
-
# Build wrapper config.
|
|
161
|
-
# TARGET_BUILD_PREFIX customizes the window flag baked into each build —
|
|
162
|
-
# rendered as window.\${TARGET_BUILD_PREFIX}_\${contentHash}_\${hash}. Defaults
|
|
163
|
-
# to "TargetBuild" when empty. Useful when multiple at-builder activities
|
|
164
|
-
# end up loaded on the same page and you want each project's flag namespaced.
|
|
165
|
-
TARGET_BUILD_PREFIX=""
|
|
166
|
-
|
|
167
|
-
# Adobe Target Deployment Configuration
|
|
168
|
-
# ADOBE_TENANT is your AT tenant slug — find it in the AT URL after "mc.adobe.io/".
|
|
169
|
-
ADOBE_TENANT=""
|
|
170
|
-
ADOBE_CLIENT_ID=""
|
|
171
|
-
ADOBE_CLIENT_SECRET=""
|
|
172
|
-
`;
|
|
173
|
-
// Write the content to the .env file
|
|
174
|
-
fs.writeFileSync(envPath, envContent.trim(), 'utf8');
|
|
175
|
-
console.log('.env file created successfully!');
|
|
176
|
-
} else {
|
|
177
|
-
console.log('.env file already exists!');
|
|
178
|
-
}
|
|
179
|
-
// watch-config.json is no longer scaffolded by `atb init` — VARIATION/PAGE
|
|
180
|
-
// now live in .env. Existing projects with a watch-config.json keep working
|
|
181
|
-
// (puppeteer.js prefers it with a deprecation warning); `atb doctor --fix`
|
|
182
|
-
// migrates the values into .env and deletes the legacy file.
|
|
183
|
-
createAdobeConfig(basePath);
|
|
184
|
-
createGitignore(basePath);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Default .gitignore content for at-builder consumer projects.
|
|
189
|
-
*
|
|
190
|
-
* Shared between `atb init` (via setupEnv) and `atb doctor --fix` so the two
|
|
191
|
-
* paths stay in lockstep. Covers secrets, deploy-runtime artifacts, build
|
|
192
|
-
* output, and OS noise. Does NOT ignore the Activities folder — those are the
|
|
193
|
-
* user's source files and should be committed.
|
|
194
|
-
*/
|
|
195
|
-
export const GITIGNORE_TEMPLATE = `# Dependencies
|
|
196
|
-
node_modules/
|
|
197
|
-
|
|
198
|
-
# Environment / secrets — never commit
|
|
199
|
-
.env
|
|
200
|
-
.env.local
|
|
201
|
-
|
|
202
|
-
# Adobe Target deploy runtime (cooldown lock written by \`atb deploy\`)
|
|
203
|
-
.deploy-lock
|
|
204
|
-
|
|
205
|
-
# Build output (regenerated by \`atb build\`)
|
|
206
|
-
dist/
|
|
207
|
-
|
|
208
|
-
# OS noise
|
|
209
|
-
.DS_Store
|
|
210
|
-
|
|
211
|
-
# Editor / local-history
|
|
212
|
-
.history/
|
|
213
|
-
|
|
214
|
-
# Logs
|
|
215
|
-
*.log
|
|
216
|
-
npm-debug.log*
|
|
217
|
-
`;
|
|
218
|
-
|
|
219
|
-
const createGitignore = (basePath) => {
|
|
220
|
-
const gitignorePath = path.join(basePath, '.gitignore');
|
|
221
|
-
|
|
222
|
-
if (!fs.existsSync(gitignorePath)) {
|
|
223
|
-
fs.writeFileSync(gitignorePath, GITIGNORE_TEMPLATE, 'utf8');
|
|
224
|
-
console.log('.gitignore file created successfully!');
|
|
225
|
-
} else {
|
|
226
|
-
console.log('.gitignore file already exists!');
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const createWatchConfig = (basePath) => {
|
|
232
|
-
|
|
233
|
-
// Path to the watch-config.json file
|
|
234
|
-
const watchConfigPath = path.join(basePath, 'watch-config.json');
|
|
235
|
-
|
|
236
|
-
// Default content for watch-config.json.
|
|
237
|
-
// VARIATION : which variation/experience to preview in `atb dev --browser`
|
|
238
|
-
// PAGE : leave empty for single-page activities; set to the page
|
|
239
|
-
// subfolder name (e.g. "Global", "Cart") for multi-page.
|
|
240
|
-
// Editing this file mid-session hot-swaps the preview.
|
|
241
|
-
const watchConfigContent = {
|
|
242
|
-
"VARIATION": "Variation-1",
|
|
243
|
-
"PAGE": ""
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
// Check if the watch-config.json file already exists
|
|
247
|
-
if (!fs.existsSync(watchConfigPath)) {
|
|
248
|
-
fs.writeFileSync(watchConfigPath, JSON.stringify(watchConfigContent, null, 2), 'utf8');
|
|
249
|
-
console.log('watch-config.json file created successfully!');
|
|
250
|
-
} else {
|
|
251
|
-
console.log('watch-config.json file already exists!');
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const createAdobeConfig = (basePath) => {
|
|
256
|
-
// Path to the adobe.config.js file
|
|
257
|
-
const adobeConfigPath = path.join(basePath, 'adobe.config.js');
|
|
258
|
-
|
|
259
|
-
// Default content for adobe.config.js
|
|
260
|
-
const adobeConfigContent = `/**
|
|
261
|
-
* Adobe Target API Configuration
|
|
262
|
-
*
|
|
263
|
-
* Used by at-sync.js and at-deploy.js. BASE_URL is the activities root —
|
|
264
|
-
* callers append \`\${activityType}/\${activityId}\` (e.g. ab/12345, xt/67890).
|
|
265
|
-
*
|
|
266
|
-
* ADOBE_TENANT comes from the consumer .env. Both at-sync and at-deploy load
|
|
267
|
-
* dotenv before requiring this file, so process.env is populated by the time
|
|
268
|
-
* BASE_URL is built.
|
|
269
|
-
*/
|
|
270
|
-
|
|
271
|
-
const TENANT = process.env.ADOBE_TENANT || 'YOUR_TENANT';
|
|
272
|
-
|
|
273
|
-
module.exports = {
|
|
274
|
-
BASE_URL: \`https://mc.adobe.io/\${TENANT}/target/activities/\`,
|
|
275
|
-
IMS_TOKEN_URL: 'https://ims-na1.adobelogin.com/ims/token/v3',
|
|
276
|
-
IMS_SCOPE: 'openid,AdobeID,target_sdk,additional_info.projectedProductContext'
|
|
277
|
-
};`;
|
|
278
|
-
|
|
279
|
-
// Check if the adobe.config.js file already exists
|
|
280
|
-
if (!fs.existsSync(adobeConfigPath)) {
|
|
281
|
-
fs.writeFileSync(adobeConfigPath, adobeConfigContent, 'utf8');
|
|
282
|
-
console.log('adobe.config.js file created successfully!');
|
|
283
|
-
} else {
|
|
284
|
-
console.log('adobe.config.js file already exists!');
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Reads and returns environment variables from the specified .env file.
|
|
290
|
-
*
|
|
291
|
-
* Throws if the file is missing or unreadable. Callers decide whether
|
|
292
|
-
* to surface the failure — printing here would spam every `atb` run from
|
|
293
|
-
* a directory that doesn't have a `.env` (e.g. `atb --version` from /tmp).
|
|
294
|
-
*
|
|
295
|
-
* @param basePath - The base path where the .env file is located
|
|
296
|
-
* @returns Object containing environment variables
|
|
297
|
-
*/
|
|
298
|
-
export const getENV = async (basePath: string) => {
|
|
299
|
-
const envPath = path.join(basePath, '.env');
|
|
300
|
-
if (!fs.existsSync(envPath)) {
|
|
301
|
-
throw new Error('.env file not found');
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const envContent = await fs.promises.readFile(envPath, { encoding: 'utf8' });
|
|
305
|
-
|
|
306
|
-
const envVars: { [key: string]: string } = {};
|
|
307
|
-
envContent.split('\n').forEach(line => {
|
|
308
|
-
line = line.trim();
|
|
309
|
-
// Skip empty lines and comments
|
|
310
|
-
if (line && !line.startsWith('#')) {
|
|
311
|
-
const [key, ...valueParts] = line.split('=');
|
|
312
|
-
if (key) {
|
|
313
|
-
const value = valueParts.join('=').trim();
|
|
314
|
-
// Remove quotes if present
|
|
315
|
-
envVars[key.trim()] = value.replace(/^["'](.*)["']$/, '$1');
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
return envVars;
|
|
321
|
-
};
|