class ShellParser {
constructor() {
this.variables = {}; // 普通变量
this.exports = {}; // 导出变量
this.sections = []; // 所有section
this.comments = []; // 所有注释
this.originalContent = ''; // 原始内容
}
// 解析整个shell文件
parseFile(content) {
this.originalContent = content;
const lines = content.split('\n');
let currentSection = {
name: '',
level: 0,
lineNumber: 0,
variables: [],
comments: []
};
this.sections.push(currentSection);
let currentSectionContent = ''; // 用于收集section的内容
let lastComment = null;
let inMultilineValue = false;
let currentVariable = null;
let multilineBuffer = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
const lineNumber = i + 1;
// 处理多行值
if (inMultilineValue) {
if (line.endsWith(currentVariable.quote)) {
// 多行值结束
multilineBuffer.push(line.slice(0, -1));
const fullValue = multilineBuffer.join('\n');
this.exports[currentVariable.name] = fullValue;
currentVariable.value = fullValue;
inMultilineValue = false;
multilineBuffer = [];
} else {
multilineBuffer.push(line);
}
continue;
}
// 处理导出变量
if (line.startsWith('export')) {
// 修改正则表达式,只匹配引号外的注释
const match = line.match(/^export\s+([A-Za-z0-9_]+)=(['"])((?:(?!\2).)*)\2(?:\s*#(.*))?$/);
if (match) {
const [_, name, quote, value, comment] = match;
console.log(`发现导出变量: ${name} = ${quote}${value}${quote}`);
// 创建变量对象
currentVariable = {
name,
value,
type: 'export',
lineNumber,
section: currentSection,
comment: comment ? { // 只有引号外的#才作为注释
content: comment.trim(),
lineNumber,
section: currentSection
} : lastComment,
quote
};
// 添加到exports
this.exports[name] = value;
currentSection.variables.push(currentVariable);
continue;
} else {
// 如果没有匹配到完整的引号对,尝试处理多行值
const basicMatch = line.match(/^export\s+([A-Za-z0-9_]+)=(['"])(.*?)$/);
if (basicMatch) {
const [_, name, quote, value] = basicMatch;
console.log(`发现多行变量: ${name}`);
// 创建变量对象
currentVariable = {
name,
type: 'export',
lineNumber,
section: currentSection,
comment: lastComment,
quote
};
// 开始多行值收集
inMultilineValue = true;
multilineBuffer = [value];
this.exports[name] = ''; // 初始化为空字符串
currentSection.variables.push(currentVariable);
continue;
}
}
}
// 处理section标题
if (line.startsWith('##')) {
const level = line.match(/^#+/)[0].length;
const sectionName = line.substring(level).trim();
// 创建新section
currentSection = {
name: sectionName,
level,
lineNumber,
variables: [],
comments: []
};
this.sections.push(currentSection);
currentSectionContent = ''; // 重置section内容
continue;
}
// 收集section内容
if (currentSection) {
currentSectionContent += line + '\n';
}
}
return this;
}
// 解析值(处理引号)
parseValue(value) {
console.log('解析值:', value); // 调试输出
// 去除引号
if ((value.startsWith("'") && value.endsWith("'")) ||
(value.startsWith('"') && value.endsWith('"'))) {
value = value.slice(1, -1);
console.log('去除引号后:', value); // 调试输出
}
return value;
}
// 获取变量信息
getValue(name) {
// 查找变量
let value = this.exports[name] || this.variables[name] || ''; // 默认返回空字符串而不是undefined
let type = name in this.exports ? 'export' :
name in this.variables ? 'variable' : null;
// 查找变量所在的section
let section = this.sections.find(s =>
s.variables.some(v => v.name === name)
) || this.sections[0];
// 查找变量对象
let variable = section.variables.find(v => v.name === name);
return {
name,
value, // 现在总是返回字符串
type,
section: {
name: section?.name || '',
level: section?.level || 0,
lineNumber: section?.lineNumber || 0,
commentCount: section?.comments?.length || 0,
variableCount: section?.variables?.length || 0
},
comments: variable?.comment ? [{
content: variable.comment.content,
lineNumber: variable.comment.lineNumber
}] : []
};
}
// 设置变量值
setValue(name, value, options = {}) {
const isExport = options.isExport !== undefined ? options.isExport : (name in this.exports);
const varInfo = this.getValue(name);
// 更新或添加变量
if (isExport) {
this.exports[name] = value;
delete this.variables[name];
} else {
this.variables[name] = value;
delete this.exports[name];
}
// 如果是新变量,添加到指定section
let targetSection;
if (options.section) {
targetSection = this.sections.find(s => s.name === options.section);
} else if (varInfo.section && varInfo.section.name) {
targetSection = this.sections.find(s => s.name === varInfo.section.name);
} else {
targetSection = this.sections[0];
}
if (!targetSection) {
targetSection = this.sections[0];
}
// 检查变量是否已存在于section中
const existingVarIndex = targetSection.variables.findIndex(v => v.name === name);
if (existingVarIndex >= 0) {
// 更新现有变量
targetSection.variables[existingVarIndex].value = value;
targetSection.variables[existingVarIndex].type = isExport ? 'export' : 'variable';
} else {
// 添加新变量
targetSection.variables.push({
name,
value,
type: isExport ? 'export' : 'variable',
lineNumber: 999999, // 放在section的最后
section: targetSection
});
}
return this.getValue(name);
}
// 转换为字符串
toString() {
const lines = [];
for (const section of this.sections) {
if (section.lineNumber > 0) {
lines.push('');
}
// 添加section标题
if (section.level > 1) {
lines.push(`${'#'.repeat(section.level)} ${section.name}`);
}
// 添加变量
section.variables.forEach(variable => {
if (variable.name in this.exports) {
const value = this.exports[variable.name];
const quote = variable.quote || "'"; // 默认使用单引号
let line = `export ${variable.name}=${quote}${value}${quote}`;
// 如果有行尾注释,添加它
if (variable.comment && variable.comment.content) {
line += ` #${variable.comment.content}`;
}
lines.push(line);
}
});
}
return lines.join('\n');
}
// 保存到文件
saveToFile(filePath) {
try {
const content = this.toString();
fs.writeFileSync(filePath, content, 'utf-8');
return true;
} catch (error) {
console.error('保存文件失败:', error);
return false;
}
}
}
// 解析shell文件
function parseShellFile(input, options = {}) {
const parser = new ShellParser();
if (options.isContent) {
return parser.parseFile(input);
} else {
try {
const content = fs.readFileSync(input, 'utf-8');
return parser.parseFile(content);
} catch (error) {
console.warn('无法读取文件,尝试直接解析内容');
return parser.parseFile(input);
}
}
}
版权归属:
管理员
许可协议:
本文使用《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》协议授权
评论区