codenautas/time-warp

View on GitHub
time-warp.js

Summary

Maintainability
D
2 days
Test Coverage
"use strict";

(function codenautasModuleDefinition(root, name, factory) {
    /* global define */
    /* istanbul ignore next */
    if(typeof root.globalModuleName !== 'string'){
        root.globalModuleName = name;
    }
    /* istanbul ignore next */
    if(typeof exports === 'object' && typeof module === 'object'){
        module.exports = factory();
    }else if(typeof define === 'function' && define.amd){
        define(factory);
    }else if(typeof exports === 'object'){
        exports[root.globalModuleName] = factory();
    }else{
        root[root.globalModuleName] = factory();
    }
    root.globalModuleName = null;
})(/*jshint -W040 */this, 'TimeWarp', function() {
/*jshint +W040 */

/*jshint -W004 */
var TimeWarp = {};
/*jshint +W004 */

require('lazy-some').bindToPrototypeIn(Array);

var likeAr = require('like-ar');

var regexplicit = require('regexplicit');

var changing = require('best-globals').changing;

TimeWarp = function TimeWarp(object, precision){
    likeAr(TimeWarp.property).forEach(function(prop, name){
        if(name in object){
            var value = object[name];
            if(!prop.text){
                value = Number(value);
            }
            if(!prop.validate(value)){
                throw new Error("invalid value for "+name);
            }
            this[name] = value;
        }
    },this);
    if(!('precision' in this) && precision){
        this.precision = precision;
    }
    likeAr(object).forEach(function(value, name){
        if(!(name in TimeWarp.property[this.precision].property)){
            throw new Error("invalid property "+name+" for "+this.precision);
        }
    },this);
    TimeWarp.property.precision.validate(this.precision);
};

function validateIntRange(from,to){
    return function(n){return n>=from && n<=to && n===Math.abs(n);};
}

TimeWarp.precisions = [
    {name:'year'     , controlers:[
        {regexp:/^\s*(\d+)\s*$/, match2tw: function(matches){ return TimeWarp.year(Number(matches[1])); }}
    ]},
    {name:'trim', controlers:[
        {regexp:regexplicit.yearTrim, match2tw: function(matches){ 
            var tw={year:matches[1], trim:matches[2]};
            if(matches[3]){ tw.trim=1; }
            if(matches[4]){ tw.trim=2; }
            if(matches[5]){ tw.trim=3; }
            if(matches[6]){ tw.trim=4; }
            return TimeWarp.trim(tw);
        }}, 
        {regexp:regexplicit.trimYear, match2tw: function(matches){ 
            var tw={year:matches[6], trim:matches[1]};
            if(matches[2]){ tw.trim=1; }
            if(matches[3]){ tw.trim=2; }
            if(matches[4]){ tw.trim=3; }
            if(matches[5]){ tw.trim=4; }
            return TimeWarp.trim(tw);
        }}, 
    ] },
    {name:'sem', controlers:[
        {regexp:regexplicit.yearSem, match2tw: function(matches){ 
            var tw={year:matches[1], sem:matches[2]};
            if(matches[3]){ tw.sem=1; }
            if(matches[4]){ tw.sem=2; }
            return TimeWarp.sem(tw);
        }}, 
        {regexp:regexplicit.semYear, match2tw: function(matches){ 
            var tw={year:matches[4], sem:matches[1]};
            if(matches[2]){ tw.sem=1; }
            if(matches[3]){ tw.sem=2; }
            return TimeWarp.sem(tw);
        }}, 
    ] },
];

TimeWarp.precisionsRegExp = new RegExp(TimeWarp.precisions.map(function(p){ return p.name; }).join('|'));

TimeWarp.property = {
    precision: {validate:function(x){ return TimeWarp.precisionsRegExp.test(x); }, text:true, skipInToString:true},
    year     : {validate:function(x){ return !isNaN(x) && typeof x === "number";}, property:{precision:true, year:true}, prefix:''},
    trim     : {validate:validateIntRange(1,4) , property:{precision:true, year:true, trim :true}, prefix:'t'},
    sem      : {validate:validateIntRange(1,2) , property:{precision:true, year:true, sem  :true}, prefix:'s'},
    month    : {validate:validateIntRange(1,12), property:{precision:true, year:true, month:true}, prefix:'-'}
};

TimeWarp.year = function parse(year){
    return new TimeWarp({year:year}, 'year');
};

function completeYearAndValidateMinimumLength(o){
    if(o.year<100 && o.year>=0){
        if(typeof o.year === "string" && o.year.length<2){
            throw new Error('invalid year');
        }
        return changing(o,{year:2000+Number(o.year)});
    }
    return o;
}

TimeWarp.trim = function parse(o){
    o=completeYearAndValidateMinimumLength(o);
    return new TimeWarp(o,'trim');
};

TimeWarp.sem = function parse(o){
    o=completeYearAndValidateMinimumLength(o);
    return new TimeWarp(o,'sem');
};

TimeWarp.parse = function parse(text){
    var pc = TimeWarp.precisions.lazySome(function(precisionDef){
        var result = precisionDef.controlers.lazySome(function(controler){
            var match=text.match(controler.regexp);
            return match && {controler:controler, match:match};
        });
        return result && {precision:precisionDef, controler:result.controler, match:result.match};
    });
    if(pc){
        return pc.controler.match2tw(pc.match);
    }else{
        throw new Error('not a time string');
    }
};

TimeWarp.JSON4reviver = function JSON4reviver(value){
    var rta = new TimeWarp(value);
    return rta;
};

TimeWarp.prototype.toString = function toString(){
    return likeAr(TimeWarp.property).map(function(prop, name){
        if(prop.skipInToString){
            return '';
        }
        if(name in this){
            return prop.prefix+this[name];
        }else{
            return '';
        }
    },this).join('');
};

return TimeWarp;

});