refactor: extract CSV text cleaning to reusable method in manifest generator
This commit is contained in:
parent
7c68f816b6
commit
039d1b2420
|
|
@ -22,6 +22,19 @@ class ManifestGenerator {
|
||||||
this.selectedIdes = [];
|
this.selectedIdes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean text for CSV output by normalizing whitespace and escaping quotes
|
||||||
|
* @param {string} text - Text to clean
|
||||||
|
* @returns {string} Cleaned text safe for CSV
|
||||||
|
*/
|
||||||
|
cleanForCSV(text) {
|
||||||
|
if (!text) return '';
|
||||||
|
return text
|
||||||
|
.trim()
|
||||||
|
.replaceAll(/\s+/g, ' ') // Normalize all whitespace (including newlines) to single space
|
||||||
|
.replaceAll('"', '""'); // Escape quotes for CSV
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate all manifests for the installation
|
* Generate all manifests for the installation
|
||||||
* @param {string} bmadDir - _bmad
|
* @param {string} bmadDir - _bmad
|
||||||
|
|
@ -202,7 +215,7 @@ class ManifestGenerator {
|
||||||
// Workflows with standalone: false are filtered out above
|
// Workflows with standalone: false are filtered out above
|
||||||
workflows.push({
|
workflows.push({
|
||||||
name: workflow.name,
|
name: workflow.name,
|
||||||
description: workflow.description.replaceAll('"', '""'), // Escape quotes for CSV
|
description: this.cleanForCSV(workflow.description),
|
||||||
module: moduleName,
|
module: moduleName,
|
||||||
path: installPath,
|
path: installPath,
|
||||||
});
|
});
|
||||||
|
|
@ -320,24 +333,15 @@ class ManifestGenerator {
|
||||||
|
|
||||||
const agentName = entry.name.replace('.md', '');
|
const agentName = entry.name.replace('.md', '');
|
||||||
|
|
||||||
// Helper function to clean and escape CSV content
|
|
||||||
const cleanForCSV = (text) => {
|
|
||||||
if (!text) return '';
|
|
||||||
return text
|
|
||||||
.trim()
|
|
||||||
.replaceAll(/\s+/g, ' ') // Normalize whitespace
|
|
||||||
.replaceAll('"', '""'); // Escape quotes for CSV
|
|
||||||
};
|
|
||||||
|
|
||||||
agents.push({
|
agents.push({
|
||||||
name: agentName,
|
name: agentName,
|
||||||
displayName: nameMatch ? nameMatch[1] : agentName,
|
displayName: nameMatch ? nameMatch[1] : agentName,
|
||||||
title: titleMatch ? titleMatch[1] : '',
|
title: titleMatch ? titleMatch[1] : '',
|
||||||
icon: iconMatch ? iconMatch[1] : '',
|
icon: iconMatch ? iconMatch[1] : '',
|
||||||
role: roleMatch ? cleanForCSV(roleMatch[1]) : '',
|
role: roleMatch ? this.cleanForCSV(roleMatch[1]) : '',
|
||||||
identity: identityMatch ? cleanForCSV(identityMatch[1]) : '',
|
identity: identityMatch ? this.cleanForCSV(identityMatch[1]) : '',
|
||||||
communicationStyle: styleMatch ? cleanForCSV(styleMatch[1]) : '',
|
communicationStyle: styleMatch ? this.cleanForCSV(styleMatch[1]) : '',
|
||||||
principles: principlesMatch ? cleanForCSV(principlesMatch[1]) : '',
|
principles: principlesMatch ? this.cleanForCSV(principlesMatch[1]) : '',
|
||||||
module: moduleName,
|
module: moduleName,
|
||||||
path: installPath,
|
path: installPath,
|
||||||
});
|
});
|
||||||
|
|
@ -404,7 +408,7 @@ class ManifestGenerator {
|
||||||
const frontmatter = yaml.parse(frontmatterMatch[1]);
|
const frontmatter = yaml.parse(frontmatterMatch[1]);
|
||||||
name = frontmatter.name || name;
|
name = frontmatter.name || name;
|
||||||
displayName = frontmatter.displayName || frontmatter.name || name;
|
displayName = frontmatter.displayName || frontmatter.name || name;
|
||||||
description = frontmatter.description || '';
|
description = this.cleanForCSV(frontmatter.description || '');
|
||||||
standalone = frontmatter.standalone === true || frontmatter.standalone === 'true';
|
standalone = frontmatter.standalone === true || frontmatter.standalone === 'true';
|
||||||
} catch {
|
} catch {
|
||||||
// If YAML parsing fails, use defaults
|
// If YAML parsing fails, use defaults
|
||||||
|
|
@ -417,7 +421,7 @@ class ManifestGenerator {
|
||||||
|
|
||||||
const descMatch = content.match(/description="([^"]+)"/);
|
const descMatch = content.match(/description="([^"]+)"/);
|
||||||
const objMatch = content.match(/<objective>([^<]+)<\/objective>/);
|
const objMatch = content.match(/<objective>([^<]+)<\/objective>/);
|
||||||
description = descMatch ? descMatch[1] : objMatch ? objMatch[1].trim() : '';
|
description = this.cleanForCSV(descMatch ? descMatch[1] : objMatch ? objMatch[1].trim() : '');
|
||||||
|
|
||||||
const standaloneMatch = content.match(/<task[^>]+standalone="true"/);
|
const standaloneMatch = content.match(/<task[^>]+standalone="true"/);
|
||||||
standalone = !!standaloneMatch;
|
standalone = !!standaloneMatch;
|
||||||
|
|
@ -430,7 +434,7 @@ class ManifestGenerator {
|
||||||
tasks.push({
|
tasks.push({
|
||||||
name: name,
|
name: name,
|
||||||
displayName: displayName,
|
displayName: displayName,
|
||||||
description: description.replaceAll('"', '""'),
|
description: description,
|
||||||
module: moduleName,
|
module: moduleName,
|
||||||
path: installPath,
|
path: installPath,
|
||||||
standalone: standalone,
|
standalone: standalone,
|
||||||
|
|
@ -498,7 +502,7 @@ class ManifestGenerator {
|
||||||
const frontmatter = yaml.parse(frontmatterMatch[1]);
|
const frontmatter = yaml.parse(frontmatterMatch[1]);
|
||||||
name = frontmatter.name || name;
|
name = frontmatter.name || name;
|
||||||
displayName = frontmatter.displayName || frontmatter.name || name;
|
displayName = frontmatter.displayName || frontmatter.name || name;
|
||||||
description = frontmatter.description || '';
|
description = this.cleanForCSV(frontmatter.description || '');
|
||||||
standalone = frontmatter.standalone === true || frontmatter.standalone === 'true';
|
standalone = frontmatter.standalone === true || frontmatter.standalone === 'true';
|
||||||
} catch {
|
} catch {
|
||||||
// If YAML parsing fails, use defaults
|
// If YAML parsing fails, use defaults
|
||||||
|
|
@ -511,7 +515,7 @@ class ManifestGenerator {
|
||||||
|
|
||||||
const descMatch = content.match(/description="([^"]+)"/);
|
const descMatch = content.match(/description="([^"]+)"/);
|
||||||
const objMatch = content.match(/<objective>([^<]+)<\/objective>/);
|
const objMatch = content.match(/<objective>([^<]+)<\/objective>/);
|
||||||
description = descMatch ? descMatch[1] : objMatch ? objMatch[1].trim() : '';
|
description = this.cleanForCSV(descMatch ? descMatch[1] : objMatch ? objMatch[1].trim() : '');
|
||||||
|
|
||||||
const standaloneMatch = content.match(/<tool[^>]+standalone="true"/);
|
const standaloneMatch = content.match(/<tool[^>]+standalone="true"/);
|
||||||
standalone = !!standaloneMatch;
|
standalone = !!standaloneMatch;
|
||||||
|
|
@ -524,7 +528,7 @@ class ManifestGenerator {
|
||||||
tools.push({
|
tools.push({
|
||||||
name: name,
|
name: name,
|
||||||
displayName: displayName,
|
displayName: displayName,
|
||||||
description: description.replaceAll('"', '""'),
|
description: description,
|
||||||
module: moduleName,
|
module: moduleName,
|
||||||
path: installPath,
|
path: installPath,
|
||||||
standalone: standalone,
|
standalone: standalone,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue