view src/layout/ViewConfig.ts @ 150:3ce355e4f388 default tip

bye jest; hi vitest. new working test for styles.ts
author drewp@bigasterisk.com
date Mon, 08 May 2023 17:27:44 -0700
parents cf642d395be4
children
line wrap: on
line source

import Immutable from "immutable"; // mostly using this for the builtin equals() testing, since NamedNode(x)!=NamedNode(x)
import { DataFactory, NamedNode, Quad_Predicate, Term } from "n3";
import { MultiStore } from "../MultiStore";
import { EX, RDF } from "./namespaces";
import { uriValue } from "./rdf_value";
import { Quad_Graph } from "rdf-js";
const Uri = DataFactory.namedNode;

function firstElem<E>(seq: Iterable<E>): E {
  for (let e of seq) {
    return e;
  }
  throw new Error("no elems");
}

export interface Link {
  // If you display a subject u1 with a `pred` edge to u2, then treat u2 as an alias of u1.
  pred: NamedNode;
}

interface TableDesc {
  uri: NamedNode;
  primary: NamedNode;
  joins: NamedNode[];
  links: Link[];
}

// High-level guide to how to draw the page, independent of the graph data.
// Layout.ts turns this plus the actual graph data into a structure that's
// close to the final render.
export class ViewConfig {
  viewRoot: NamedNode; // this structure...
  graph: MultiStore; // in this graph...
  tables: TableDesc[] = []; // populates all the rest of these fields for use by Layout
  hidePredFrees: Immutable.Set<Quad_Predicate> = Immutable.Set();
  hideGraphEverywhere: Immutable.Set<Quad_Graph> = Immutable.Set();

  constructor(graph: MultiStore, viewUri: NamedNode) {
    this.graph = graph;
    this.viewRoot = viewUri;
    // todo
    // const here = "https://bigasterisk.com/lanscape/";
    // if (this.viewRoot.value.startsWith(here)) {
    //   this.viewRoot = new NamedNode(this.viewRoot.value.slice(here.length));
    // }
    this.read();
  }

  private read() {
    for (let table of this.graph.getObjects(this.viewRoot, EX("table"), null)) {
      const t = this.readTable(table);
      this.tables.push(t);
    }
    this.tables.sort();

    this.readHides();
  }

  private readHides() {
    for (let instr of this.graph.getObjects(this.viewRoot, EX("hide"), null)) {
      const types = this.graph.getObjects(instr, RDF("type"), null);
      if (types.length == 1 && types[0].equals(EX("HideEverywhere"))) {
        for (let g of this.graph.getObjects(instr, EX("graph"), null)) {
          this.hideGraphEverywhere = this.hideGraphEverywhere.add(
            g as Quad_Graph
          );
        }
      } else if (types.length == 1 && types[0].equals(EX("HideFreeStatements"))) {
        for (let pred of this.graph.getObjects(instr, EX("predicate"), null)) {
          this.hidePredFrees = this.hidePredFrees.add(pred as Quad_Predicate);
        }
      } else {
        throw new Error(":hide instruction must have 1 valid type");
      }
    }
  }

  private readTable(table: Term): TableDesc {
    const tableType = uriValue(this.graph, table, EX("primaryType"));
    const joins: NamedNode[] = [];
    for (let joinType of this.graph.getObjects(table, EX("joinType"), null)) {
      joins.push(joinType as NamedNode);
    }
    joins.sort();

    const links: Link[] = [];
    for (let linkDesc of this.graph.getObjects(table, EX("link"), null)) {
      links.push({
        pred: uriValue(this.graph, linkDesc, EX("predicate")),
      });
    }

    return {
      uri: table as NamedNode,
      primary: tableType,
      joins: joins,
      links: links,
    };
  }
}