Revision cc881149f3ed6cb516936ae3810989acc06e9b8c authored by Eric Prud'hommeaux on 26 November 2016, 06:26:03 UTC, committed by GitHub on 26 November 2016, 06:26:03 UTC
c.f. https://rawgit.com/shexSpec/shex.js/master/doc/shex-simple.html
1 parent 83c7341
Raw File
ShExLoader.js
// **ShExLoader** return promise to load ShExC, ShExJ and N3 (Turtle) files.

var FS = require("fs");
var N3 = require("n3");
var ShExUtil = require("../lib/ShExUtil");
var ShExParser = require("../lib/ShExParser").Parser;
var Request = require("request-promise");
var Promise = require("promise");
var Path = require("path");
var Jsonld = require("jsonld");

/* Helper function to read from filesystem or web.
 */
function GET (f) {
  var m;
  return f === "-" ?
    new Promise(function (fulfill, reject) {
      var inputChunks = [];

      //process.stdin.resume(); is old mode needed?
      process.stdin.setEncoding("utf8");

      process.stdin.on("data", function (chunk) {
        inputChunks.push(chunk);
      });

      process.stdin.on("end", function () {
        fulfill({text: inputChunks.join(""), url: f});
      });

      process.stdin.on("error", function (e) {
        reject(e);
      });
    }) : (f.match("^[a-z]+://.") && !f.match("^file://.")) ?
    // Read from http or whatever Request handles.
    Request(f).then(function (text) {
      return {text: text, url: f};
    }) : (m = f.match("^data:([^,]+),(.*)$")) ?
    // Read from data: URL
    Promise.resolve({text: m[2], url: m[0]}) :
  // Read from filesystem
  new Promise(function (fulfill, reject) {
    var filename = f;
    var fileURLmatch = filename.match("^file://[^/]*(/.*)$");
    if (fileURLmatch) {
      filename = fileURLmatch[1];
    }
    FS.readFile(filename, "utf8", function (error, text) {
      if (error) {
        reject(error)
      } else {
        fulfill({text: text, url: fileURLmatch ? f : "file://" + Path.resolve(process.cwd(), f)});
      }
    })
  });
}

function loadList (list, done) {
  return list.map(function (p) {
    return GET(p).then(function (loaded) {
      return done(loaded.text, loaded.url);
    });
  });
}

/* LoadPromise - load shex and json files into a single Schema and turtle into
 * a graph (Data).
 */
function LoadPromise (shex, json, turtle, jsonld, schemaOptions, dataOptions) {
  var returns = {
    schema: ShExUtil.emptySchema(),
    data: N3.Store(),
    schemaMeta: [],
    dataMeta: []
  }

  function add (src, metaList, mediaType, f, target, options) {
    return loadList(src, function (text, url) {
      var meta = {mediaType: mediaType, url: url, base: url, prefixes: {}};
      metaList.push(meta);
      return new Promise(function (resolve, reject) {
        f(resolve, reject, text, mediaType, url, target, meta, options);
      });
    })
  }

  return Promise.all([].
                     // gather all the potentially remote inputs
                     concat(add(shex, returns.schemaMeta,
                                "text/shex", parseShExC, returns.schema, schemaOptions)).
                     concat(add(json, returns.schemaMeta,
                                "text/json", parseShExJ, returns.schema, schemaOptions)).
                     concat(add(turtle, returns.dataMeta,
                                "text.turtle", parseTurtle, returns.data, dataOptions)).
                     concat(add(jsonld, returns.dataMeta,
                                "application/ld+json", parseJSONLD, returns.data, dataOptions))
                    ).then(function () { return returns; });
}

function parseShExC (resolve, reject, text, mediaType, url, schema, meta, schemaOptions) {
  try {
    var s = (new ShExParser(url, {}, schemaOptions)).parse(text);
    // !! horrible hack until I set a variable to know if there's a BASE.
    if (s.base === url) delete s.base;
    ShExUtil.merge(schema, s, true, true);
    meta.prefixes = schema.prefixes;
    meta.base = schema.base || meta.base;
    resolve([mediaType, url]);
  } catch (e) {
    var e2 = Error("error parsing ShEx " + url + ": " + e);
    e2.stack = e.stack;
    reject(e2);
  }
}

function parseShExJ (resolve, reject, text, mediaType, url, schema, meta, schemaOptions) {
  try {
    var s = JSON.parse(text);
    ShExUtil.merge(schema, s, true, true);
    meta.prefixes = schema.prefixes;
    meta.base = schema.base;
    resolve([mediaType, url]);
  } catch (e) {
    var e2 = Error("error parsing JSON " + url + ": " + e);
    e2.stack = e.stack;
    reject(e2);
  }
}

function parseTurtle (resolve, reject, text, mediaType, url, data, meta, dataOptions) {
  N3.Parser({documentIRI: url, blankNodePrefix: ""}).
    parse(text,
          function (error, triple, prefixes) {
            if (prefixes)
              meta.prefixes = prefixes;
              data.addPrefixes(prefixes);
            if (error) {
              reject("error parsing " + url + ": " + error);
            } else if (triple) {
              data.addTriple(triple)
            } else {
              meta.base = this._base;
              resolve([mediaType, url]);
            }
          });
}

function parseJSONLD (resolve, reject, text, mediaType, url, data, meta, dataOptions) {
  var struct = JSON.parse(text);
  Jsonld.toRDF(struct, {format: "application/nquads", base: url}, function (lderr, nquads) {
    if (lderr) {
      reject("error parsing JSON-ld " + url + ": " + lderr);
    } else {
      meta.prefixes = {}; // @@ take from @context?
      meta.base = url;    // @@ take from @context.base? (or vocab?)
      parseTurtle(resolve, reject, nquads, mediaType, url, data, meta);
    }
  });
}

function LoadExtensions () {
  return FS.
    readdirSync(__dirname + "/../extensions").
    filter(function (s) { return s.indexOf(".js") !== -1; }).
    reduce(function (ret, module) {
      var t = require(__dirname + "/../extensions/" + module);
      ret[t.url] = t;
      return ret;
    }, {});
}

// Expose ShExLoader, attaching all functions to it
if (typeof require !== "undefined" && typeof exports !== "undefined")
  module.exports = { load: LoadPromise, loadExtensions: LoadExtensions, GET: GET }; // node environment
else
  ShExLoader = LoadPromise;
back to top