Setting the file. One moment. Config Env · Wix Replatform · wix/skills · Skills Docslib/config-env.js
JavaScript·133 lines·3 KB
/
\r
?
\n
/
);
10 for (const rawLine of lines) {
11 const line = rawLine.trim();
12 if (!line || line.startsWith('#')) {
13 continue;
14 }
15 const idx = line.indexOf('=');
16 if (idx === -1) {
17 continue;
18 }
19 const key = line.slice(0, idx).trim();
20 const value = line.slice(idx + 1);
21 values[key] = value;
22 }
23 return values;
24}
25
26async function readEnvFile(filePath) {
27 const raw = await fs.readFile(filePath, 'utf8');
28 return parseEnvText(raw);
29}
30
31function statEnvValues(values, requiredKeys, options = {}) {
32 const placeholder = options.placeholder || PLACEHOLDER_VALUE;
33 const keys = {};
34 for (const key of requiredKeys) {
35 if (!(key in values)) {
36 keys[key] = 'missing';
37 } else if (String(values[key]).trim() === '') {
38 keys[key] = 'blank';
39 } else if (String(values[key]) === placeholder) {
40 keys[key] = 'placeholder';
41 } else {
42 keys[key] = 'present';
43 }
44 }
45 return keys;
46}
47
48async function statEnvKeys(filePath, requiredKeys, options = {}) {
49 try {
50 const values = await readEnvFile(filePath);
51 const keys = statEnvValues(values, requiredKeys, options);
52 return { exists: true, keys };
53 } catch (error) {
54 if (error && error.code === 'ENOENT') {
55 const keys = {};
56 for (const key of requiredKeys) {
57 keys[key] = 'missing';
58 }
59 return { exists: false, keys };
60 }
61 throw error;
62 }
63}
64
65function assertEnvValueSafe(value, key) {
66 if (String(value).includes('\n') || String(value).includes('\r')) {
67 throw new Error(`${key} contains a newline and cannot be written to simple .env syntax`);
68 }
69}
70
71function renderEnvLine(key, value) {
72 assertEnvValueSafe(value, key);
73 return `${key}=${value}`;
74}
75
76function upsertEnvText(text, updates) {
77 const updateKeys = Object.keys(updates);
78 const seen = new Set();
79 const source = String(text);
80 const hasTrailingNewline = /\r?\n$/.test(source);
81 const lines = source === '' ? [] : source.split(/\r?\n/);
82 if (hasTrailingNewline && lines[lines.length - 1] === '') {
83 lines.pop();
84 }
85 const rendered = lines.map((rawLine) => {
86 const trimmed = rawLine.trim();
87 if (!trimmed || trimmed.startsWith('#')) {
88 return rawLine;
89 }
90 const idx = rawLine.indexOf('=');
91 if (idx === -1) {
92 return rawLine;
93 }
94 const key = rawLine.slice(0, idx).trim();
95 if (!Object.prototype.hasOwnProperty.call(updates, key)) {
96 return rawLine;
97 }
98 seen.add(key);
99 return renderEnvLine(key, updates[key]);
100 });
101
102 for (const key of updateKeys) {
103 if (!seen.has(key)) {
104 rendered.push(renderEnvLine(key, updates[key]));
105 }
106 }
107
108 const out = rendered.join('\n');
109 return hasTrailingNewline || updateKeys.some((key) => !seen.has(key)) ? `${out.replace(/\n$/, '')}\n` : out;
110}
111
112async function upsertEnvFile(filePath, updates) {
113 let raw = '';
114 try {
115 raw = await fs.readFile(filePath, 'utf8');
116 } catch (error) {
117 if (!error || error.code !== 'ENOENT') {
118 throw error;
119 }
120 }
121 await fs.mkdir(require('node:path').dirname(filePath), { recursive: true });
122 await fs.writeFile(filePath, upsertEnvText(raw, updates), 'utf8');
123}
124
125module.exports = {
126 PLACEHOLDER_VALUE,
127 parseEnvText,
128 readEnvFile,
129 statEnvValues,
130 statEnvKeys,
131 upsertEnvText,
132 upsertEnvFile,
133};