You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发Mount&Blade: Warband脚本格式化插件遇unexpected token(1:5)错误

Warband脚本语言VS Code格式化工具报错修复

我正在为《骑马与砍杀:战团》的Warband Script Language开发VS Code代码格式化工具和代码片段支持,目前代码片段功能正常,但格式化工具完全无法工作。按下快捷键alt+shift+f触发格式化时,VS Code弹出unexpected token(1:5)错误,此时执行的是mbap.formatWarbandScript命令。

预期实现效果:

  • operationNames数组中每个元素对应的语句后换行并添加缩进
  • 结束语句try_end与起始语句对齐

extension.js

const acorn = require('acorn');
const escodegen = require('escodegen');
const vscode = require('vscode');

function formatWarbandScriptLanguageCode(code) {
    const parsedAst = acorn.parse(code, { ecmaVersion: 5 });

    let indentationLevel = 0;

    traverse(parsedAst, {
        enter(node, parent) {
            if (node.type === 'CallExpression') {
                const operationNames = [
                    'try_begin',
                    'try_for_range',
                    'try_for_range_backwards',
                    'try_for_parties',
                    'try_for_agents',
                    'try_for_prop_instances',
                    'try_for_players',
                    'try_for_dict_keys',
                ];

                if (operationNames.includes(node.callee.name)) {
                    // Insert a newline before the operation call
                    if (parent.body.indexOf(node) === 0) {
                        const newlineNode = {
                            type: 'WhiteSpace',
                            value: '\n' + '    '.repeat(indentationLevel), // Adjust the desired indentation
                        };
                        parent.body.unshift(newlineNode);
                    }

                    // Add a tab indentation to the arguments of the operation
                    node.arguments.forEach(arg => {
                        if (arg.type === 'ArrayExpression') {
                            arg.elements.forEach(element => {
                                element.loc.indent += 1; // Adjust the indentation level
                            });
                        }
                    });

                    indentationLevel++;
                }
            }
        },
        leave(node) {
            if (node.type === 'CallExpression') {
                const operationNames = [
                    'try_begin',
                    'try_for_range',
                    'try_for_range_backwards',
                    'try_for_parties',
                    'try_for_agents',
                    'try_for_prop_instances',
                    'try_for_players',
                    'try_for_dict_keys',
                ];

                if (operationNames.includes(node.callee.name)) {
                    indentationLevel--;
                }
            }
        },
    });

    const formattedCode = escodegen.generate(parsedAst);
    return formattedCode;
}

function activate(context) {
    console.log('M&B Warband API extension is now active.');
    // ... other activation code ...

    let disposable = vscode.commands.registerCommand('mbap.formatWarbandScript', () => {
        const editor = vscode.window.activeTextEditor;
        if (!editor) {
            return;
        }

        const document = editor.document;
        const text = document.getText();

        // Format the code
        const formattedCode = formatWarbandScriptLanguageCode(text);

        // Apply the formatted code
        const edit = new vscode.TextEdit(
            new vscode.Range(0, 0, document.lineCount, 0),
            formattedCode
        );

        const workspaceEdit = new vscode.WorkspaceEdit();
        workspaceEdit.set(document.uri, [edit]);
        vscode.workspace.applyEdit(workspaceEdit);
    });

    context.subscriptions.push(disposable);
}

// This method is called when your extension is deactivated
function deactivate() {
    console.log('M&B Warband API extension is now deactivated.');
}

module.exports = {
    activate,
    deactivate
};

package.json

{
    "name": "mbap",
    "displayName": "M&B: Warband API",
    "description": "Mount & Blade: Warband language support for Microsoft Visual Studio Code by Azremen and Sart",
    "publisher": "Azremen",
    "version": "0.1.18",
    "homepage": "https://github.com/Azremen/MB-Warband-API-VSC/blob/main/README.md",
    "engines": {
        "vscode": "^1.62.0"
    },
    "repository": {
        "type": "git",
        "url": "https://github.com/Azremen/MB-Warband-API-VSC.git"
    },
    "categories": [
        "Programming Languages"
    ],
    "main": "./extension.js",
    "activationEvents": [
        "onCommand:mbap.formatWarbandScript"
    ],
    "contributes": {
        "languages": [
            {
                "id": "warbandsl",
                "aliases": [
                    "Warband Script Language"
                ],
                "extensions": [
                    ".py"
                ],
                "configuration": "./language-configuration.json"
            }
        ],
        "commands": [
            {
                "command": "mbap.formatWarbandScript",
                "title": "Format Warband Script Language Code"
            }
        ],
        "snippets": [
            {
                "language": "warbandsl",
                "path": "./snippets/mbap.code-snippets"
            }
        ],
        "keybindings": [
            {
                "command": "mbap.formatWarbandScript",
                "key": "alt+shift+f",
                "when": "editorTextFocus && resourceLangId == warbandsl"
            }
        ]
    },
    "configuration": {
        "title": "Warband Script Language Formatter",
        "properties": {
            "warbandsl.indentation": {
                "type": "string",
                "enum": [
                    "tabs",
                    "spaces"
                ],
                "default": "spaces",
                "description": "Indentation style for Warband Script Language Formatter."
            },
            "warbandsl.tabSize": {
                "type": "number",
                "default": 4,
                "description": "Number of spaces or tabs to use for indentation."
            }
        }
    },
    "dependencies": {
        "acorn": "^8.0.1",
        "escodegen": "^2.0.0"
    }
}

问题根源与修复方案

1. 核心错误原因

unexpected token(1:5)错误是因为你用JavaScript专用解析器acorn去解析Warband脚本语言,两者语法完全不兼容。Warband脚本的语法(如(try_begin)、无括号的函数调用)不符合JavaScript规范,acorn无法识别,直接抛出解析错误。

2. 针对性修复步骤

步骤1:替换解析方案,放弃acorn/escodegen

acorn只适用于JavaScript,无法处理自定义脚本语言。你有两种选择:

  • 手动编写Warband脚本的词法分析器和语法分析器,或者用通用解析工具(如nearley.js)定义语法规则
  • 用正则表达式/字符串匹配实现轻量级格式化(适合Warband脚本这种语法相对简单的场景)

步骤2:修复traverse函数未定义问题

代码中调用的traverse函数属于acorn-walk模块,你没安装也没导入,会导致运行时错误。如果坚持用acorn生态,需要:

npm install acorn-walk

然后在extension.js头部添加:

const { traverse } = require('acorn-walk');

步骤3:实现Warband脚本专属格式化逻辑

以下是基于字符串匹配的轻量格式化实现,能满足你的预期需求:

function formatWarbandScriptLanguageCode(code) {
    let indentLevel = 0;
    const indent = '    ';
    const lines = code.split('\n').map(line => line.trim());
    const formattedLines = [];

    for (const line of lines) {
        if (!line) continue;

        // 处理结束语句,先减缩进再添加
        if (line.startsWith('(try_end')) {
            indentLevel = Math.max(0, indentLevel - 1);
            formattedLines.push(indent.repeat(indentLevel) + line);
        } else {
            // 添加当前行
            formattedLines.push(indent.repeat(indentLevel) + line);
            // 处理起始语句,增加缩进
            const operationNames = [
                'try_begin', 'try_for_range', 'try_for_range_backwards',
                'try_for_parties', 'try_for_agents', 'try_for_prop_instances',
                'try_for_players', 'try_for_dict_keys'
            ];
            for (const op of operationNames) {
                if (line.startsWith(`(${op}`)) {
                    indentLevel++;
                    break;
                }
            }
        }
    }

    return formattedLines.join('\n');
}

步骤4:完善VS Code格式化配置

在package.json的contributes中添加格式化器声明,让VS Code自动关联:

"contributes": {
    // ... 现有内容 ...
    "formatters": [
        {
            "language": "warbandsl",
            "id": "mbap.warbandslFormatter",
            "label": "Warband Script Language Formatter"
        }
    ]
},
"activationEvents": [
    "onCommand:mbap.formatWarbandScript",
    "onLanguage:warbandsl"
]

更规范的做法是实现DocumentFormattingEditProvider接口,替代当前的命令触发方式。


内容的提问来源于stack exchange,提问作者Gökberk Alkış

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 05:47:08