Script: Copying Tyme.app projects and tasks to TaskPaper


#1

A script which copies the Tyme.app database of tracked projects and tasks to the clipboard in TaskPaper 3 format.

I use it simply to get the names of some currently tracked items when starting a new TaskPaper file, so that further time counts of tracking from TaskPaper are added to the existing items in Tyme.app.

Can be run from something like Keyboard Maestro or Fastscripts, or, for testing, from Script Editor (Yosemite onwards – this is a JavaScript for Automation script).

var strClip =  (function () {
    'use strict';

    // JSO nested and tagged text nodes -> TaskPaper 3 text
    // [dct] -> Integer -> String
    function jsoNestTP(lst, lngIndent) {
        return lst.reduce(function (txt, node) {
            var strType = node.type,
                lstNest = node.nest,
                dctTags = node.tags,
                strTags = (dctTags ? tpTagString(dctTags) : '');

            return txt + (lngIndent ? nreps('\t', lngIndent) : '') +
                (strType === 'task' ? '- ' : '') + node.txt +
                (strType === 'project' ? ":" : '') +
                (strTags ? ' ' + strTags : '') + '\n' +
                ((lstNest && lstNest.length) ? jsoNestTP(lstNest, lngIndent + 1) : '');
        }, '');
    }

    // JSO set of key-value pairs -> TaskPaper 3 tag string
    // [(key, value)] --> String
    function tpTagString(dctTags) {
        return Object.keys(dctTags).map(function (k) {
            var v = (k !== 'due') ? dctTags[k] : (
                function() {
                    var strDate = dctTags[k],
                        lstMatch = strDate.match(/^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}):\d{2}/);
                    
                    return (lstMatch ? lstMatch[1] + ' ' + lstMatch[2] : strDate);
                }
            )();
        
            return '@' + k + (v ? '(' + v + ')' : '');
        }).join(' ');
    }

    // Tyme projectTags or taskTags rewritten as JSO dict of key:value pairs 
    // Tyme Object --> String -> {(key, value)}
    function tagSet(oParent, strClass) {
        var dctTags = oParent[strClass]()
            .reduce(function (a, tag) {
                return (a[tag.name()] = "", a);
            }, {}),
            dte = oParent.duedate();

        if (dte !== null) dctTags.due = dte.toISOString();

        return (Object.keys(dctTags).length > 0 ? dctTags : undefined);
    }

    // Substring s repeated n times
    // String -> Integer -> String
    function nreps(s, n) {
        var o = '';
        if (n < 1) return o;
        while (n > 1) {
            if (n & 1) o += s;
            n >>= 1;
            s += s;
        }
        return o + s;
    }

    // MAIN

    // Tyme interface -> JSO nest -> TaskPaper 3 text
    return jsoNestTP(
        Application("Tyme").projects()
        .filter(function (p) {
            return (p.archived() === false);
        })
        .map(function (p) {
            return { // PROJECT

                txt: p.name(),
                'type': 'project',
                'tags': tagSet(p, 'projecttags'),
                
                nest: p.tasks()
                    .filter(function (t) {
                        return (t.archived() === false);
                    })
                    .map(function (t) {
                        return { // TASK
                            txt: t.name(),
                            'type': 'task',
                            'tags': tagSet(t, 'tasktags')
                        }
                    })              
            };
        }),
        0
    );
})();

var a = Application.currentApplication(),
    sa = (a.includeStandardAdditions = true, a); 

sa.setTheClipboardTo(strClip);
sa.activate;
sa.displayNotification("Tyme.app projects copied as TaskPaper", {withTitle: "Copied to clipboard"})

strClip