1
0
Fork 0
liza/src/document/DocumentProgramFormatter.js

219 lines
5.8 KiB
JavaScript

/**
* Formats program bucket data
*
* Copyright (C) 2010-2019 R-T Specialty, LLC.
*
* This file is part of the Liza Data Collection Framework.
*
* liza is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
const Class = require( 'easejs' ).Class;
/**
* Formats program bucket data
*
* This takes a document and formats the bucket data in a
* structured manner of steps, groups and fields metadata
*/
module.exports = Class( 'DocumentProgramFormatter',
{
/**
* Current program
*
* @type {Program}
*/
'private _program': null,
/**
* Performs classification matching on fields
*
* A field will have a positive match for a given index if all of its
* classes match
*
* @type {FieldClassMatcher}
*/
'private _class_matcher': null,
/**
* Initialize document formatter
*
* @param {Program} program active program
* @param {FieldClassMatcher} class_matcher class/field matcher
*/
constructor( program, class_matcher )
{
this._program = program;
this._class_matcher = class_matcher;
},
/**
* Formats document data into structure similar to program
*
* @param {Bucket} bucket document bucket
*
* @return {Promise.<Object>} a promise of a data object
*/
'public format'( bucket )
{
return new Promise( ( resolve, reject ) =>
{
const cmatch = this._program.classify( bucket.getData() );
this._class_matcher.match( cmatch, ( matches ) =>
{
const len = this._program.steps.length;
const data = this._parseSteps( len, bucket, matches );
resolve( data );
} );
} );
},
/**
* Parses step data
*
* @param {Number} len step length
* @param {Bucket} bucket document bucket
* @param {Object} matches field matches
*
* @return {Object} step data
*/
'private _parseSteps'( len, bucket, matches )
{
const data = { steps: [] };
for ( let i = 1; i < len; i++ )
{
const step = {};
const step_groups = this._program.steps[ i ].groups;
const groups = this._parseGroups( step_groups, bucket, matches );
step.title = this._program.steps[ i ].title;
step.groups = groups;
data.steps.push( step );
}
return data;
},
/**
* Parses group data
*
* @param {Array} step_groups array of group data
* @param {Bucket} bucket document bucket
* @param {Object} matches field matches
*
* @return {Array} array of groups
*/
'private _parseGroups'( step_groups, bucket, matches )
{
return step_groups.map( group_id =>
{
const fields = this._program.groupExclusiveFields[ group_id ];
const { title, link } = this._program.groups[ group_id ];
return {
id: group_id,
title: title || "",
link: link || "",
questions: this._parseFields( fields, bucket, matches ),
};
} );
},
/**
* Parses fields/question data
*
* @param {Array} fields array of field data
* @param {Bucket} bucket document bucket
* @param {Object} matches field matches
*
* @return {Array} array of questions
*/
'private _parseFields'( fields, bucket, matches )
{
const questions = [];
for ( let field in fields )
{
const field_id = fields[ field ];
// Don't include fields that are not in program.fields
if ( typeof this._program.fields[ field_id ] === "undefined" )
{
continue;
}
const value = bucket.getDataByName( field_id );
const { label, type } = this._program.fields[ field_id ];
questions.push( {
id: field_id,
label: label || "",
value: value,
type: type || "",
applicable: this._getApplicable( matches, field_id, value ),
} );
}
return questions;
},
/**
* Determine when a field is shown by index
* Map boolean values of [0, 1] to [true, false]
*
* @param {Object} matches field matches
* @param {String} field_id id of field
* @param {Object} field_value field object
*
* @return {Array.<boolean>} array of booleans
*/
'private _getApplicable'( matches, field_id, field_value )
{
// If object is undefined, default to array of true
if ( typeof matches[ field_id ] === "undefined" )
{
return field_value.map( _ => true );
}
const indexes = matches[ field_id ].indexes;
const all_match = matches[ field_id ].all;
if ( indexes.length > 0 )
{
// Map indexes of 0, 1 to true, false
return indexes.map( x => !!x );
}
else
{
return field_value.map( _ => all_match );
}
},
} );