@google-cloud/kcmd 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +203 -0
- package/README.md +266 -2
- package/build/ts/kcmd/cli.js +19578 -0
- package/build/ts/kcmd/gcp/alloydb.d.ts +12 -0
- package/build/ts/kcmd/gcp/alloydb.js +70 -0
- package/build/ts/kcmd/gcp/api.d.ts +29 -0
- package/build/ts/kcmd/gcp/api.js +162 -0
- package/build/ts/kcmd/gcp/biglake.d.ts +16 -0
- package/build/ts/kcmd/gcp/biglake.js +50 -0
- package/build/ts/kcmd/gcp/bigquery.d.ts +57 -0
- package/build/ts/kcmd/gcp/bigquery.js +134 -0
- package/build/ts/kcmd/gcp/context.d.ts +10 -0
- package/build/ts/kcmd/gcp/context.js +74 -0
- package/build/ts/kcmd/gcp/crm.d.ts +13 -0
- package/build/ts/kcmd/gcp/crm.js +91 -0
- package/build/ts/kcmd/gcp/dataplex.d.ts +147 -0
- package/build/ts/kcmd/gcp/dataplex.js +406 -0
- package/build/ts/kcmd/gcp/index.d.ts +3 -0
- package/build/ts/kcmd/gcp/index.js +21 -0
- package/build/ts/kcmd/gcp/spanner.d.ts +63 -0
- package/build/ts/kcmd/gcp/spanner.js +123 -0
- package/build/ts/kcmd/index.d.ts +7 -0
- package/build/ts/kcmd/index.js +46 -0
- package/build/ts/kcmd/layout.d.ts +16 -0
- package/build/ts/kcmd/layout.js +31 -0
- package/build/ts/kcmd/layouts/documents.d.ts +24 -0
- package/build/ts/kcmd/layouts/documents.js +264 -0
- package/build/ts/kcmd/layouts/okf.d.ts +31 -0
- package/build/ts/kcmd/layouts/okf.js +344 -0
- package/build/ts/kcmd/layouts/semantic-model.d.ts +61 -0
- package/build/ts/kcmd/layouts/semantic-model.js +542 -0
- package/build/ts/kcmd/layouts/standard.d.ts +13 -0
- package/build/ts/kcmd/layouts/standard.js +108 -0
- package/build/ts/kcmd/manifest.d.ts +34 -0
- package/build/ts/kcmd/manifest.js +262 -0
- package/build/ts/kcmd/metadata.d.ts +25 -0
- package/build/ts/kcmd/metadata.js +8 -0
- package/build/ts/kcmd/okf/catalog_residue.d.ts +14 -0
- package/build/ts/kcmd/okf/catalog_residue.js +124 -0
- package/build/ts/kcmd/okf/concept.d.ts +14 -0
- package/build/ts/kcmd/okf/concept.js +104 -0
- package/build/ts/kcmd/okf/concept_to_entry.d.ts +8 -0
- package/build/ts/kcmd/okf/concept_to_entry.js +254 -0
- package/build/ts/kcmd/okf/init_okf_workspace.d.ts +15 -0
- package/build/ts/kcmd/okf/init_okf_workspace.js +115 -0
- package/build/ts/kcmd/okf/links.d.ts +23 -0
- package/build/ts/kcmd/okf/links.js +468 -0
- package/build/ts/kcmd/okf/okf_metadata.d.ts +12 -0
- package/build/ts/kcmd/okf/okf_metadata.js +82 -0
- package/build/ts/kcmd/semantic/bigquery.d.ts +22 -0
- package/build/ts/kcmd/semantic/bigquery.js +525 -0
- package/build/ts/kcmd/semantic/binding.d.ts +3 -0
- package/build/ts/kcmd/semantic/binding.js +97 -0
- package/build/ts/kcmd/semantic/catalog_entry.d.ts +24 -0
- package/build/ts/kcmd/semantic/catalog_entry.js +35 -0
- package/build/ts/kcmd/semantic/converters/owl/convert.d.ts +26 -0
- package/build/ts/kcmd/semantic/converters/owl/convert.js +41 -0
- package/build/ts/kcmd/semantic/converters/owl/model.d.ts +98 -0
- package/build/ts/kcmd/semantic/converters/owl/model.js +30 -0
- package/build/ts/kcmd/semantic/converters/owl/parse.d.ts +11 -0
- package/build/ts/kcmd/semantic/converters/owl/parse.js +634 -0
- package/build/ts/kcmd/semantic/converters/owl/to_ir.d.ts +19 -0
- package/build/ts/kcmd/semantic/converters/owl/to_ir.js +390 -0
- package/build/ts/kcmd/semantic/deploy_bigquery.d.ts +20 -0
- package/build/ts/kcmd/semantic/deploy_bigquery.js +226 -0
- package/build/ts/kcmd/semantic/deploy_knowledge_catalog.d.ts +129 -0
- package/build/ts/kcmd/semantic/deploy_knowledge_catalog.js +1396 -0
- package/build/ts/kcmd/semantic/deploy_spanner.d.ts +15 -0
- package/build/ts/kcmd/semantic/deploy_spanner.js +150 -0
- package/build/ts/kcmd/semantic/deployment_target.d.ts +93 -0
- package/build/ts/kcmd/semantic/deployment_target.js +379 -0
- package/build/ts/kcmd/semantic/graph_ddl.d.ts +34 -0
- package/build/ts/kcmd/semantic/graph_ddl.js +563 -0
- package/build/ts/kcmd/semantic/import_model.d.ts +50 -0
- package/build/ts/kcmd/semantic/import_model.js +1275 -0
- package/build/ts/kcmd/semantic/ir.d.ts +589 -0
- package/build/ts/kcmd/semantic/ir.js +247 -0
- package/build/ts/kcmd/semantic/kc_actions.d.ts +45 -0
- package/build/ts/kcmd/semantic/kc_actions.js +531 -0
- package/build/ts/kcmd/semantic/kc_constraints.d.ts +44 -0
- package/build/ts/kcmd/semantic/kc_constraints.js +279 -0
- package/build/ts/kcmd/semantic/kc_converter.d.ts +31 -0
- package/build/ts/kcmd/semantic/kc_converter.js +824 -0
- package/build/ts/kcmd/semantic/kc_custom_types.d.ts +70 -0
- package/build/ts/kcmd/semantic/kc_custom_types.js +828 -0
- package/build/ts/kcmd/semantic/kc_entries.d.ts +155 -0
- package/build/ts/kcmd/semantic/kc_entries.js +284 -0
- package/build/ts/kcmd/semantic/kc_ids.d.ts +103 -0
- package/build/ts/kcmd/semantic/kc_ids.js +191 -0
- package/build/ts/kcmd/semantic/knowledge_catalog.d.ts +32 -0
- package/build/ts/kcmd/semantic/knowledge_catalog.js +1043 -0
- package/build/ts/kcmd/semantic/loader.d.ts +262 -0
- package/build/ts/kcmd/semantic/loader.js +3440 -0
- package/build/ts/kcmd/semantic/names.d.ts +10 -0
- package/build/ts/kcmd/semantic/names.js +85 -0
- package/build/ts/kcmd/semantic/osi_converter.d.ts +60 -0
- package/build/ts/kcmd/semantic/osi_converter.js +911 -0
- package/build/ts/kcmd/semantic/parameters.d.ts +18 -0
- package/build/ts/kcmd/semantic/parameters.js +152 -0
- package/build/ts/kcmd/semantic/pull_kc.d.ts +14 -0
- package/build/ts/kcmd/semantic/pull_kc.js +346 -0
- package/build/ts/kcmd/semantic/resolve_inheritance.d.ts +54 -0
- package/build/ts/kcmd/semantic/resolve_inheritance.js +330 -0
- package/build/ts/kcmd/semantic/resolve_profiles.d.ts +250 -0
- package/build/ts/kcmd/semantic/resolve_profiles.js +1822 -0
- package/build/ts/kcmd/semantic/runtime/agent_tools.d.ts +93 -0
- package/build/ts/kcmd/semantic/runtime/agent_tools.js +243 -0
- package/build/ts/kcmd/semantic/runtime/dialect.d.ts +13 -0
- package/build/ts/kcmd/semantic/runtime/dialect.js +39 -0
- package/build/ts/kcmd/semantic/runtime/runtime.d.ts +94 -0
- package/build/ts/kcmd/semantic/runtime/runtime.js +318 -0
- package/build/ts/kcmd/semantic/runtime/store.d.ts +112 -0
- package/build/ts/kcmd/semantic/runtime/store.js +344 -0
- package/build/ts/kcmd/semantic/skills.d.ts +110 -0
- package/build/ts/kcmd/semantic/skills.js +697 -0
- package/build/ts/kcmd/semantic/source_dialect.d.ts +10 -0
- package/build/ts/kcmd/semantic/source_dialect.js +261 -0
- package/build/ts/kcmd/semantic/source_entries.d.ts +12 -0
- package/build/ts/kcmd/semantic/source_entries.js +282 -0
- package/build/ts/kcmd/semantic/spanner.d.ts +18 -0
- package/build/ts/kcmd/semantic/spanner.js +60 -0
- package/build/ts/kcmd/semantic/sql_expr_utils.d.ts +17 -0
- package/build/ts/kcmd/semantic/sql_expr_utils.js +221 -0
- package/build/ts/kcmd/semantic/sql_identifiers.d.ts +6 -0
- package/build/ts/kcmd/semantic/sql_identifiers.js +267 -0
- package/build/ts/kcmd/semantic/sql_parser.d.ts +44 -0
- package/build/ts/kcmd/semantic/sql_parser.js +378 -0
- package/build/ts/kcmd/semantic/transpile.d.ts +74 -0
- package/build/ts/kcmd/semantic/transpile.js +563 -0
- package/build/ts/kcmd/semantic/validate.d.ts +35 -0
- package/build/ts/kcmd/semantic/validate.js +1899 -0
- package/build/ts/kcmd/semantic/yaml_options.d.ts +6 -0
- package/build/ts/kcmd/semantic/yaml_options.js +58 -0
- package/build/ts/kcmd/semantic/yaml_update.d.ts +26 -0
- package/build/ts/kcmd/semantic/yaml_update.js +782 -0
- package/build/ts/kcmd/snapshot.d.ts +33 -0
- package/build/ts/kcmd/snapshot.js +379 -0
- package/build/ts/kcmd/source.d.ts +31 -0
- package/build/ts/kcmd/source.js +119 -0
- package/build/ts/kcmd/sources/bq-dataset.d.ts +17 -0
- package/build/ts/kcmd/sources/bq-dataset.js +131 -0
- package/build/ts/kcmd/sources/entrygroup.d.ts +21 -0
- package/build/ts/kcmd/sources/entrygroup.js +83 -0
- package/build/ts/kcmd/sources/kb.d.ts +21 -0
- package/build/ts/kcmd/sources/kb.js +82 -0
- package/build/ts/kcmd/sources/semantic-model.d.ts +18 -0
- package/build/ts/kcmd/sources/semantic-model.js +48 -0
- package/build/ts/kcmd/sync.d.ts +35 -0
- package/build/ts/kcmd/sync.js +697 -0
- package/package.json +62 -4
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Turtle (.ttl) -> OwlModel parser.
|
|
3
|
+
//
|
|
4
|
+
// A mechanical triples-to-structs step: it reads RDF with `n3`, recognizes the
|
|
5
|
+
// OWL/RDFS/SKOS/Dublin-Core terms the converter supports, and fills the staging
|
|
6
|
+
// OwlModel (model.ts). All OWL -> OSI mapping policy lives in to_ir.ts, not
|
|
7
|
+
// here; this file only decides "which triples matter and where do their values
|
|
8
|
+
// go".
|
|
9
|
+
//
|
|
10
|
+
// Declaration order is preserved: classes and properties appear in the order
|
|
11
|
+
// their `rdf:type` triple is first seen in the document, so the generated OSI
|
|
12
|
+
// is stable across runs (and matches its golden).
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.localName = localName;
|
|
15
|
+
exports.namespace = namespace;
|
|
16
|
+
exports.parseOwl = parseOwl;
|
|
17
|
+
const n3_1 = require("n3");
|
|
18
|
+
// RDF/RDFS/OWL/SKOS/Dublin-Core term IRIs we recognize. Only these; anything
|
|
19
|
+
// else is carried by neither the parser nor the model (see the user guide's
|
|
20
|
+
// "not covered yet").
|
|
21
|
+
const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
22
|
+
const RDFS = 'http://www.w3.org/2000/01/rdf-schema#';
|
|
23
|
+
const OWL = 'http://www.w3.org/2002/07/owl#';
|
|
24
|
+
const SKOS = 'http://www.w3.org/2004/02/skos/core#';
|
|
25
|
+
const DCTERMS = 'http://purl.org/dc/terms/';
|
|
26
|
+
const DC = 'http://purl.org/dc/elements/1.1/';
|
|
27
|
+
const XSD = 'http://www.w3.org/2001/XMLSchema#';
|
|
28
|
+
const XSD_BOOLEAN = `${XSD}boolean`;
|
|
29
|
+
const XSD_STRING = `${XSD}string`;
|
|
30
|
+
// The two lexical forms of xsd:boolean `true` (XSD admits both `true` and `1`);
|
|
31
|
+
// `false`/`0` restate the default and are not carried (see the OWL_DEPRECATED
|
|
32
|
+
// case).
|
|
33
|
+
const XSD_BOOLEAN_TRUE = new Set(['true', '1']);
|
|
34
|
+
const RDF_TYPE = `${RDF}type`;
|
|
35
|
+
// RDF collection (list) terms, used to walk an owl:hasKey list.
|
|
36
|
+
const RDF_FIRST = `${RDF}first`;
|
|
37
|
+
const RDF_REST = `${RDF}rest`;
|
|
38
|
+
const RDF_NIL = `${RDF}nil`;
|
|
39
|
+
const OWL_CLASS = `${OWL}Class`;
|
|
40
|
+
const OWL_DATATYPE_PROPERTY = `${OWL}DatatypeProperty`;
|
|
41
|
+
const OWL_OBJECT_PROPERTY = `${OWL}ObjectProperty`;
|
|
42
|
+
const OWL_INVERSE_FUNCTIONAL_PROPERTY = `${OWL}InverseFunctionalProperty`;
|
|
43
|
+
// Property characteristics carried verbatim (no native OSI home). Recognized by
|
|
44
|
+
// their rdf:type, like owl:InverseFunctionalProperty, and collected as
|
|
45
|
+
// typed-subject sets.
|
|
46
|
+
const OWL_SYMMETRIC_PROPERTY = `${OWL}SymmetricProperty`;
|
|
47
|
+
const OWL_TRANSITIVE_PROPERTY = `${OWL}TransitiveProperty`;
|
|
48
|
+
const OWL_FUNCTIONAL_PROPERTY = `${OWL}FunctionalProperty`;
|
|
49
|
+
const OWL_REFLEXIVE_PROPERTY = `${OWL}ReflexiveProperty`;
|
|
50
|
+
const OWL_IRREFLEXIVE_PROPERTY = `${OWL}IrreflexiveProperty`;
|
|
51
|
+
const OWL_ASYMMETRIC_PROPERTY = `${OWL}AsymmetricProperty`;
|
|
52
|
+
const OWL_ONTOLOGY = `${OWL}Ontology`;
|
|
53
|
+
const OWL_HAS_KEY = `${OWL}hasKey`;
|
|
54
|
+
// List-valued constructs whose object is an RDF collection head (a blank node),
|
|
55
|
+
// resolved with the same list walker as owl:hasKey. owl:oneOf enumerates a
|
|
56
|
+
// class's members; owl:propertyChainAxiom composes a property from a sequence
|
|
57
|
+
// of others. Both are carried verbatim (no native OSI home).
|
|
58
|
+
const OWL_ONE_OF = `${OWL}oneOf`;
|
|
59
|
+
const OWL_PROPERTY_CHAIN_AXIOM = `${OWL}propertyChainAxiom`;
|
|
60
|
+
const OWL_INVERSE_OF = `${OWL}inverseOf`;
|
|
61
|
+
const OWL_EQUIVALENT_PROPERTY = `${OWL}equivalentProperty`;
|
|
62
|
+
const OWL_PROPERTY_DISJOINT_WITH = `${OWL}propertyDisjointWith`;
|
|
63
|
+
const OWL_DISJOINT_WITH = `${OWL}disjointWith`;
|
|
64
|
+
const OWL_DEPRECATED = `${OWL}deprecated`;
|
|
65
|
+
const OWL_VERSION_INFO = `${OWL}versionInfo`;
|
|
66
|
+
const OWL_THING = `${OWL}Thing`;
|
|
67
|
+
// Set-level axioms. Each is asserted on an ANONYMOUS node (not a named term)
|
|
68
|
+
// typed with one of these, whose `owl:members` list names the set the axiom
|
|
69
|
+
// constrains. owl:AllDifferent also accepts the legacy OWL 1
|
|
70
|
+
// `owl:distinctMembers` spelling. Carried verbatim at the model level (no
|
|
71
|
+
// native OSI home).
|
|
72
|
+
const OWL_ALL_DISJOINT_CLASSES = `${OWL}AllDisjointClasses`;
|
|
73
|
+
const OWL_ALL_DISJOINT_PROPERTIES = `${OWL}AllDisjointProperties`;
|
|
74
|
+
const OWL_ALL_DIFFERENT = `${OWL}AllDifferent`;
|
|
75
|
+
const OWL_MEMBERS = `${OWL}members`;
|
|
76
|
+
const OWL_DISTINCT_MEMBERS = `${OWL}distinctMembers`;
|
|
77
|
+
const RDFS_LABEL = `${RDFS}label`;
|
|
78
|
+
const RDFS_COMMENT = `${RDFS}comment`;
|
|
79
|
+
const RDFS_DOMAIN = `${RDFS}domain`;
|
|
80
|
+
const RDFS_RANGE = `${RDFS}range`;
|
|
81
|
+
const RDFS_SUBCLASS_OF = `${RDFS}subClassOf`;
|
|
82
|
+
const RDFS_SUBPROPERTY_OF = `${RDFS}subPropertyOf`;
|
|
83
|
+
const RDFS_SEE_ALSO = `${RDFS}seeAlso`;
|
|
84
|
+
const RDFS_IS_DEFINED_BY = `${RDFS}isDefinedBy`;
|
|
85
|
+
const OWL_EQUIVALENT_CLASS = `${OWL}equivalentClass`;
|
|
86
|
+
const RDFS_RESOURCE = `${RDFS}Resource`;
|
|
87
|
+
// The implicit universal superclasses: every class is trivially a subclass of
|
|
88
|
+
// owl:Thing / rdfs:Resource, so an explicit `rdfs:subClassOf` naming one
|
|
89
|
+
// carries no inheritance information and is not recorded as `extends` (nor
|
|
90
|
+
// warned about).
|
|
91
|
+
const TOP_CLASS_IRIS = new Set([OWL_THING, RDFS_RESOURCE]);
|
|
92
|
+
const SKOS_ALT_LABEL = `${SKOS}altLabel`;
|
|
93
|
+
const SKOS_PREF_LABEL = `${SKOS}prefLabel`;
|
|
94
|
+
const SKOS_HIDDEN_LABEL = `${SKOS}hiddenLabel`;
|
|
95
|
+
const SKOS_DEFINITION = `${SKOS}definition`;
|
|
96
|
+
const SKOS_EXAMPLE = `${SKOS}example`;
|
|
97
|
+
const DCTERMS_DESCRIPTION = `${DCTERMS}description`;
|
|
98
|
+
const DC_DESCRIPTION = `${DC}description`;
|
|
99
|
+
const KIND_BY_TYPE = {
|
|
100
|
+
[OWL_CLASS]: 'class',
|
|
101
|
+
[OWL_DATATYPE_PROPERTY]: 'datatypeProperty',
|
|
102
|
+
[OWL_OBJECT_PROPERTY]: 'objectProperty',
|
|
103
|
+
};
|
|
104
|
+
// The namespace-stripped local name of a term IRI: the part after the last `#`
|
|
105
|
+
// or `/`. This is the OSI-facing identity of an in-namespace term (e.g. an
|
|
106
|
+
// entity/field name); the mapper also uses it to shorten a carried in-namespace
|
|
107
|
+
// cross-reference (see to_ir.refValue). Exported for that mapper use.
|
|
108
|
+
function localName(iri) {
|
|
109
|
+
const cut = Math.max(iri.lastIndexOf('#'), iri.lastIndexOf('/'));
|
|
110
|
+
return cut >= 0 ? iri.slice(cut + 1) : iri;
|
|
111
|
+
}
|
|
112
|
+
// The namespace portion of a term IRI (everything up to and including the last
|
|
113
|
+
// `#`/`/`); the ontology's base IRI for provenance, and the key the mapper
|
|
114
|
+
// compares against to decide whether a cross-reference is in-namespace (see
|
|
115
|
+
// to_ir.refValue). Exported for that mapper use.
|
|
116
|
+
function namespace(iri) {
|
|
117
|
+
const cut = Math.max(iri.lastIndexOf('#'), iri.lastIndexOf('/'));
|
|
118
|
+
return cut >= 0 ? iri.slice(0, cut + 1) : undefined;
|
|
119
|
+
}
|
|
120
|
+
// Renders a literal term in the N-Triples form used to carry an rdfs:seeAlso
|
|
121
|
+
// literal (see the RDFS_SEE_ALSO case): the lexical value wrapped in double
|
|
122
|
+
// quotes, followed by an optional `@lang` language tag or `^^<datatype>` type
|
|
123
|
+
// IRI so a language-tagged or typed literal round-trips rather than collapsing
|
|
124
|
+
// to a bare string. A plain xsd:string carries no suffix (it is the implicit
|
|
125
|
+
// default). Backslash and double quote in the value are escaped, the two
|
|
126
|
+
// characters that would otherwise break the wrapping. Reversed by parsing the
|
|
127
|
+
// N-Triples literal grammar.
|
|
128
|
+
function ntriplesLiteral(value, language, datatype) {
|
|
129
|
+
const quoted = `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
130
|
+
if (language)
|
|
131
|
+
return `${quoted}@${language}`;
|
|
132
|
+
if (datatype && datatype !== XSD_STRING)
|
|
133
|
+
return `${quoted}^^<${datatype}>`;
|
|
134
|
+
return quoted;
|
|
135
|
+
}
|
|
136
|
+
// The most common namespace among a set of term IRIs -- the ontology's own
|
|
137
|
+
// namespace. A tie (or a single term) resolves to the first in document order,
|
|
138
|
+
// since `best` is only replaced on a STRICTLY greater count. Returns undefined
|
|
139
|
+
// for an empty set (a document with no typed terms). Delimiter-exact, unlike
|
|
140
|
+
// deriving the base from the ontology IRI (which often omits the trailing
|
|
141
|
+
// `#`/`/`).
|
|
142
|
+
function dominantNamespace(iris) {
|
|
143
|
+
const counts = new Map();
|
|
144
|
+
let best;
|
|
145
|
+
let bestCount = 0;
|
|
146
|
+
for (const iri of iris) {
|
|
147
|
+
const ns = namespace(iri);
|
|
148
|
+
if (ns === undefined)
|
|
149
|
+
continue;
|
|
150
|
+
const n = (counts.get(ns) ?? 0) + 1;
|
|
151
|
+
counts.set(ns, n);
|
|
152
|
+
if (n > bestCount) {
|
|
153
|
+
bestCount = n;
|
|
154
|
+
best = ns;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return best;
|
|
158
|
+
}
|
|
159
|
+
function emptyAnnotations() {
|
|
160
|
+
return {
|
|
161
|
+
synonyms: [],
|
|
162
|
+
examples: [],
|
|
163
|
+
domains: [],
|
|
164
|
+
ranges: [],
|
|
165
|
+
keyListHeads: [],
|
|
166
|
+
oneOfListHeads: [],
|
|
167
|
+
chainListHeads: [],
|
|
168
|
+
subClassOf: [],
|
|
169
|
+
subPropertyOf: [],
|
|
170
|
+
equivalentClass: [],
|
|
171
|
+
inverseOf: [],
|
|
172
|
+
disjointWith: [],
|
|
173
|
+
equivalentProperty: [],
|
|
174
|
+
propertyDisjointWith: [],
|
|
175
|
+
seeAlso: [],
|
|
176
|
+
isDefinedBy: [],
|
|
177
|
+
deprecated: false
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
// The effective description: the first present of rdfs:comment,
|
|
181
|
+
// skos:definition, dcterms:description, dc:description -- a fixed precedence so
|
|
182
|
+
// a term with more than one carries the most specific.
|
|
183
|
+
function descriptionOf(a) {
|
|
184
|
+
return a.rdfsComment ?? a.skosDefinition ?? a.dctermsDescription ??
|
|
185
|
+
a.dcDescription;
|
|
186
|
+
}
|
|
187
|
+
// The per-term carried annotations (rdfs:seeAlso / isDefinedBy, owl:deprecated
|
|
188
|
+
// / versionInfo), shared by classes and both property kinds, projected from the
|
|
189
|
+
// accumulator into the model's common-annotation shape.
|
|
190
|
+
function commonAnnotations(a) {
|
|
191
|
+
return {
|
|
192
|
+
seeAlso: a.seeAlso,
|
|
193
|
+
isDefinedBy: a.isDefinedBy,
|
|
194
|
+
deprecated: a.deprecated,
|
|
195
|
+
versionInfo: a.versionInfo,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Parses a Turtle document into an OwlModel.
|
|
200
|
+
*
|
|
201
|
+
* Synchronous: `n3`'s Parser returns the full quad array when called without a
|
|
202
|
+
* callback, which suits a one-shot file import. Throws on malformed Turtle (the
|
|
203
|
+
* parser's own error), which the CLI surfaces.
|
|
204
|
+
*/
|
|
205
|
+
function parseOwl(turtle) {
|
|
206
|
+
const quads = new n3_1.Parser().parse(turtle);
|
|
207
|
+
// Pass 1: types. An ordered list of typed subjects (first `rdf:type`
|
|
208
|
+
// occurrence wins the position) plus a kind index; the set of
|
|
209
|
+
// inverse-functional subjects and the ontology-header subject, which are
|
|
210
|
+
// recognized by their type but are not themselves classes/properties.
|
|
211
|
+
// Scanning `quads` directly (not the Store) keeps document order.
|
|
212
|
+
const order = [];
|
|
213
|
+
const kind = new Map();
|
|
214
|
+
const inverseFunctional = new Set();
|
|
215
|
+
// Property characteristics carried verbatim, each a set of the subjects typed
|
|
216
|
+
// with it. A property is commonly typed with several types (e.g.
|
|
217
|
+
// `a owl:ObjectProperty, owl:SymmetricProperty`), so a characteristic type is
|
|
218
|
+
// recorded here and does not compete with the kind that routes it to a
|
|
219
|
+
// class/property.
|
|
220
|
+
const symmetric = new Set();
|
|
221
|
+
const transitive = new Set();
|
|
222
|
+
const functional = new Set();
|
|
223
|
+
const reflexive = new Set();
|
|
224
|
+
const irreflexive = new Set();
|
|
225
|
+
const asymmetric = new Set();
|
|
226
|
+
// Anonymous set-level-axiom nodes, in document order, deduped by node id
|
|
227
|
+
// within each kind (a duplicate type triple must not list the node twice). A
|
|
228
|
+
// node typed as two different kinds -- legal, if unusual, RDF -- is recorded
|
|
229
|
+
// under each, so the dedup is per-kind rather than one shared seen-set. Their
|
|
230
|
+
// `owl:members` list is resolved after the list structure is known.
|
|
231
|
+
const allDisjointClassesNodes = [];
|
|
232
|
+
const allDisjointPropertiesNodes = [];
|
|
233
|
+
const allDifferentNodes = [];
|
|
234
|
+
const seenDisjointClasses = new Set();
|
|
235
|
+
const seenDisjointProperties = new Set();
|
|
236
|
+
const seenDifferent = new Set();
|
|
237
|
+
let ontologyIri;
|
|
238
|
+
for (const q of quads) {
|
|
239
|
+
if (q.predicate.value !== RDF_TYPE)
|
|
240
|
+
continue;
|
|
241
|
+
const type = q.object.value;
|
|
242
|
+
const subject = q.subject.value;
|
|
243
|
+
if (type === OWL_INVERSE_FUNCTIONAL_PROPERTY) {
|
|
244
|
+
inverseFunctional.add(subject);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (type === OWL_SYMMETRIC_PROPERTY) {
|
|
248
|
+
symmetric.add(subject);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (type === OWL_TRANSITIVE_PROPERTY) {
|
|
252
|
+
transitive.add(subject);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (type === OWL_FUNCTIONAL_PROPERTY) {
|
|
256
|
+
functional.add(subject);
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (type === OWL_REFLEXIVE_PROPERTY) {
|
|
260
|
+
reflexive.add(subject);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (type === OWL_IRREFLEXIVE_PROPERTY) {
|
|
264
|
+
irreflexive.add(subject);
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (type === OWL_ASYMMETRIC_PROPERTY) {
|
|
268
|
+
asymmetric.add(subject);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (type === OWL_ONTOLOGY) {
|
|
272
|
+
if (ontologyIri === undefined)
|
|
273
|
+
ontologyIri = subject;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (type === OWL_ALL_DISJOINT_CLASSES) {
|
|
277
|
+
if (!seenDisjointClasses.has(subject)) {
|
|
278
|
+
seenDisjointClasses.add(subject);
|
|
279
|
+
allDisjointClassesNodes.push(subject);
|
|
280
|
+
}
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (type === OWL_ALL_DISJOINT_PROPERTIES) {
|
|
284
|
+
if (!seenDisjointProperties.has(subject)) {
|
|
285
|
+
seenDisjointProperties.add(subject);
|
|
286
|
+
allDisjointPropertiesNodes.push(subject);
|
|
287
|
+
}
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (type === OWL_ALL_DIFFERENT) {
|
|
291
|
+
if (!seenDifferent.has(subject)) {
|
|
292
|
+
seenDifferent.add(subject);
|
|
293
|
+
allDifferentNodes.push(subject);
|
|
294
|
+
}
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const k = KIND_BY_TYPE[type];
|
|
298
|
+
if (!k)
|
|
299
|
+
continue;
|
|
300
|
+
if (!kind.has(subject)) {
|
|
301
|
+
kind.set(subject, k);
|
|
302
|
+
order.push(subject);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
// Pass 2: RDF list structure (rdf:first / rdf:rest), so an owl:hasKey list
|
|
306
|
+
// can be resolved to its member properties. List nodes are blank nodes
|
|
307
|
+
// unrelated to the typed subjects, so they are collected separately.
|
|
308
|
+
const listFirst = new Map();
|
|
309
|
+
const listRest = new Map();
|
|
310
|
+
// The `owl:members` list head of each set-level-axiom node. owl:members (OWL
|
|
311
|
+
// 2) wins over the legacy owl:distinctMembers (OWL 1, owl:AllDifferent only)
|
|
312
|
+
// when a node carries both, regardless of the order the two triples appear.
|
|
313
|
+
// owl:distinctMembers is honored ONLY on an owl:AllDifferent node, matching
|
|
314
|
+
// the OWL spec (it has no meaning on the disjointness axioms), so a stray
|
|
315
|
+
// owl:distinctMembers on an owl:AllDisjoint* node is ignored rather than
|
|
316
|
+
// carried.
|
|
317
|
+
const membersHead = new Map();
|
|
318
|
+
for (const q of quads) {
|
|
319
|
+
if (q.predicate.value === RDF_FIRST)
|
|
320
|
+
listFirst.set(q.subject.value, q.object.value);
|
|
321
|
+
else if (q.predicate.value === RDF_REST)
|
|
322
|
+
listRest.set(q.subject.value, q.object.value);
|
|
323
|
+
else if (q.predicate.value === OWL_MEMBERS)
|
|
324
|
+
membersHead.set(q.subject.value, q.object.value);
|
|
325
|
+
else if (q.predicate.value === OWL_DISTINCT_MEMBERS &&
|
|
326
|
+
seenDifferent.has(q.subject.value) && !membersHead.has(q.subject.value))
|
|
327
|
+
membersHead.set(q.subject.value, q.object.value);
|
|
328
|
+
}
|
|
329
|
+
// Resolves an RDF collection to its member IRIs, following rdf:rest to nil.
|
|
330
|
+
// Defensive against a cycle or a missing link (stops at the first gap).
|
|
331
|
+
const resolveList = (head) => {
|
|
332
|
+
const out = [];
|
|
333
|
+
const seen = new Set();
|
|
334
|
+
let node = head;
|
|
335
|
+
while (node && node !== RDF_NIL && !seen.has(node)) {
|
|
336
|
+
seen.add(node);
|
|
337
|
+
const value = listFirst.get(node);
|
|
338
|
+
if (value === undefined)
|
|
339
|
+
break;
|
|
340
|
+
out.push(value);
|
|
341
|
+
node = listRest.get(node);
|
|
342
|
+
}
|
|
343
|
+
return out;
|
|
344
|
+
};
|
|
345
|
+
// Pass 3: accumulate annotations for each typed subject (and the ontology
|
|
346
|
+
// header) in document order, so the first label is the primary and the rest
|
|
347
|
+
// are synonyms.
|
|
348
|
+
const annotations = new Map();
|
|
349
|
+
const annotationsFor = (iri) => {
|
|
350
|
+
let a = annotations.get(iri);
|
|
351
|
+
if (!a) {
|
|
352
|
+
a = emptyAnnotations();
|
|
353
|
+
annotations.set(iri, a);
|
|
354
|
+
}
|
|
355
|
+
return a;
|
|
356
|
+
};
|
|
357
|
+
const annotated = (iri) => kind.has(iri) || iri === ontologyIri;
|
|
358
|
+
for (const q of quads) {
|
|
359
|
+
const subject = q.subject.value;
|
|
360
|
+
if (!annotated(subject))
|
|
361
|
+
continue;
|
|
362
|
+
const a = annotationsFor(subject);
|
|
363
|
+
switch (q.predicate.value) {
|
|
364
|
+
case RDFS_LABEL:
|
|
365
|
+
// First label -> the display label; any further label -> a synonym.
|
|
366
|
+
if (a.label === undefined)
|
|
367
|
+
a.label = q.object.value;
|
|
368
|
+
else
|
|
369
|
+
a.synonyms.push(q.object.value);
|
|
370
|
+
break;
|
|
371
|
+
case SKOS_ALT_LABEL:
|
|
372
|
+
case SKOS_PREF_LABEL:
|
|
373
|
+
case SKOS_HIDDEN_LABEL:
|
|
374
|
+
a.synonyms.push(q.object.value);
|
|
375
|
+
break;
|
|
376
|
+
case SKOS_EXAMPLE:
|
|
377
|
+
a.examples.push(q.object.value);
|
|
378
|
+
break;
|
|
379
|
+
case RDFS_COMMENT:
|
|
380
|
+
a.rdfsComment = q.object.value;
|
|
381
|
+
break;
|
|
382
|
+
case SKOS_DEFINITION:
|
|
383
|
+
a.skosDefinition = q.object.value;
|
|
384
|
+
break;
|
|
385
|
+
case DCTERMS_DESCRIPTION:
|
|
386
|
+
a.dctermsDescription = q.object.value;
|
|
387
|
+
break;
|
|
388
|
+
case DC_DESCRIPTION:
|
|
389
|
+
a.dcDescription = q.object.value;
|
|
390
|
+
break;
|
|
391
|
+
case RDFS_DOMAIN:
|
|
392
|
+
a.domains.push(localName(q.object.value));
|
|
393
|
+
break;
|
|
394
|
+
case RDFS_RANGE:
|
|
395
|
+
a.ranges.push(q.object.value); // kept as IRI; mapper maps xsd:*
|
|
396
|
+
break;
|
|
397
|
+
case OWL_VERSION_INFO:
|
|
398
|
+
a.versionInfo = q.object.value;
|
|
399
|
+
break;
|
|
400
|
+
case OWL_HAS_KEY:
|
|
401
|
+
a.keyListHeads.push(q.object.value);
|
|
402
|
+
break;
|
|
403
|
+
case OWL_ONE_OF:
|
|
404
|
+
// Enumerated class -> no native OSI home; carried verbatim. The object
|
|
405
|
+
// is an RDF collection head; the members (usually individuals) are
|
|
406
|
+
// resolved with the list walker at build time. This is recorded for any
|
|
407
|
+
// annotated subject, but only the class build reads it -- if the
|
|
408
|
+
// subject is typed a property instead, the heads are collected here and
|
|
409
|
+
// then dropped (an owl:oneOf on a property is not meaningful).
|
|
410
|
+
a.oneOfListHeads.push(q.object.value);
|
|
411
|
+
break;
|
|
412
|
+
case OWL_PROPERTY_CHAIN_AXIOM:
|
|
413
|
+
// Property chain -> no native OSI home; carried verbatim. The object is
|
|
414
|
+
// an RDF collection head naming the composed properties, in order.
|
|
415
|
+
a.chainListHeads.push(q.object.value);
|
|
416
|
+
break;
|
|
417
|
+
case RDFS_SUBCLASS_OF:
|
|
418
|
+
// Class hierarchy -> the entity's `extends`. Named superclasses only:
|
|
419
|
+
// a blank-node object (an owl:Restriction and similar axioms) is not a
|
|
420
|
+
// named class, so it is ignored here (out of scope). The implicit
|
|
421
|
+
// universal superclasses (owl:Thing / rdfs:Resource) are ignored too --
|
|
422
|
+
// every class subclasses them, so they carry no inheritance
|
|
423
|
+
// information.
|
|
424
|
+
if (q.object.termType === 'NamedNode' &&
|
|
425
|
+
!TOP_CLASS_IRIS.has(q.object.value))
|
|
426
|
+
a.subClassOf.push(localName(q.object.value));
|
|
427
|
+
break;
|
|
428
|
+
case RDFS_SUBPROPERTY_OF:
|
|
429
|
+
// Property hierarchy -> no native OSI home; carried verbatim by the
|
|
430
|
+
// mapper as a custom extension. Named superproperties only (a
|
|
431
|
+
// blank-node property expression is out of scope). The full IRI is
|
|
432
|
+
// kept; the mapper shortens an in-namespace one (see to_ir.refValue).
|
|
433
|
+
if (q.object.termType === 'NamedNode')
|
|
434
|
+
a.subPropertyOf.push(q.object.value);
|
|
435
|
+
break;
|
|
436
|
+
case OWL_EQUIVALENT_CLASS:
|
|
437
|
+
// Class equivalence -> no native OSI home; carried verbatim. Named
|
|
438
|
+
// classes only; a blank-node class expression (owl:intersectionOf, ...)
|
|
439
|
+
// is a class definition, not a plain cross-reference, so it is ignored
|
|
440
|
+
// (out of scope, like a blank-node subClassOf).
|
|
441
|
+
if (q.object.termType === 'NamedNode')
|
|
442
|
+
a.equivalentClass.push(q.object.value);
|
|
443
|
+
break;
|
|
444
|
+
case OWL_DISJOINT_WITH:
|
|
445
|
+
// Class disjointness -> no native OSI home; carried verbatim. Named
|
|
446
|
+
// classes only (a blank-node class expression is out of scope).
|
|
447
|
+
if (q.object.termType === 'NamedNode')
|
|
448
|
+
a.disjointWith.push(q.object.value);
|
|
449
|
+
break;
|
|
450
|
+
case OWL_INVERSE_OF:
|
|
451
|
+
// Inverse edge -> no native OSI home; carried verbatim. Named object
|
|
452
|
+
// properties only.
|
|
453
|
+
if (q.object.termType === 'NamedNode')
|
|
454
|
+
a.inverseOf.push(q.object.value);
|
|
455
|
+
break;
|
|
456
|
+
case OWL_EQUIVALENT_PROPERTY:
|
|
457
|
+
// Property equivalence -> no native OSI home; carried verbatim. Named
|
|
458
|
+
// properties only.
|
|
459
|
+
if (q.object.termType === 'NamedNode')
|
|
460
|
+
a.equivalentProperty.push(q.object.value);
|
|
461
|
+
break;
|
|
462
|
+
case OWL_PROPERTY_DISJOINT_WITH:
|
|
463
|
+
// Property disjointness -> no native OSI home; carried verbatim. Named
|
|
464
|
+
// properties only.
|
|
465
|
+
if (q.object.termType === 'NamedNode')
|
|
466
|
+
a.propertyDisjointWith.push(q.object.value);
|
|
467
|
+
break;
|
|
468
|
+
case RDFS_SEE_ALSO:
|
|
469
|
+
// A pointer to further information -> carried verbatim as an N-Triples
|
|
470
|
+
// object term, so an IRI stays distinguishable from a literal on
|
|
471
|
+
// round-trip: an IRI as `<iri>`, a literal as `"text"` with any
|
|
472
|
+
// language tag (`@en`) or datatype (`^^<iri>`) preserved (see
|
|
473
|
+
// ntriplesLiteral). seeAlso is the only carried slot that admits either
|
|
474
|
+
// kind; every other carries a bare IRI or local name. A blank node has
|
|
475
|
+
// no stable identity to carry, so it is skipped.
|
|
476
|
+
if (q.object.termType === 'NamedNode')
|
|
477
|
+
a.seeAlso.push(`<${q.object.value}>`);
|
|
478
|
+
else if (q.object.termType === 'Literal')
|
|
479
|
+
a.seeAlso.push(ntriplesLiteral(q.object.value, q.object.language, q.object.datatype?.value ?? ''));
|
|
480
|
+
break;
|
|
481
|
+
case RDFS_IS_DEFINED_BY:
|
|
482
|
+
// The resource (usually the defining ontology) that defines this term
|
|
483
|
+
// -> carried verbatim. Named resources only.
|
|
484
|
+
if (q.object.termType === 'NamedNode')
|
|
485
|
+
a.isDefinedBy.push(q.object.value);
|
|
486
|
+
break;
|
|
487
|
+
case OWL_DEPRECATED:
|
|
488
|
+
// Lifecycle flag -> carried only for an xsd:boolean literal that is
|
|
489
|
+
// `true`. That is the one meaningful assertion; an explicit `false`/`0`
|
|
490
|
+
// restates the default, and a non-boolean value (e.g. the string
|
|
491
|
+
// "true") is malformed -- neither is carried. Both XSD lexical forms of
|
|
492
|
+
// true (`true` and `1`) are accepted.
|
|
493
|
+
if (q.object.termType === 'Literal' &&
|
|
494
|
+
q.object.datatype?.value === XSD_BOOLEAN &&
|
|
495
|
+
XSD_BOOLEAN_TRUE.has(q.object.value))
|
|
496
|
+
a.deprecated = true;
|
|
497
|
+
break;
|
|
498
|
+
default:
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
const classes = [];
|
|
503
|
+
const datatypeProperties = [];
|
|
504
|
+
const objectProperties = [];
|
|
505
|
+
// The ontology's own namespace: the one shared by MOST of its typed terms.
|
|
506
|
+
// Taking the most common namespace (not merely the first typed term's) is
|
|
507
|
+
// robust to a document that also types a handful of foreign-namespace terms
|
|
508
|
+
// -- e.g. an imported class it annotates -- which would otherwise hijack the
|
|
509
|
+
// base if one happened to appear first and silently invert the mapper's
|
|
510
|
+
// in-namespace/cross-namespace shortening (see to_ir.refValue).
|
|
511
|
+
let baseIri = dominantNamespace(order);
|
|
512
|
+
for (const iri of order) {
|
|
513
|
+
const a = annotations.get(iri) ?? emptyAnnotations();
|
|
514
|
+
switch (kind.get(iri)) {
|
|
515
|
+
case 'class':
|
|
516
|
+
classes.push({
|
|
517
|
+
localName: localName(iri),
|
|
518
|
+
label: a.label,
|
|
519
|
+
comment: descriptionOf(a),
|
|
520
|
+
synonyms: a.synonyms,
|
|
521
|
+
examples: a.examples,
|
|
522
|
+
keys: a.keyListHeads.flatMap(resolveList).map(localName),
|
|
523
|
+
subClassOf: a.subClassOf,
|
|
524
|
+
equivalentClass: a.equivalentClass,
|
|
525
|
+
disjointWith: a.disjointWith,
|
|
526
|
+
// Full member IRIs of the enumeration set (a carried cross-reference;
|
|
527
|
+
// the mapper shortens an in-namespace one). flatMap unions the
|
|
528
|
+
// members across every oneOf head -- an enumeration is a set, so the
|
|
529
|
+
// mapper dedupes and order does not matter (contrast propertyChain).
|
|
530
|
+
oneOf: a.oneOfListHeads.flatMap(resolveList),
|
|
531
|
+
...commonAnnotations(a),
|
|
532
|
+
});
|
|
533
|
+
break;
|
|
534
|
+
case 'datatypeProperty':
|
|
535
|
+
datatypeProperties.push({
|
|
536
|
+
localName: localName(iri),
|
|
537
|
+
domains: a.domains,
|
|
538
|
+
rangeIri: a.ranges[0],
|
|
539
|
+
label: a.label,
|
|
540
|
+
comment: descriptionOf(a),
|
|
541
|
+
synonyms: a.synonyms,
|
|
542
|
+
examples: a.examples,
|
|
543
|
+
inverseFunctional: inverseFunctional.has(iri),
|
|
544
|
+
functional: functional.has(iri),
|
|
545
|
+
subPropertyOf: a.subPropertyOf,
|
|
546
|
+
equivalentProperty: a.equivalentProperty,
|
|
547
|
+
propertyDisjointWith: a.propertyDisjointWith,
|
|
548
|
+
...commonAnnotations(a),
|
|
549
|
+
});
|
|
550
|
+
break;
|
|
551
|
+
case 'objectProperty':
|
|
552
|
+
objectProperties.push({
|
|
553
|
+
localName: localName(iri),
|
|
554
|
+
// a.domains are already local names; a.ranges are raw IRIs. Carry all
|
|
555
|
+
// of each so the mapper can warn about (and drop) the extras rather
|
|
556
|
+
// than silently keeping only the first.
|
|
557
|
+
domains: a.domains,
|
|
558
|
+
ranges: a.ranges.map(localName),
|
|
559
|
+
label: a.label,
|
|
560
|
+
comment: descriptionOf(a),
|
|
561
|
+
synonyms: a.synonyms,
|
|
562
|
+
examples: a.examples,
|
|
563
|
+
subPropertyOf: a.subPropertyOf,
|
|
564
|
+
inverseOf: a.inverseOf,
|
|
565
|
+
equivalentProperty: a.equivalentProperty,
|
|
566
|
+
propertyDisjointWith: a.propertyDisjointWith,
|
|
567
|
+
// One resolved chain per owl:propertyChainAxiom (map, NOT flatMap):
|
|
568
|
+
// OWL 2 permits several chain axioms on one property, and fusing them
|
|
569
|
+
// would be indistinguishable from a single longer chain. Full
|
|
570
|
+
// property IRIs in chain order (the mapper shortens in-namespace
|
|
571
|
+
// ones); within a chain order and repetition are preserved, so no
|
|
572
|
+
// dedupe. An empty chain (a broken/gapped list) is dropped rather
|
|
573
|
+
// than carried as [].
|
|
574
|
+
propertyChain: a.chainListHeads.map(resolveList).filter(c => c.length),
|
|
575
|
+
symmetric: symmetric.has(iri),
|
|
576
|
+
transitive: transitive.has(iri),
|
|
577
|
+
functional: functional.has(iri),
|
|
578
|
+
reflexive: reflexive.has(iri),
|
|
579
|
+
irreflexive: irreflexive.has(iri),
|
|
580
|
+
asymmetric: asymmetric.has(iri),
|
|
581
|
+
...commonAnnotations(a),
|
|
582
|
+
});
|
|
583
|
+
break;
|
|
584
|
+
default:
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// The ontology header, if present, becomes model-level metadata. The base IRI
|
|
589
|
+
// is best derived from an actual term's namespace (exact, delimiter and all);
|
|
590
|
+
// the ontology IRI is only a heuristic fallback (its own IRI often omits the
|
|
591
|
+
// trailing `#`/`/`), so use it only when no term supplied a namespace.
|
|
592
|
+
let ontology;
|
|
593
|
+
if (ontologyIri !== undefined) {
|
|
594
|
+
const a = annotations.get(ontologyIri) ?? emptyAnnotations();
|
|
595
|
+
const labels = a.label !== undefined ? [a.label, ...a.synonyms] : a.synonyms;
|
|
596
|
+
ontology = {
|
|
597
|
+
comment: descriptionOf(a),
|
|
598
|
+
synonyms: labels,
|
|
599
|
+
examples: a.examples,
|
|
600
|
+
version: a.versionInfo,
|
|
601
|
+
};
|
|
602
|
+
baseIri = baseIri ?? ontologyBaseIri(ontologyIri);
|
|
603
|
+
}
|
|
604
|
+
// Resolve each set-level-axiom node's `owl:members` list to its member IRIs.
|
|
605
|
+
// A node with no members list, or one whose list is broken/empty, contributes
|
|
606
|
+
// nothing (an axiom over no members is meaningless). Member names are kept as
|
|
607
|
+
// full IRIs; the mapper shortens an in-namespace one.
|
|
608
|
+
const resolveMembers = (nodes) => nodes.map(n => membersHead.get(n))
|
|
609
|
+
.filter((h) => h !== undefined)
|
|
610
|
+
.map(resolveList)
|
|
611
|
+
.filter(members => members.length > 0);
|
|
612
|
+
return {
|
|
613
|
+
baseIri,
|
|
614
|
+
ontology,
|
|
615
|
+
classes,
|
|
616
|
+
datatypeProperties,
|
|
617
|
+
objectProperties,
|
|
618
|
+
allDisjointClasses: resolveMembers(allDisjointClassesNodes),
|
|
619
|
+
allDisjointProperties: resolveMembers(allDisjointPropertiesNodes),
|
|
620
|
+
allDifferent: resolveMembers(allDifferentNodes),
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
// The base namespace an ontology IRI stands for. An owl:Ontology is commonly
|
|
624
|
+
// named by the namespace root without the trailing `#`/`/` (e.g.
|
|
625
|
+
// `http://example.com/sales`), so append `#` when the IRI has no delimiter of
|
|
626
|
+
// its own; otherwise keep it as given.
|
|
627
|
+
function ontologyBaseIri(iri) {
|
|
628
|
+
if (!iri)
|
|
629
|
+
return undefined;
|
|
630
|
+
const last = iri[iri.length - 1];
|
|
631
|
+
if (last === '#' || last === '/')
|
|
632
|
+
return iri;
|
|
633
|
+
return `${iri}#`;
|
|
634
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SemanticModel } from '../../ir';
|
|
2
|
+
import { OwlModel } from './model';
|
|
3
|
+
export interface ToIrResult {
|
|
4
|
+
model: SemanticModel;
|
|
5
|
+
warnings: string[];
|
|
6
|
+
stats: {
|
|
7
|
+
classes: number;
|
|
8
|
+
datatypeProperties: number;
|
|
9
|
+
objectProperties: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Maps a parsed OwlModel to a Semantic Model IR (see ../../ir.ts).
|
|
14
|
+
*
|
|
15
|
+
* `modelName` names the resulting semantic model (the CLI derives it from the
|
|
16
|
+
* source filename). The IR it returns serializes, via osi_converter, to the
|
|
17
|
+
* OSI YAML shown in the user guide.
|
|
18
|
+
*/
|
|
19
|
+
export declare function owlToIr(owl: OwlModel, modelName: string): ToIrResult;
|