Explorar o código

读取文件,保存文件可以设置编码
const fileData = {
filename: getDaysAgo(0) + '.csv',
content: arrayToCSV(fileList),
encoding: "gb2312"
};

// 调用保存方法
window.electronAPI.saveFile(fileData).then(result => {
if (result.success) {
console.log('文件保存成功:', result.path);
} else {
console.error('文件保存失败:', result.error);
}
});

PUGE hai 5 meses
pai
achega
be41697cbc

+ 23 - 0
dist/win-ia32-unpacked/config.json

@@ -0,0 +1,23 @@
+{
+    "enterURL": "https://m.youtube.com/",
+    "width": 376,
+    "height": 667,
+    "webPreferences": {
+        "webSecurity": false,
+        "nodeIntegration": false,
+        "nativeWindowOpen": false,
+        "preload": "<dir>/preload.js",
+        "worldSafeExecuteJavaScript": true,
+        "enableRemoteModule": false,
+        "safeDialogs": false
+    },
+    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
+    "autoHideMenuBar": true,
+    "redirect":[],
+    "redirectURL":"",
+    "proxy":"",
+    "noCache": false,
+    "interceptor":[
+    ],
+    "preLoadFile": "<dir>/preLoadFile.js"
+}

+ 195 - 0
dist/win-ia32-unpacked/preLoadFile.js

@@ -0,0 +1,195 @@
+function getDaysAgo(n) {
+  const timestamp = Date.now() - (n * 24 * 60 * 60 * 1000);
+  const date = new Date(timestamp);
+  
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, '0');
+  const day = String(date.getDate()).padStart(2, '0');
+  
+  return `${year}-${month}-${day}`;
+}
+
+function csvToArray(csvString) {
+  const lines = csvString.split('\n');
+  const result = [];
+  
+  for (let line of lines) {
+    // 跳过空行
+    if (line.trim() === '') continue;
+    
+    // 按逗号分割,并去除每个字段的空白
+    const row = line.split(',').map(field => field.trim());
+    result.push(row);
+  }
+  
+  return result;
+}
+
+function arrayToCSV(array) {
+  return array.map(row => 
+    row.map(field => String(field)).join(',')
+  ).join('\n');
+}
+
+
+function creatToday(fileList) {
+  for (let index = 1; index < fileList.length - 1; index++) {
+    fileList[index][2] = fileList[index][5]
+    fileList[index][3] = fileList[index][6]
+    fileList[index][4] = fileList[index][7]
+    fileList[index][5] = ""
+    fileList[index][6] = ""
+    fileList[index][7] = ""
+    fileList[index][8] = ""
+    fileList[index][9] = ""
+    fileList[index][10] = ""
+  }
+  const fileData = {
+    filename: getDaysAgo(0) + '.csv',
+    content: arrayToCSV(fileList)
+  };
+
+  // 调用保存方法
+  window.electronAPI.saveFile(fileData).then(result => {
+    if (result.success) {
+      console.log('文件保存成功:', result.path);
+    } else {
+      console.error('文件保存失败:', result.error);
+    }
+  });
+}
+
+
+function saveFile(adtaArr, next) {
+  // 保存数据
+  const fileData = {
+    filename: getDaysAgo(0) + '.csv',
+    content: arrayToCSV(adtaArr)
+  };
+
+  // 调用保存方法
+  window.electronAPI.saveFile(fileData).then(result => {
+    if (result.success) {
+      console.log('文件保存成功:', result.path);
+      setTimeout(() => {
+        if (next) checkData(adtaArr, next)
+      }, 1000);
+    } else {
+      console.error('文件保存失败:', result.error);
+    }
+  });
+}
+
+function cutString (original, before, after, index) {
+  index = index || 0;
+  if (typeof index === "number") {
+    const P = original.indexOf(before, index);
+    if (P > -1) {
+      if (after) {
+        const f = original.indexOf(after, P + before.length);
+        return (f>-1)? original.slice(P + before.toString().length, f):console.error("Tool [在文本中找不到 参数三 "+after+"]");
+      } else {
+        return original.slice(P + before.toString().length);
+      }
+    } else {
+      console.error("Tool [在文本中找不到 参数一 " + before + "]");
+      return
+    }
+  } else {
+    console.error("Tool [sizeTransition:" + index + "不是一个整数!]");
+  }
+}
+
+function checkData (adtaArr) {
+  for (let index = 0; index < adtaArr.length; index++) {
+    const element = adtaArr[index];
+    console.log(element)
+    if (element[1].includes('https://') && element[5] === '') {
+      console.log(element[1])
+      if (location.href.slice(0, 40) == element[1].slice(0, 40)) {
+        setTimeout(() => {
+          document.querySelector('.yt-truncated-text__absolute-button').click()
+          setTimeout(() => {
+            let pdInfo = document.querySelector('.style-scope.ytd-about-channel-renderer').innerText
+            let bfsl = parseInt(cutString(pdInfo,'视频\n\n\t', '次观看'))
+            let spsl = parseInt(cutString(pdInfo,'订阅者\n\n\t', '个视频'))
+            let dyrs = parseInt(cutString(pdInfo,'注册\n\n\t', '位订阅者'))
+            bfsl = bfsl ? bfsl : 0
+            spsl = spsl ? spsl : 0
+            dyrs = dyrs ? dyrs : 0
+            console.log(bfsl, spsl, dyrs)
+            adtaArr[index][5] = bfsl
+            adtaArr[index][6] = spsl
+            adtaArr[index][7] = dyrs
+            adtaArr[index][8] = bfsl - parseInt(adtaArr[index][2])
+            adtaArr[index][9] = spsl - parseInt(adtaArr[index][3])
+            adtaArr[index][10] = dyrs - parseInt(adtaArr[index][4])
+            saveFile(adtaArr, true)
+          }, 3000);
+        }, 2000);
+      } else {
+        location.href = element[1]
+      }
+      
+      return
+    }
+  }
+  // 汇总计算
+  adtaArr[adtaArr.length - 1][2] = 0
+  adtaArr[adtaArr.length - 1][3] = 0
+  adtaArr[adtaArr.length - 1][4] = 0
+  adtaArr[adtaArr.length - 1][5] = 0
+  adtaArr[adtaArr.length - 1][6] = 0
+  adtaArr[adtaArr.length - 1][7] = 0
+  adtaArr[adtaArr.length - 1][8] = 0
+  adtaArr[adtaArr.length - 1][9] = 0
+  adtaArr[adtaArr.length - 1][10] = 0
+  for (let index = 1; index < adtaArr.length - 1; index++) {
+    const element = adtaArr[index];
+    adtaArr[adtaArr.length - 1][2] += parseInt(element[2])
+    adtaArr[adtaArr.length - 1][3] += parseInt(element[3])
+    adtaArr[adtaArr.length - 1][4] += parseInt(element[4])
+    adtaArr[adtaArr.length - 1][5] += parseInt(element[5])
+    adtaArr[adtaArr.length - 1][6] += parseInt(element[6])
+    adtaArr[adtaArr.length - 1][7] += parseInt(element[7])
+    adtaArr[adtaArr.length - 1][8] += parseInt(element[8])
+    adtaArr[adtaArr.length - 1][9] += parseInt(element[9])
+    adtaArr[adtaArr.length - 1][10] += parseInt(element[10])
+  }
+  saveFile(adtaArr, false)
+  alert('所有项目已经检查完!')
+}
+
+
+// 调用保存方法
+window.electronAPI.readFile({filename: getDaysAgo(0) + '.csv', encoding: "utf8"}).then(result => {
+  if (result.success) {
+    console.log(result.content);
+    // 如果内容是空的,则读取昨天的
+    if (result.content == '') {
+      window.electronAPI.readFile({filename: getDaysAgo(1) + '.csv', encoding: "utf8"}).then(result2 => {
+        if (result2.success) {
+          console.log(result2.content);
+          // 如果内容是空的,则读取昨天的
+          if (result2.content == '') {
+            alert('缺少昨天的数据!')
+          } else {
+            let fileData = csvToArray(result2.content)
+            creatToday(fileData)
+            console.log(fileData)
+            checkData(fileData)
+          }
+        } else {
+          console.error('文件读取失败:', result2.error);
+        }
+      });
+    } else {
+      // 读取加载文件
+      let fileData = csvToArray(result.content)
+      console.log(fileData)
+      checkData(fileData)
+    }
+  } else {
+    console.error('文件读取失败:', result.error);
+  }
+});

+ 1 - 0
dist/win-ia32-unpacked/preload.js

@@ -26,6 +26,7 @@ contextBridge.exposeInMainWorld('electronAPI', {
   download: (msg) => ipcRenderer.send('download', msg),
   broadcast: (msg) => ipcRenderer.send('broadcast-message', msg),
   saveFile: (msg) => ipcRenderer.invoke('saveFile', msg),
+  readFile: (msg) => ipcRenderer.invoke('readFile', msg),
   onBroadcast: (callback) => ipcRenderer.on('message-broadcast', (event, data) => callback(data))
 });
 

+ 23 - 0
dist/油管数据/config.json

@@ -0,0 +1,23 @@
+{
+    "enterURL": "https://m.youtube.com/",
+    "width": 376,
+    "height": 667,
+    "webPreferences": {
+        "webSecurity": false,
+        "nodeIntegration": false,
+        "nativeWindowOpen": false,
+        "preload": "<dir>/preload.js",
+        "worldSafeExecuteJavaScript": true,
+        "enableRemoteModule": false,
+        "safeDialogs": false
+    },
+    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
+    "autoHideMenuBar": true,
+    "redirect":[],
+    "redirectURL":"",
+    "proxy":"",
+    "noCache": false,
+    "interceptor":[
+    ],
+    "preLoadFile": "<dir>/preLoadFile.js"
+}

+ 195 - 0
dist/油管数据/preLoadFile.js

@@ -0,0 +1,195 @@
+function getDaysAgo(n) {
+  const timestamp = Date.now() - (n * 24 * 60 * 60 * 1000);
+  const date = new Date(timestamp);
+  
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, '0');
+  const day = String(date.getDate()).padStart(2, '0');
+  
+  return `${year}-${month}-${day}`;
+}
+
+function csvToArray(csvString) {
+  const lines = csvString.split('\n');
+  const result = [];
+  
+  for (let line of lines) {
+    // 跳过空行
+    if (line.trim() === '') continue;
+    
+    // 按逗号分割,并去除每个字段的空白
+    const row = line.split(',').map(field => field.trim());
+    result.push(row);
+  }
+  
+  return result;
+}
+
+function arrayToCSV(array) {
+  return array.map(row => 
+    row.map(field => String(field)).join(',')
+  ).join('\n');
+}
+
+
+function creatToday(fileList) {
+  for (let index = 1; index < fileList.length - 1; index++) {
+    fileList[index][2] = fileList[index][5]
+    fileList[index][3] = fileList[index][6]
+    fileList[index][4] = fileList[index][7]
+    fileList[index][5] = ""
+    fileList[index][6] = ""
+    fileList[index][7] = ""
+    fileList[index][8] = ""
+    fileList[index][9] = ""
+    fileList[index][10] = ""
+  }
+  const fileData = {
+    filename: getDaysAgo(0) + '.csv',
+    content: arrayToCSV(fileList)
+  };
+
+  // 调用保存方法
+  window.electronAPI.saveFile(fileData).then(result => {
+    if (result.success) {
+      console.log('文件保存成功:', result.path);
+    } else {
+      console.error('文件保存失败:', result.error);
+    }
+  });
+}
+
+
+function saveFile(adtaArr, next) {
+  // 保存数据
+  const fileData = {
+    filename: getDaysAgo(0) + '.csv',
+    content: arrayToCSV(adtaArr)
+  };
+
+  // 调用保存方法
+  window.electronAPI.saveFile(fileData).then(result => {
+    if (result.success) {
+      console.log('文件保存成功:', result.path);
+      setTimeout(() => {
+        if (next) checkData(adtaArr, next)
+      }, 1000);
+    } else {
+      console.error('文件保存失败:', result.error);
+    }
+  });
+}
+
+function cutString (original, before, after, index) {
+  index = index || 0;
+  if (typeof index === "number") {
+    const P = original.indexOf(before, index);
+    if (P > -1) {
+      if (after) {
+        const f = original.indexOf(after, P + before.length);
+        return (f>-1)? original.slice(P + before.toString().length, f):console.error("Tool [在文本中找不到 参数三 "+after+"]");
+      } else {
+        return original.slice(P + before.toString().length);
+      }
+    } else {
+      console.error("Tool [在文本中找不到 参数一 " + before + "]");
+      return
+    }
+  } else {
+    console.error("Tool [sizeTransition:" + index + "不是一个整数!]");
+  }
+}
+
+function checkData (adtaArr) {
+  for (let index = 0; index < adtaArr.length; index++) {
+    const element = adtaArr[index];
+    console.log(element)
+    if (element[1].includes('https://') && element[5] === '') {
+      console.log(element[1])
+      if (location.href.slice(0, 40) == element[1].slice(0, 40)) {
+        setTimeout(() => {
+          document.querySelector('.yt-truncated-text__absolute-button').click()
+          setTimeout(() => {
+            let pdInfo = document.querySelector('.style-scope.ytd-about-channel-renderer').innerText
+            let bfsl = parseInt(cutString(pdInfo,'视频\n\n\t', '次观看'))
+            let spsl = parseInt(cutString(pdInfo,'订阅者\n\n\t', '个视频'))
+            let dyrs = parseInt(cutString(pdInfo,'注册\n\n\t', '位订阅者'))
+            bfsl = bfsl ? bfsl : 0
+            spsl = spsl ? spsl : 0
+            dyrs = dyrs ? dyrs : 0
+            console.log(bfsl, spsl, dyrs)
+            adtaArr[index][5] = bfsl
+            adtaArr[index][6] = spsl
+            adtaArr[index][7] = dyrs
+            adtaArr[index][8] = bfsl - parseInt(adtaArr[index][2])
+            adtaArr[index][9] = spsl - parseInt(adtaArr[index][3])
+            adtaArr[index][10] = dyrs - parseInt(adtaArr[index][4])
+            saveFile(adtaArr, true)
+          }, 3000);
+        }, 2000);
+      } else {
+        location.href = element[1]
+      }
+      
+      return
+    }
+  }
+  // 汇总计算
+  adtaArr[adtaArr.length - 1][2] = 0
+  adtaArr[adtaArr.length - 1][3] = 0
+  adtaArr[adtaArr.length - 1][4] = 0
+  adtaArr[adtaArr.length - 1][5] = 0
+  adtaArr[adtaArr.length - 1][6] = 0
+  adtaArr[adtaArr.length - 1][7] = 0
+  adtaArr[adtaArr.length - 1][8] = 0
+  adtaArr[adtaArr.length - 1][9] = 0
+  adtaArr[adtaArr.length - 1][10] = 0
+  for (let index = 1; index < adtaArr.length - 1; index++) {
+    const element = adtaArr[index];
+    adtaArr[adtaArr.length - 1][2] += parseInt(element[2])
+    adtaArr[adtaArr.length - 1][3] += parseInt(element[3])
+    adtaArr[adtaArr.length - 1][4] += parseInt(element[4])
+    adtaArr[adtaArr.length - 1][5] += parseInt(element[5])
+    adtaArr[adtaArr.length - 1][6] += parseInt(element[6])
+    adtaArr[adtaArr.length - 1][7] += parseInt(element[7])
+    adtaArr[adtaArr.length - 1][8] += parseInt(element[8])
+    adtaArr[adtaArr.length - 1][9] += parseInt(element[9])
+    adtaArr[adtaArr.length - 1][10] += parseInt(element[10])
+  }
+  saveFile(adtaArr, false)
+  alert('所有项目已经检查完!')
+}
+
+
+// 调用保存方法
+window.electronAPI.readFile({filename: getDaysAgo(0) + '.csv', encoding: "utf8"}).then(result => {
+  if (result.success) {
+    console.log(result.content);
+    // 如果内容是空的,则读取昨天的
+    if (result.content == '') {
+      window.electronAPI.readFile({filename: getDaysAgo(1) + '.csv', encoding: "utf8"}).then(result2 => {
+        if (result2.success) {
+          console.log(result2.content);
+          // 如果内容是空的,则读取昨天的
+          if (result2.content == '') {
+            alert('缺少昨天的数据!')
+          } else {
+            let fileData = csvToArray(result2.content)
+            creatToday(fileData)
+            console.log(fileData)
+            checkData(fileData)
+          }
+        } else {
+          console.error('文件读取失败:', result2.error);
+        }
+      });
+    } else {
+      // 读取加载文件
+      let fileData = csvToArray(result.content)
+      console.log(fileData)
+      checkData(fileData)
+    }
+  } else {
+    console.error('文件读取失败:', result.error);
+  }
+});

+ 33 - 0
dist/油管数据/preload.js

@@ -0,0 +1,33 @@
+const { contextBridge, ipcRenderer } = require('electron');
+
+
+
+// window.open = (url)=>{console.log(url)}
+window.lastText = ''
+window.lastText2 = ''
+
+
+
+contextBridge.exposeInMainWorld('electronAPI', {
+  openWindow: (msg) => ipcRenderer.invoke('openWindow', msg),
+  closeAllWindow: (msg) => ipcRenderer.send('closeAllWindow', msg),
+  getData: (msg) => ipcRenderer.send('getData', msg),
+  postData: (msg) => ipcRenderer.send('postData', msg),
+  setProxy: (msg) => ipcRenderer.send('setProxy', msg),
+  addPreLoadCode: (msg) => ipcRenderer.send('addPreLoadCode', msg),
+  setStoData: (msg) => ipcRenderer.send('setStoData', msg),
+  getStoData: (msg) => ipcRenderer.send('getStoData', msg),
+  closeWindow: (msg) => ipcRenderer.send('closeWindow', msg),
+  changeProxy: (msg) => ipcRenderer.send('changeProxy', msg),
+  readConfig: (msg) => ipcRenderer.send('readConfig', msg),
+  saveConfig: (msg) => ipcRenderer.send('saveConfig', msg),
+  setMaxWindowOpenNum: (msg) => ipcRenderer.send('setMaxWindowOpenNum', msg),
+  readdir: (msg) => ipcRenderer.send('readdir', msg),
+  download: (msg) => ipcRenderer.send('download', msg),
+  broadcast: (msg) => ipcRenderer.send('broadcast-message', msg),
+  saveFile: (msg) => ipcRenderer.invoke('saveFile', msg),
+  readFile: (msg) => ipcRenderer.invoke('readFile', msg),
+  onBroadcast: (callback) => ipcRenderer.on('message-broadcast', (event, data) => callback(data))
+});
+
+

+ 8 - 12
main.js

@@ -2,6 +2,7 @@
 const {app, ipcMain, BrowserWindow, session} = require('electron')
 const path = require('path')
 const fs = require('fs')
+const iconv = require('iconv-lite');
 const request = require('request');
 const download = require('download');
 // 读取配置文件
@@ -533,10 +534,10 @@ ipcMain.handle("saveFile", async (event, message) => {
     
     // 构建完整的文件路径
     const filePath = path.join(downloadDir, message.filename);
-    
-    // 添加UTF-8 BOM头并保存文件
-    const contentWithBOM = '\uFEFF' + message.content;
-    fs.writeFileSync(filePath, contentWithBOM, 'utf8');
+
+    // 将字符串编码为缓冲区
+    const fileBuffer = iconv.encode(message.content, message.encoding ? message.encoding : 'utf8');
+    fs.writeFileSync(filePath, fileBuffer);
     
     console.log('文件保存成功:', filePath);
     return { success: true, path: filePath };
@@ -565,16 +566,11 @@ ipcMain.handle("readFile", async (event, message) => {
     }
     
     // 读取文件内容
-    const content = fs.readFileSync(filePath, message.encoding ? message.encoding : 'utf8');
-    
-    // 移除UTF-8 BOM头(如果存在)
-    let processedContent = content;
-    if (content.charCodeAt(0) === 0xFEFF) {
-      processedContent = content.slice(1);
-    }
+    const buffer = fs.readFileSync(filePath);
+    const content = iconv.decode(buffer, message.encoding ? message.encoding : 'utf8');
     
     console.log('文件读取成功:', filePath);
-    return { success: true, content: processedContent, exists: true };
+    return { success: true, content: content, exists: true };
   } catch (error) {
     console.error('读取文件失败:', error);
     return { success: false, error: error.message, exists: false };

+ 1 - 0
package.json

@@ -38,6 +38,7 @@
   },
   "dependencies": {
     "download": "^8.0.0",
+    "iconv-lite": "^0.7.0",
     "request": "^2.88.2"
   }
 }

+ 6 - 4
preLoadFile.js

@@ -46,7 +46,8 @@ function creatToday(fileList) {
   }
   const fileData = {
     filename: getDaysAgo(0) + '.csv',
-    content: arrayToCSV(fileList)
+    content: arrayToCSV(fileList),
+    encoding: "gb2312"
   };
 
   // 调用保存方法
@@ -64,7 +65,8 @@ function saveFile(adtaArr, next) {
   // 保存数据
   const fileData = {
     filename: getDaysAgo(0) + '.csv',
-    content: arrayToCSV(adtaArr)
+    content: arrayToCSV(adtaArr),
+    encoding: "gb2312"
   };
 
   // 调用保存方法
@@ -162,12 +164,12 @@ function checkData (adtaArr) {
 
 
 // 调用保存方法
-window.electronAPI.readFile({filename: getDaysAgo(0) + '.csv', encoding: "utf8"}).then(result => {
+window.electronAPI.readFile({filename: getDaysAgo(0) + '.csv', encoding: "gb2312"}).then(result => {
   if (result.success) {
     console.log(result.content);
     // 如果内容是空的,则读取昨天的
     if (result.content == '') {
-      window.electronAPI.readFile({filename: getDaysAgo(1) + '.csv', encoding: "utf8"}).then(result2 => {
+      window.electronAPI.readFile({filename: getDaysAgo(1) + '.csv', encoding: "gb2312"}).then(result2 => {
         if (result2.success) {
           console.log(result2.content);
           // 如果内容是空的,则读取昨天的

+ 35 - 3
yarn.lock

@@ -1671,6 +1671,13 @@ iconv-lite@^0.6.2:
   dependencies:
     safer-buffer ">= 2.1.2 < 3.0.0"
 
+iconv-lite@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.0.tgz#c50cd80e6746ca8115eb98743afa81aa0e147a3e"
+  integrity sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==
+  dependencies:
+    safer-buffer ">= 2.1.2 < 3.0.0"
+
 ieee754@^1.1.13:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
@@ -2752,7 +2759,16 @@ strict-uri-encode@^1.0.0:
   resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
   integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==
 
-"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+"string-width-cjs@npm:string-width@^4.2.0":
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+  integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+  dependencies:
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.1"
+
+string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
   version "4.2.3"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
   integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -2784,7 +2800,14 @@ string_decoder@~1.1.1:
   dependencies:
     safe-buffer "~5.1.0"
 
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+  dependencies:
+    ansi-regex "^5.0.1"
+
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
   integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -3040,7 +3063,16 @@ which@^2.0.1, which@^2.0.2:
   dependencies:
     isexe "^2.0.0"
 
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+  dependencies:
+    ansi-styles "^4.0.0"
+    string-width "^4.1.0"
+    strip-ansi "^6.0.0"
+
+wrap-ansi@^7.0.0:
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
   integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==