Handling forking on different levels of Tasks
Asked Answered
F

0

9

I'm really stuck on handling different levels of Tasks in Ramda. I'm trying to build a script to parse LESS files for comments and build a pattern library site from the data in the comments and inline HTML from an example file. It's all working (with a lot of help from SO) except the inlining the example file contents.

const target = path.join(__dirname, 'app/dist/templates/');
const source = path.join(__dirname, 'source/');
const stylesSource = path.join(__dirname, 'source/less/');
const template = path.join(__dirname, 'app/src/templates/page-template.html');

const writeTemplate = function(data) {
    var rs = fs.createReadStream(template);
    var ws = fs.createWriteStream(path.join(target, R.toLower(R.concat(data.name, ".html"))));

    rs
        .pipe(replaceStream("{{name}}", data.name))
        .pipe(replaceStream("{{description}}", data.description))
        .pipe(replaceStream("{{example}}", data.example))
        .pipe(ws);
}

const inlineExample = function(data) {
    return readFile(path.join(source, data.example));
}

//    parseFile :: String -> { name :: String
//                           , description :: String
//                           , example :: String }
const parseFile = function parseFile(data) {
  return {
    name: R.trim(R.nth(1, R.match(/[$]name:(.*)/, data))),
    description: R.trim(R.nth(1, R.match(/[$]description:(.*)/, data))),
    example: R.trim(R.nth(1, R.match(/[$]example:(.*)/, data)))
  };
};

//    readDirectories :: String -> Task [String]
const readDirectories = function readDirectories(dir) {
  return new Task(function (reject, resolve) {
    glob(path.join(dir, "/**/*.less"), function (err, files) {
          err == null ? resolve(files) : reject(err);
        })
  });
};

//    readFile :: String -> Task String
const readFile = function readFile(filename) {
  return new Task(function (reject, resolve) {
    fs.readFile(path.normalize(filename), 'utf8', function (err, data) {
      err == null ? resolve(data) : reject(err);
    });
  });
};

//    dirs :: Task [String]
const dirs = readDirectories(stylesSource);

//    files :: Task [Task String]
const files = R.map(R.map(readFile), dirs);

//    commuted :: Task (Task [String])
const commuted = R.map(R.commute(Task.of), files);

//    unnested :: Task [String]
const unnested = R.unnest(commuted);

//    parsed :: Task [{ name :: String
//                    , description :: String
//                    , example :: String }]
const parsed = R.map(R.map(parseFile), unnested);

const inlined = R.map(R.chain(inlineExample), parsed);

inlined.fork(err => {
      process.stderr.write(err.message);
    },
    data => {
      R.map(writeTemplate, data);
      util.log(R.concat('Library successfully generated at: ', target));
    });
});

I can go through, read the directory, open the files (returning a new Task) and extract the template path from the comments. I'm then running (I think) parseFile on the path (which returns a Task) and that's where it's failing. I'm struggling with getting the example template Task forked so I can use the contents.

I'm open to any suggestions but suspect that the problem is somewhere in R.map(writeTemplate, data) in the original success fork but I'm a bit out of my depth now.

Floria answered 17/11, 2015 at 15:31 Comment(7)
Instead of using map followed by unnest, you should just chain directly.Priestley
R.chain(inlineExample) seems to be your problem. Your inlineExample function returns a Task, but you apply the chainer on a list, which is incompatible. I assume you want R.chain(R.traverse(inlineExample), parsed) (or whatever an (a -> Task b) -> List a -> Task (List b) function is called)Priestley
R.traverse? I'm just starting with signatures and Tasks.Floria
Yeah, those folktale tasks should have a way to execute multiple tasks in parallel. Something like Promise.all, it would be [Task a] -> Task [a]. I couldn't find such a method in their docs though, so I was suggesting the generic one (which relies on Task being an Applicative)Priestley
you said - I'm then running (I think) parseFile - -so you're not sure if you're running it? i.e parseFile ? if so why?Wobbly
Bad phrasing on my part @Coffee. It is running parseFile, but doesn't seem to want to fork the task returned from that so when we get to writeTemplate it's trying to run on a Task, not file data. Does that make sense?Floria
2 hours left for 100 points...Floria

© 2022 - 2024 — McMap. All rights reserved.