基于PEG.js实现支持缩进修剪的heredoc功能方案咨询
结论
PEG.js完全可以实现你需要的带智能缩进修剪的heredoc功能,你遇到的两个核心问题都有成熟的解决方案。
解决marker反向引用问题
你原来的写法报错是因为PEG.js的静态规则不能直接引用前面捕获的变量作为匹配条件,需要用语义谓词(&{} 或前置动态校验)实现运行时的marker匹配,基础规则示例如下:
// 基础词法规则 word_char = [a-zA-Z0-9_] eol = "\r\n" / "\n" / "\r" sp = " " / "\t" line = $([^\r\n]* eol) // heredoc核心规则 heredoc = "<<<" marker:$(word_char+) eol text:line* // 先捕获结束行的前导空格,再校验后面是marker标记(不消耗输入) end_prefix:$(sp*) &(marker eol?) // 正式匹配结束标记行,消耗输入 marker eol? { // 这里写缩进处理逻辑 }
语义谓词的作用是在运行时动态校验当前位置是否符合匹配条件,此时你已经可以拿到前面捕获的marker变量,完全解决了反向引用的问题。
实现智能缩进修剪
你提到用位置信息处理的思路是可行的,更简单的方案是直接拿结束标记前的空格长度作为全局修剪长度,完全符合你的需求:结束标记缩进到哪一级,所有内容行就统一砍掉相同长度的前导空格,用户如果需要保留字符串前置空格,只要内容行的缩进比结束标记更深即可。
完整的动作逻辑示例如下:
heredoc = "<<<" marker:$(word_char+) eol text:line* end_prefix:$(sp*) &(marker eol?) marker eol? { const trim_len = end_prefix.length; const processedText = text.map(line => { // 计算当前行的前导空格长度 const linePrefixLen = line.match(/^[ \t]*/)[0].length; // 最多砍掉trim_len长度的前导空格,避免截断用户主动保留的缩进 return line.slice(Math.min(linePrefixLen, trim_len)); }).join(''); // 可选:去掉末尾多余的换行 return processedText.replace(/\n$/, ''); }
这套逻辑运行后完全符合你给出的示例效果,不会误删用户需要保留的前置空格,代码格式也足够美观。
内容的提问来源于stack exchange,提问作者jcubic
相关产品推荐
相关产品推荐

