Vscode脚本——自动注释文件更新时间


需求

  1. 每次打开Vscode编辑器执行任务。
  2. 只有打开指定的文件夹后脚本的实际内容才会被真正执行。
  3. 在指定的文件夹下创建JavaScript文件后,会在文件开头生成更新此文件的时间,精确到秒。
  4. 每次保存后:
    • 如果当前时间距离上一次更新时间 > 24小时,则另起一行生成新的时间注释。
    • 如果当前时间距离上一次更新时间 < 24小时,则覆盖之前的时间注释。

成果展示:

image-20240316110834527

设置任务

  1. 在 VS Code 中,打开命令面板(Ctrl+Shift+P),然后输入 “Tasks: Configure Task” 并选择它。
  2. 在弹出的菜单中,选择 “Create tasks.json file from template”,然后选择 “Others”。
  3. 这将会在你的工作区的 .vscode 文件夹中创建一个 tasks.json 文件。在这个文件中,你可以定义你的任务。
  4. 在 tasks.json 文件中,你可以设置你的任务的 label(标签),type(类型),command(命令)和 args(参数)。command 应该是你的脚本的路径,args 应该是你想要处理的文件夹的路径。
  5. 你还可以设置 presentation 属性来控制任务的输出和运行方式。例如,你可以设置 reveal 为 always 来总是在输出面板中显示任务的输出。

task.json文件

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Update Date Comment",
            "type": "shell",
            "command": "node",
            "args": ["./self_practice/updateDateComment.js", "./self_practice/每日练习"],
            "presentation": {
                "reveal": "always"
            },
            "problemMatcher": [],
            "runOptions": {
                "runOn": "folderOpen"
            }
        }
    ]
}

代码展示

const fs = require('fs');
const path = require('path');

const folderPath = './self_practice/每日练习'; // 你的文件夹路径
let watcher;

// 防抖函数
function debounce(func, wait) {
    let timeout = null;
    return function () {
        if (timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(() => {
            func.apply(this, arguments);
            timeout = null;
        }, wait);
    };
}



// 替换注释等操作
function changeComments(filePath) {
    // 只处理.js文件
    if (path.extname(filePath) === '.js') {
        try {
            let content = fs.readFileSync(filePath, 'utf8');
            let lines = content.split('\n');

            let now = new Date();
            let dateComment = `// Last updated: ${now.toLocaleString()}`;

            if (lines[0].startsWith('// Last updated:')) {
                let oldDateStr = lines[0].replace('// Last updated: ', '');
                // 由于toLocaleString()的结果可能因浏览器和地区设置的不同而不同,我们需要将其转换回时间戳进行比较
                if (now.getTime() - Date.parse(oldDateStr) >= 24 * 60 * 60 * 1000) {
                    // 如果距离上次更新超过24小时,添加新的注释
                    lines.unshift(dateComment);
                } else {
                    // 否则,覆盖旧的注释
                    lines[0] = dateComment;
                }
            } else {
                lines.unshift(dateComment);
            }

            let newContent = lines.join('\n');

            fs.writeFileSync(filePath, newContent, 'utf8');


        } catch (error) {
            if (error.code !== 'EBUSY') {
                throw error;
            }
            // 如果文件正在被使用,忽略错误
        }
    }
}

// 更新文件的日期注释
function updateDateComment(filePath) {

    // 检查self_practice文件夹是否存在
    if (!fs.existsSync(filePath)) {
        console.log('self_practice folder does not exist. Exiting...');
        return;
    }
     // 停止监视文件
     watcher.close();
    changeComments(filePath)
    
     // 重新开始监视文件
     startWatching();
}



function startWatching() {
    watcher = fs.watch(folderPath, (eventType, filename) => {
        if (filename && (eventType === 'change' || eventType === 'rename')) {
            const filePath = path.join(folderPath, filename);
            console.log('watching folder')
            debouncedUpdateDateComment(filePath);
        }
    });
}

// 使用防抖函数,延迟1秒执行
const debouncedUpdateDateComment = debounce(updateDateComment, 1000);

// 开始监视文件
startWatching();

BUG解决方案

  • 保存操作频率过快导致文件写入操作产生"竞态条件"(Race Condition)的问题,即如果你的代码正在尝试读取或者写入文件,而你又在同一时间保存文件,那么你的代码可能会读取到一个旧的文件版本,或者你的保存操作可能会覆盖你的代码的修改。

  • 保存一次,监视文件修改的函数会被执行几百次,性能非常差。

    引入防抖函数!限制操作的频率,同时将多次操作保存为一次!

  • 引入防抖函数导致的循环:当脚本修改文件时(覆盖注释)—— fs.watch 触发change事件——脚本再次修改文件(覆盖注释)——…

    1. 在修改文件之前,先停止监视文件。
    2. 文件修改完成后再开始监视。

文章作者: QT-7274
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 QT-7274 !
赏
评论
  目录