Skip to content

Commit

Permalink
Merge pull request #15 from w3c/add-dataypes
Browse files Browse the repository at this point in the history
Add dataypes
  • Loading branch information
iherman authored Aug 16, 2023
2 parents 58f4b08 + bedb6c7 commit b37132b
Show file tree
Hide file tree
Showing 55 changed files with 951 additions and 332 deletions.
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## Version 1.4.4

- Adding the possibility to define datatypes

## Version 1.4.3

- Bug handling...

## Version 1.4.2

- Minor improvement on the generated JSON vs language handling (thanks to @pchampin).
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ Each block sequence consists of blocks with the following keys:`id`, `property`,

- `individual`: blocks of definitions of individuals, i.e., a single resources defined in the vocabulary. For each individual the `id` key defines the property name (no prefix should be used here); the possible types are defined in the block for `upper_value` as a single term, or a sequence of terms.

- `datatype`: blocks of datatype definitions. For each datatype the `id` key defines the datatype name (no prefix should be used here); the possible types are defined in the block for `upper_value` as a single term for possible datatype this is derived from.

There are some examples in the [example directory on github](https://github.com/w3c/yml2vocab/tree/main/example) that illustrate all of these terms.

## Installation and use
Expand Down
15 changes: 13 additions & 2 deletions dist/lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@
* @packageDocumentation
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.global = exports.StatusCounter = exports.Status = void 0;
exports.global = exports.StatusCounter = exports.Status = exports.EXTRA_DATATYPES = void 0;
/**
* List of datatypes that are formally defined in the RDF World, and are beyond the
* list of core, XSD datatypes
*/
exports.EXTRA_DATATYPES = [
"rdf:JSON",
"rdf:HTML",
"rdf:XMLLiteral",
"rdf:PlainLiteral",
"rdf:langString"
];
/**
* Characterization of a class/property/individual on whether it is stable or not.
*/
Expand All @@ -14,7 +25,7 @@ var Status;
Status["stable"] = "stable";
Status["reserved"] = "reserved";
Status["deprecated"] = "deprecated";
})(Status || (exports.Status = Status = {}));
})(Status = exports.Status || (exports.Status = {}));
/**
* Simple counter to track how many terms are defined as `stable`, `reserved`, or `deprecated`.
*/
Expand Down
6 changes: 5 additions & 1 deletion dist/lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,14 @@ function toContext(vocab) {
top_level[prop.id] = propertyContext(prop, false);
}
}
// Finally, add the individuals
// Add the individuals
for (const individual of vocab.individuals) {
top_level[individual.id] = `${common_1.global.vocab_url}${individual.id}`;
}
// Add the individuals
for (const datatype of vocab.datatypes) {
top_level[datatype.id] = `${common_1.global.vocab_url}${datatype.id}`;
}
// That is it... return the nicely formatted JSON text
return JSON.stringify({ "@context": top_level }, null, 4);
}
Expand Down
68 changes: 52 additions & 16 deletions dist/lib/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ exports.getData = void 0;
*/
const common_1 = require("./common");
const common_2 = require("./common");
const common_3 = require("./common");
const schema_1 = require("./schema");
/************************************************ Helper functions and constants **********************************/
/**
Expand Down Expand Up @@ -222,6 +223,7 @@ function finalizeRawVocab(raw) {
class: raw.class?.map(finalizeRawEntry),
property: raw.property?.map(finalizeRawEntry),
individual: raw.individual?.map(finalizeRawEntry),
datatype: raw.datatype?.map(finalizeRawEntry),
};
}
/******************************************* External entry point **********************************/
Expand All @@ -246,6 +248,25 @@ function getData(vocab_source) {
throw (new TypeError(`JSON Schema validation error`, { cause: error }));
}
const vocab = finalizeRawVocab(validation_results.vocab);
// Calculates cross references from properties to classes or datatypes; used
// to make the cross references for the property ranges and domains
// @param raw: raw entry for the class or datatype
// @param refs: the range or domain array of the property
// @return: whether the class/datatype is indeed in the range of the property
const crossref = (raw, property, refs, single_ref, multi_ref) => {
if (refs) {
// Remove the (possible) namespace reference from the CURIE
const pure_refs = refs.map((range) => {
const terms = range.split(':');
return terms.length === 1 ? range : terms[1];
});
if (pure_refs.length !== 0 && pure_refs.indexOf(raw.id) !== -1) {
(pure_refs.length === 1 ? single_ref : multi_ref).push(property.id);
return true;
}
}
return false;
};
// Convert all the raw structures into their respective internal representations for
// prefixes, ontology properties, classes, etc.
// Get the extra prefixes and combine them with the defaults. Note that the 'vocab' category
Expand Down Expand Up @@ -304,7 +325,7 @@ function getData(vocab_source) {
else {
let isDTProperty = true;
for (const rg of range) {
if (rg.startsWith("xsd") === false) {
if (!(rg.startsWith("xsd") === true || common_3.EXTRA_DATATYPES.find((entry) => entry === rg) !== undefined)) {
isDTProperty = false;
break;
}
Expand Down Expand Up @@ -341,20 +362,8 @@ function getData(vocab_source) {
common_2.global.status_counter.add(raw.status);
// Get all domain/range cross references
for (const property of properties) {
const crossref = (refs, single_ref, multi_ref) => {
if (refs) {
// Remove the (possible) namespace reference from the CURIE
const pure_refs = refs.map((range) => {
const terms = range.split(':');
return terms.length === 1 ? range : terms[1];
});
if (pure_refs.length !== 0 && pure_refs.indexOf(raw.id) !== -1) {
(pure_refs.length === 1 ? single_ref : multi_ref).push(property.id);
}
}
};
crossref(property.range, range_of, includes_range_of);
crossref(property.domain, domain_of, included_in_domain_of);
crossref(raw, property, property.range, range_of, includes_range_of);
crossref(raw, property, property.domain, domain_of, included_in_domain_of);
}
return {
id: raw.id,
Expand Down Expand Up @@ -385,6 +394,33 @@ function getData(vocab_source) {
example: raw.example,
};
}) : [];
return { prefixes, ontology_properties, classes, properties, individuals };
// Get the datatypes.
const datatypes = (vocab.datatype !== undefined) ?
vocab.datatype.map((raw) => {
const range_of = [];
const includes_range_of = [];
// Get the range cross-references
for (const property of properties) {
const is_dt_property = crossref(raw, property, property.range, range_of, includes_range_of);
if (is_dt_property) {
// a bit convoluted, but trying to avoid repeating the extra entry
property.type = [...((new Set(property.type)).add('owl:DatatypeProperty'))];
}
}
return {
id: raw.id,
subClassOf: (raw.upper_value !== undefined) ? raw.upper_value : [],
label: raw.label,
comment: raw.comment,
deprecated: raw.deprecated,
defined_by: raw.defined_by,
status: raw.status,
type: (raw.upper_value !== undefined) ? raw.upper_value : [],
see_also: raw.see_also,
example: raw.example,
range_of, includes_range_of
};
}) : [];
return { prefixes, ontology_properties, classes, properties, individuals, datatypes };
}
exports.getData = getData;
69 changes: 66 additions & 3 deletions dist/lib/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,10 @@ function toHTML(vocab, template_text) {
}
}
// Again an extra list for range/domain references, if applicable
if ((item.range_of.length > 0 ||
if (item.range_of.length > 0 ||
item.domain_of.length > 0 ||
item.includes_range_of.length > 0 ||
item.included_in_domain_of.length > 0)) {
item.included_in_domain_of.length > 0) {
// This for the creation of a list of property references, each
// a hyperlink to the property's definition.
const prop_names = (ids) => {
Expand Down Expand Up @@ -431,6 +431,64 @@ function toHTML(vocab, template_text) {
}
}
};
// Generation of the section content for datatypes: a big table, with a row per datatype
// There is a check for a possible template error and also whether there are individual
// definitions in the first place.
//
// The generated DOM nodes get a bunch of RDFa properties (typeof, resource, property,...)
// that makes things fairly confusing :-(
const datatypes = (dt_list, statusFilter) => {
const { id_prefix, intro_prefix } = statusSignals(statusFilter);
const section = document.getElementById(`${id_prefix}datatype_definitions`);
if (section) {
if (dt_list.length > 0) {
addChild(section, 'p', `The following are ${intro_prefix} datatype definitions in the <code>${vocab_prefix}</code> namespace.`);
for (const item of dt_list) {
const dt_section = addChild(section, 'section');
dt_section.id = item.id;
commonFields(dt_section, item);
if (item.subClassOf && item.subClassOf.length > 0) {
const dl = addChild(dt_section, 'dl');
dl.className = 'terms';
addChild(dl, 'dt', 'Derived from:');
const dd = addChild(dl, 'dd');
for (const superclass of item.subClassOf) {
const span = addChild(dd, 'span');
span.innerHTML = resolveCurie(superclass);
span.setAttribute('property', 'rdfs:subClassOf');
span.setAttribute('resource', superclass);
}
}
if (item.range_of.length > 0 || item.includes_range_of.length > 0) {
// This for the creation of a list of property references, each
// a hyperlink to the property's definition.
const prop_names = (ids) => {
const names = ids.map(resolveCurie);
return names.join(', ');
};
const dl = addChild(dt_section, 'dl');
dl.className = 'terms';
if (item.range_of.length > 0) {
addChild(dl, 'dt', "Range of:");
const dd = addChild(dl, 'dd');
dd.innerHTML = prop_names(item.range_of);
}
if (item.includes_range_of.length > 0) {
addChild(dl, 'dt', "Includes the range of:");
const dd = addChild(dl, 'dd');
dd.innerHTML = prop_names(item.includes_range_of);
}
}
setExample(dt_section, item);
}
}
else {
// removing the section from the DOM
if (section.parentElement)
section.parentElement.removeChild(section);
}
}
};
/* *********************** The real processing part ****************** */
// Get the DOM of the template
const document = (new jsdom_1.JSDOM(template_text)).window.document;
Expand Down Expand Up @@ -459,7 +517,12 @@ function toHTML(vocab, template_text) {
const actual_individuals = vocab.individuals.filter((entry) => entry.status === filter);
individuals(actual_individuals, filter);
});
// 7. Remove the sections on reserved/deprecation in case there aren't any...
// 7. Sections on datatypes
Object.values(common_1.Status).map((filter) => {
const actual_datatypes = vocab.datatypes.filter((entry) => entry.status === filter);
datatypes(actual_datatypes, filter);
});
// 8. Remove the sections on reserved/deprecation in case there aren't any...
if (common_1.global.status_counter.counter(common_1.Status.reserved) === 0) {
const section = document.getElementById('reserved_term_definitions');
if (section !== null && section.parentElement)
Expand Down
17 changes: 17 additions & 0 deletions dist/lib/jsonld.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const generic_context = {
"rdfs_classes": { "@reverse": "rdfs:isDefinedBy", "@type": "@id" },
"rdfs_properties": { "@reverse": "rdfs:isDefinedBy", "@type": "@id" },
"rdfs_instances": { "@reverse": "rdfs:isDefinedBy", "@type": "@id" },
"rdfs_datatypes": { "@reverse": "rdfs:isDefinedBy", "@type": "@id" },
"dc:title": { "@container": "@language" },
"dc:description": { "@container": "@language" },
};
Expand Down Expand Up @@ -195,6 +196,22 @@ function toJSONLD(vocab) {
if (individuals.length > 0)
jsonld.rdfs_individuals = individuals;
}
{
// Get the datatypes
const datatypes = [];
for (const dt of vocab.datatypes) {
const dt_object = {};
dt_object["@id"] = `${common_1.global.vocab_prefix}:${dt.id}`;
dt_object["@type"] = `rdfs:Datatype`;
if (dt.subClassOf && dt.subClassOf.length > 0) {
dt_object["rdfs:subClassOf"] = dt.subClassOf;
}
commonFields(dt_object, dt);
datatypes.push(dt_object);
}
if (datatypes.length > 0)
jsonld.rdfs_datatypes = datatypes;
}
return JSON.stringify(jsonld, null, 4);
}
exports.toJSONLD = toJSONLD;
13 changes: 13 additions & 0 deletions dist/lib/turtle.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,19 @@ function toTurtle(vocab) {
commonFields(ind);
}
}
if (vocab.datatypes.length > 0) {
turtle += "# Definitions of datatypes\n";
for (const dt of vocab.datatypes) {
turtle += `${common_1.global.vocab_prefix}:${dt.id} a rdfs:Datatype ;\n`;
if (dt.status === common_1.Status.deprecated) {
turtle += ` owl:deprecated true ;\n`;
}
if (dt.subClassOf && dt.subClassOf.length > 0) {
turtle += ` rdfs:subClassOf ${dt.subClassOf.join(", ")} ;\n`;
}
commonFields(dt);
}
}
return turtle;
}
exports.toTurtle = toTurtle;
15 changes: 15 additions & 0 deletions dist/lib/vocab.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,21 @@
],
"unevaluatedProperties": false
}
},

"datatype" : {
"title": "Definition of datatypes",
"$comment": "The use of 'unevaluatedProperties' is the schema 2019 idiom to disallow additional properties.",
"type": "array",
"items": {
"type": "object",
"allOf": [
{
"$ref": "#/$defs/CommonTerm"
}
],
"unevaluatedProperties": false
}
}
},

Expand Down
2 changes: 1 addition & 1 deletion docs/assets/search.js

Large diffs are not rendered by default.

Loading

0 comments on commit b37132b

Please sign in to comment.