format-for-composer-fixed.js•9.52 kB
#!/usr/bin/env node
/**
* Format for Composer Tool - CORRECTED
* Transforms validated lesson data into EXACT EuConquisto Composer JSON format
* Based on official reference: /docs/references/json-example.md
*/
export class ComposerFormatterFixed {
constructor() {
this.processingStartTime = null;
this.transformationLog = [];
this.educationalOptimizations = [];
}
/**
* Main formatting entry point
*/
async formatForComposer(validatedLessonData) {
this.processingStartTime = Date.now();
this.transformationLog = [];
this.educationalOptimizations = [];
console.error('[FORMAT_FOR_COMPOSER] Starting CORRECTED formatting transformation');
try {
const { metadata, widgets } = validatedLessonData;
// Create composition structure following EXACT official format
const composition = {
version: "1.1",
metadata: this.createComposerMetadata(metadata),
interface: this.createComposerInterface(),
structure: []
};
// Transform widgets with EXACT reference mapping
for (let index = 0; index < widgets.length; index++) {
const widget = widgets[index];
const transformedWidget = this.transformWidget(widget, index, widgets.length, metadata);
if (transformedWidget) {
composition.structure.push(transformedWidget);
this.logTransformation(`WIDGET_${index + 1}`, widget.type, 'transformed successfully');
}
}
const processingTime = Date.now() - this.processingStartTime;
console.error(`[FORMAT_FOR_COMPOSER] ✅ CORRECTED formatting successful: ${composition.structure.length} widgets transformed`);
return {
success: true,
data: {
composerJSON: composition,
widgetCount: composition.structure.length,
formatSummary: `Transformed ${composition.structure.length} widgets with EXACT reference format`,
educationalOptimizations: this.educationalOptimizations
},
debug: {
timestamp: new Date().toISOString(),
processingTime: processingTime,
transformationLog: this.transformationLog
}
};
} catch (error) {
console.error('[FORMAT_FOR_COMPOSER] ❌ CORRECTED formatting error:', error.message);
return {
success: false,
error: {
code: 'FORMAT_ERROR',
message: error.message,
details: [{
type: 'TRANSFORMATION_ERROR',
location: 'formatter',
field: 'system',
expected: 'successful formatting',
actual: error.message
}]
},
debug: {
timestamp: new Date().toISOString(),
processingTime: Date.now() - this.processingStartTime,
transformationLog: this.transformationLog
}
};
}
}
/**
* Create Composer-compatible metadata - EXACT format
*/
createComposerMetadata(metadata) {
return {
title: metadata.topic || "Aula Educacional",
description: `Aula completa sobre ${metadata.topic || "conteúdo educacional"}`,
thumb: null,
tags: Array.isArray(metadata.learningObjectives) ? metadata.learningObjectives : []
};
}
/**
* Create Composer interface configuration - EXACT format
*/
createComposerInterface() {
return {
content_language: "pt_br",
index_option: "buttons",
font_family: "Lato",
show_summary: "disabled",
finish_btn: "disabled"
};
}
/**
* Transform individual widget - EXACT reference mapping
*/
transformWidget(widget, index, totalWidgets, metadata) {
const baseElement = {
id: this.generateUUID(),
type: widget.type,
dam_assets: []
};
try {
switch (widget.type) {
case 'head-1':
return this.transformHead1Widget(widget, baseElement, metadata);
case 'text-1':
return this.transformText1Widget(widget, baseElement, metadata);
case 'quiz-1':
return this.transformQuiz1Widget(widget, baseElement, metadata);
case 'flashcards-1':
return this.transformFlashcards1Widget(widget, baseElement, metadata);
case 'image-1':
return this.transformImage1Widget(widget, baseElement, metadata);
case 'list-1':
return this.transformList1Widget(widget, baseElement, metadata);
default:
console.warn(`[FORMAT_FOR_COMPOSER] Unknown widget type: ${widget.type}`);
return null;
}
} catch (error) {
console.error(`[FORMAT_FOR_COMPOSER] Error transforming ${widget.type}:`, error.message);
throw new Error(`Widget transformation failed for ${widget.type}: ${error.message}`);
}
}
/**
* head-1 Widget - EXACT reference format
* Reference: lines 78-94 in json-example.md
*/
transformHead1Widget(widget, baseElement, metadata) {
return {
...baseElement,
content_title: null,
primary_color: "#FFFFFF",
secondary_color: "#2196F3",
category: `<p>${widget.content.category || 'EDUCAÇÃO'}</p>`,
background_image: "https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=1200&h=400&fit=crop",
avatar: "https://ui-avatars.com/api/?name=Professor&background=2196F3&color=fff&size=200",
avatar_border_color: "#1565C0",
author_name: `<p>${widget.content.author_name || 'Professor(a) Virtual'}</p>`,
author_office: `<p>${widget.content.author_office || 'Educador'}</p>`,
show_category: true,
show_author_name: true,
show_divider: true,
dam_assets: []
};
}
/**
* text-1 Widget - EXACT reference format
* Reference: lines 300+ in json-example.md
*/
transformText1Widget(widget, baseElement, metadata) {
return {
...baseElement,
content_title: null,
padding_top: 35,
padding_bottom: 35,
background_color: "#FFFFFF",
text: widget.content.text || widget.content.title || '<p>Conteúdo educacional</p>',
dam_assets: []
};
}
/**
* quiz-1 Widget - EXACT reference format
* Reference: quiz structure in json-example.md
*/
transformQuiz1Widget(widget, baseElement, metadata) {
const questions = widget.content.questions || [];
return {
...baseElement,
content_title: "Quiz",
padding_top: 35,
padding_bottom: 35,
background_color: "#FFFFFF",
primary_color: "#2196F3",
secondary_color: "#1565C0",
questions: questions.map((q, index) => ({
id: this.generateUUID(),
question: `<p>${q.question}</p>`,
choices: (q.options || q.answers || []).map((option, optIndex) => ({
id: this.generateUUID(),
text: `<p>${typeof option === 'string' ? option : option.text}</p>`,
correct: optIndex === (q.correct_option || q.correct_answer || 0)
}))
})),
max_attempts: widget.content.max_attempts || 3,
dam_assets: []
};
}
/**
* flashcards-1 Widget - EXACT reference format
*/
transformFlashcards1Widget(widget, baseElement, metadata) {
const items = widget.content.flashcards_items || widget.content.items || [];
return {
...baseElement,
content_title: "Flashcards",
padding_top: 35,
padding_bottom: 35,
background_color: "#FFFFFF",
primary_color: "#4CAF50",
secondary_color: "#388E3C",
items: items.map(item => ({
id: this.generateUUID(),
text_front: `<p>${item.question}</p>`,
text_back: `<p>${item.answer}</p>`,
image_front: null,
image_back: null,
video_front: null,
video_back: null
})),
dam_assets: []
};
}
/**
* image-1 Widget - EXACT reference format
*/
transformImage1Widget(widget, baseElement, metadata) {
return {
...baseElement,
content_title: null,
padding_top: 20,
padding_bottom: 20,
image: widget.content.image || "https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=800",
image_max_width: 760,
caption: widget.content.caption ? `<p>${widget.content.caption}</p>` : null,
dam_assets: []
};
}
/**
* list-1 Widget - EXACT reference format
* CRITICAL: Uses 'items' array with specific structure
*/
transformList1Widget(widget, baseElement, metadata) {
const listItems = widget.content.items || [];
return {
...baseElement,
content_title: "Lista",
padding_top: 35,
padding_bottom: 35,
background_color: "#FFFFFF",
primary_color: "#297C43",
secondary_color: "#FFFFFF",
items: listItems.map(item => ({
id: this.generateUUID(),
text: `<p>${typeof item === 'string' ? item : item.text}</p>`,
image: null,
video: null
})),
dam_assets: []
};
}
/**
* Generate UUID for widgets
*/
generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* Log transformation for debugging
*/
logTransformation(step, type, message) {
this.transformationLog.push({
step: step,
type: type,
message: message,
timestamp: new Date().toISOString()
});
}
}
export function createComposerFormatterFixed() {
return new ComposerFormatterFixed();
}