@wwkit/shared 1.0.14 → 1.0.16

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/shell.js +47 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wwkit/shared",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "author": "bluesliu <langcai163@163.com>",
5
5
  "description": "Shared utilities for @wwkit packages — config loader, platform detection",
6
6
  "type": "module",
package/src/shell.js CHANGED
@@ -214,6 +214,12 @@ export class Shell {
214
214
  /**
215
215
  * 向指定 profile 文件写入/更新一个环境变量标记块
216
216
  *
217
+ * 写入前先清理文件中所有同名的裸 export/set 行(非标记块内的),
218
+ * 避免裸行与标记块并存导致残留误导。
219
+ * 标记块用单行注释头(无尾标记),形如:
220
+ * # >>> wwkit NAME >>>
221
+ * export NAME="value"
222
+ *
217
223
  * @param {string} profilePath - profile 文件绝对路径
218
224
  * @param {string} name - 环境变量名(用于生成标记)
219
225
  * @param {string} line - 变量设置行(含正确语法)
@@ -225,28 +231,59 @@ export class Shell {
225
231
  existing = fs.readFileSync(profilePath, 'utf8')
226
232
  } catch {}
227
233
 
228
- const beginMarker = `# >>> wwkit ${name} >>>`
229
- const endMarker = `# <<< wwkit ${name} <<<`
230
- const block = `${beginMarker}\n${line}\n${endMarker}`
234
+ const marker = `# >>> wwkit ${name} >>>`
235
+ const oldEndMarker = `# <<< wwkit ${name} <<<`
236
+
237
+ // 清理同名裸 export/set 行(不在任何标记块内的)
238
+ existing = this._stripBareEnvLines(existing, name)
231
239
 
232
- const beginIdx = existing.indexOf(beginMarker)
240
+ const beginIdx = existing.indexOf(marker)
233
241
  if (beginIdx !== -1) {
234
- const endIdx = existing.indexOf(endMarker)
235
- if (endIdx !== -1 && existing.includes(line)) {
236
- return false
242
+ const afterMarker = beginIdx + marker.length
243
+ // 块尾:优先找旧版 end marker,其次找下一个 wwkit marker,最后 EOF
244
+ const oldEndIdx = existing.indexOf(oldEndMarker, afterMarker)
245
+ const nextMarkerIdx = existing.indexOf('# >>> wwkit', afterMarker)
246
+ let blockEnd
247
+ if (oldEndIdx !== -1 && (nextMarkerIdx === -1 || oldEndIdx < nextMarkerIdx)) {
248
+ blockEnd = oldEndIdx + oldEndMarker.length
249
+ } else if (nextMarkerIdx !== -1) {
250
+ blockEnd = nextMarkerIdx
251
+ } else {
252
+ blockEnd = existing.length
237
253
  }
238
- const afterEnd = endIdx !== -1 ? endIdx + endMarker.length : beginIdx + beginMarker.length
239
- existing = existing.slice(0, beginIdx) + block + existing.slice(afterEnd)
254
+ const currentBlock = existing.slice(beginIdx, blockEnd)
255
+ const newBlock = `${marker}\n${line}`
256
+ if (currentBlock.trim() === newBlock.trim()) return false
257
+ existing = existing.slice(0, beginIdx) + newBlock + existing.slice(blockEnd)
240
258
  fs.writeFileSync(profilePath, existing, 'utf8')
241
259
  return true
242
260
  }
243
261
 
244
262
  const dir = path.dirname(profilePath)
245
263
  fs.mkdirSync(dir, { recursive: true })
246
- fs.appendFileSync(profilePath, `\n${block}\n`, 'utf8')
264
+ fs.appendFileSync(profilePath, `\n${marker}\n${line}\n`, 'utf8')
247
265
  return true
248
266
  }
249
267
 
268
+ /**
269
+ * 从 profile 内容中删除所有同名的裸 export/set 行(不在标记块内的)
270
+ * @param {string} content
271
+ * @param {string} name
272
+ * @returns {string}
273
+ * @private
274
+ */
275
+ _stripBareEnvLines(content, name) {
276
+ const lines = content.split('\n')
277
+ const barePattern = new RegExp(`^\\s*(export|set -gx)\\s+${name}\\b`)
278
+ let inBlock = false
279
+ return lines.filter((l) => {
280
+ if (l.startsWith('# >>> wwkit ')) { inBlock = true; return true }
281
+ if (l.startsWith('# <<< wwkit ')) { inBlock = false; return true }
282
+ if (inBlock) return true
283
+ return !barePattern.test(l)
284
+ }).join('\n')
285
+ }
286
+
250
287
  /**
251
288
  * 检测系统命令是否可用
252
289
  * Windows: where <cmd>;Unix: which <cmd>