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 属性来控制任务的输出和运行方式。例如,你可以设置 revealalways 来总是在输出面板中显示任务的输出。

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 !
评论
  目录