UNPKG

schema-dts-gen

Version:

Generate TypeScript Definitions for Schema.org Schema

210 lines 7.36 kB
/** * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { NamedNode } from 'n3'; const rdfSchemaPrefix = 'http://www.w3.org/2000/01/rdf-schema#'; const rdfSyntaxPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; const schemaPrefix = ['http://schema.org/', 'https://schema.org/']; const owlPrefix = 'http://www.w3.org/2002/07/owl#'; function possibleTerms(prefix, names) { if (prefix instanceof Array) { return prefix.map(p => possibleTerms(p, names)).flat(); } if (names instanceof Array) { return names.map(n => possibleTerms(prefix, n)).flat(); } return [new NamedNode(`${prefix}${names}`)]; } function debugStr(node) { return JSON.stringify(node.toJSON(), undefined, 2); } // Well-known properties const Type = new NamedNode(`${rdfSyntaxPrefix}type`); const Comment = possibleTerms(rdfSchemaPrefix, 'comment'); const SubClassOf = possibleTerms(rdfSchemaPrefix, 'subClassOf'); const DomainIncludes = [ ...possibleTerms(schemaPrefix, 'domainIncludes'), // Technically "domainIncludes" and "domain" have different semantics. // domainIncludes is repeated, to include a union of possible types in the // domain. "domain" is expected to appear once. To use "domain" for a union of // possible values, it is used with owl:unionOf and a list literal. ...possibleTerms(rdfSchemaPrefix, 'domain'), ]; const RangeIncludes = [ ...possibleTerms(schemaPrefix, 'rangeIncludes'), // See comment on domainIncludes vs domain above. ...possibleTerms(rdfSchemaPrefix, 'range'), ]; const SupersededBy = possibleTerms(schemaPrefix, 'supersededBy'); // Well-known classes const Class = new NamedNode(`${rdfSchemaPrefix}Class`); const Property = new NamedNode(`${rdfSyntaxPrefix}Property`); const OWLProperty = possibleTerms(owlPrefix, [ 'DatatypeProperty', 'ObjectProperty', 'FunctionalProperty', 'InverseFunctionalProperty', 'AnnotationProperty', 'SymmetricProperty', 'TransitiveProperty', ]); const OWLClass = possibleTerms(owlPrefix, 'Class'); const OWLOntology = possibleTerms(owlPrefix, 'Ontology'); const DataType = possibleTerms(schemaPrefix, 'DataType'); /** * If an ObjectPredicate represents a comment, returns the comment. Otherwise * returns null. */ export function GetComment(q) { if (Comment.some(c => c.equals(q.predicate))) { if (q.object.termType === 'Literal') return { comment: q.object.value }; throw new Error(`Unexpected Comment predicate with non-string object: ${debugStr(q)}.`); } return null; } /** * If an ObjectPredicate represents a subClass relation, returns the parent * class. Otherwise returns null. */ export function GetSubClassOf(q) { if (SubClassOf.some(s => s.equals(q.predicate))) { if (q.object.termType !== 'NamedNode') { throw new Error(`Unexpected object for predicate 'subClassOf': ${debugStr(q)}`); } return { subClassOf: q.object }; } return null; } /** Return true iff this object is a subclass of some other entity. */ export function IsSubclass(topic) { return topic.quads.some(q => SubClassOf.some(s => s.equals(q.predicate))); } /** Returns true iff a node corresponds to http://schema.org/DataType */ export function IsDataType(t) { return DataType.some(d => d.equals(t)); } /** Returns true iff a Topic represents a DataType. */ export function ClassIsDataType(topic) { if (topic.types.some(IsDataType)) return true; return false; } /** * Returns true iff a Topic represents a named class. * * Note that some schemas define subclasses without explicitly redefining them * as classes. So just because a topic isn't directly named as a class doesn't * mean that it isn't a named class. * * A named class is such if it *OR ANY OF ITS PARENTS* are directly named * classes. */ export function IsDirectlyNamedClass(topic) { // Skip anything that isn't a class. return topic.types.some(IsClassType); } /** * Returns true iff a Predicate corresponds to http://schema.org/domainIncludes */ export function IsDomainIncludes(value) { return DomainIncludes.some(d => d.equals(value)); } /** * Returns true iff a Predicate corresponds to http://schema.org/rangeIncludes */ export function IsRangeIncludes(value) { return RangeIncludes.some(r => r.equals(value)); } /** * Returns true iff a Predicate corresponds to http://schema.org/supersededBy. */ export function IsSupersededBy(value) { return SupersededBy.some(s => s.equals(value)); } /** * Returns true iff a Predicate corresponds to * http://www.w3.org/1999/02/22-rdf-syntax-ns#type. */ export function IsType(predicate) { return predicate.equals(Type); } /** Returns iff an Object can be described as a Type Name. */ export function IsTypeName(value) { return value.termType === 'NamedNode'; } /** * If an ObjectPredicate corresponds to a * http://www.w3.org/1999/02/22-rdf-syntax-ns#type, returns a Type it describes. */ export function GetType(value) { if (IsType(value.predicate)) { if (!IsTypeName(value.object)) { throw new Error(`Unexpected type ${debugStr(value)}`); } return value.object; } return null; } /** * Returns all Nodes described by a Topic's * http://www.w3.org/1999/02/22-rdf-syntax-ns#type predicates. */ export function GetTypes(values) { const types = values.map(GetType).filter((t) => !!t); // Allow empty types. Some custom schema assume "transitive" typing, e.g. // gs1 has a TypeCode class which is an rdfs:Class, but its subclasses are // not explicitly described as an rdfs:Class. return types; } /** * Returns true iff a Type corresponds to * http://www.w3.org/2000/01/rdf-schema#Class */ export function IsClassType(type) { return Class.equals(type); } /** * Returns true iff a Type corresponds to * http://www.w3.org/1999/02/22-rdf-syntax-ns#Property */ export function IsPropertyType(type) { return Property.equals(type); } /** * Returns true iff a Subject has a Type indicating it is an Enum value. * * Enum Values have, in addition to other Data or Class types, another object as * its "Type". */ export function HasEnumType(types) { for (const type of types) { // Skip well-known types. if (IsClassType(type) || IsPropertyType(type) || IsDataType(type)) continue; // Skip OWL "meta" types if (OWLClass.some(c => c.equals(type))) continue; if (OWLProperty.some(c => c.equals(type))) continue; if (OWLOntology.some(c => c.equals(type))) continue; // If we're here, this is a 'Type' that is not well known. return true; } // Types are only well-known. return false; } //# sourceMappingURL=wellKnown.js.map