node-opcua-uanodeset-rdf 2.182.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/README.md +294 -0
- package/VOCABULARY.md +186 -0
- package/dist/address_space.d.ts +16 -0
- package/dist/address_space.js +30 -0
- package/dist/address_space.js.map +1 -0
- package/dist/from_address_space.d.ts +15 -0
- package/dist/from_address_space.js +110 -0
- package/dist/from_address_space.js.map +1 -0
- package/dist/from_session.d.ts +28 -0
- package/dist/from_session.js +293 -0
- package/dist/from_session.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/model.d.ts +79 -0
- package/dist/model.js +15 -0
- package/dist/model.js.map +1 -0
- package/dist/session.d.ts +27 -0
- package/dist/session.js +41 -0
- package/dist/session.js.map +1 -0
- package/dist/to_jsonld.d.ts +31 -0
- package/dist/to_jsonld.js +372 -0
- package/dist/to_jsonld.js.map +1 -0
- package/package.json +70 -0
- package/source/address_space.ts +25 -0
- package/source/from_address_space.ts +116 -0
- package/source/from_session.ts +327 -0
- package/source/index.ts +31 -0
- package/source/model.ts +88 -0
- package/source/session.ts +35 -0
- package/source/to_jsonld.ts +385 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collecting an `RdfModel` over a session.
|
|
3
|
+
*
|
|
4
|
+
* This is what makes a server exportable when its nodeset file is not available, which for a
|
|
5
|
+
* vendor's own companion specification is often the only way to get the model into a graph store
|
|
6
|
+
* at all.
|
|
7
|
+
*
|
|
8
|
+
* It is not the equal of `addressSpaceToRdfModel`, and the differences are not bugs to be fixed
|
|
9
|
+
* later. OPC UA has no service that lists the nodes of a namespace, so the model is whatever a
|
|
10
|
+
* crawl from Root reaches; `SymbolicName` is NodeSet2 metadata rather than an attribute, so it is
|
|
11
|
+
* simply gone; and `NamespaceMetadataType` carries no list of required models, so the ontology
|
|
12
|
+
* node has no `owl:imports` unless the caller supplies one. "What a session cannot tell you" in
|
|
13
|
+
* `VOCABULARY.md` is the full list.
|
|
14
|
+
*/
|
|
15
|
+
import { type IBasicSessionBrowseAsyncMultiple, type IBasicSessionBrowseNextAsyncMultiple, type IBasicSessionReadAsyncMultiple } from "node-opcua-pseudo-session";
|
|
16
|
+
import type { RdfModel } from "./model.js";
|
|
17
|
+
/**
|
|
18
|
+
* what collecting a model asks of a session, written out rather than named.
|
|
19
|
+
*
|
|
20
|
+
* Three services and no more: browse, follow the continuation point a browse hands back, and read
|
|
21
|
+
* attributes. Anything satisfying that will do, and both things that do are useful here: a
|
|
22
|
+
* `ClientSession` against a real server, and a `PseudoSession` over an address space. Spelling the
|
|
23
|
+
* intersection out is also what keeps `create`, `close`, subscriptions and the rest of a session's
|
|
24
|
+
* surface out of the contract, so a caller can pass something far smaller than a session.
|
|
25
|
+
*/
|
|
26
|
+
export type RdfSession = IBasicSessionBrowseAsyncMultiple & IBasicSessionBrowseNextAsyncMultiple & IBasicSessionReadAsyncMultiple;
|
|
27
|
+
/** the model a namespace of a server describes, as far as a session can see it */
|
|
28
|
+
export declare function sessionToRdfModel(session: RdfSession, modelUri?: string): Promise<RdfModel>;
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Collecting an `RdfModel` over a session.
|
|
4
|
+
*
|
|
5
|
+
* This is what makes a server exportable when its nodeset file is not available, which for a
|
|
6
|
+
* vendor's own companion specification is often the only way to get the model into a graph store
|
|
7
|
+
* at all.
|
|
8
|
+
*
|
|
9
|
+
* It is not the equal of `addressSpaceToRdfModel`, and the differences are not bugs to be fixed
|
|
10
|
+
* later. OPC UA has no service that lists the nodes of a namespace, so the model is whatever a
|
|
11
|
+
* crawl from Root reaches; `SymbolicName` is NodeSet2 metadata rather than an attribute, so it is
|
|
12
|
+
* simply gone; and `NamespaceMetadataType` carries no list of required models, so the ontology
|
|
13
|
+
* node has no `owl:imports` unless the caller supplies one. "What a session cannot tell you" in
|
|
14
|
+
* `VOCABULARY.md` is the full list.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.sessionToRdfModel = sessionToRdfModel;
|
|
18
|
+
const node_opcua_data_model_1 = require("node-opcua-data-model");
|
|
19
|
+
const node_opcua_nodeid_1 = require("node-opcua-nodeid");
|
|
20
|
+
const node_opcua_pseudo_session_1 = require("node-opcua-pseudo-session");
|
|
21
|
+
const node_opcua_service_browse_1 = require("node-opcua-service-browse");
|
|
22
|
+
/** `Root`, where a crawl has to start, since nothing lists the nodes of a namespace */
|
|
23
|
+
const ROOT = (0, node_opcua_nodeid_1.resolveNodeId)("RootFolder");
|
|
24
|
+
/** `Server_NamespaceArray` */
|
|
25
|
+
const NAMESPACE_ARRAY = (0, node_opcua_nodeid_1.resolveNodeId)("Server_NamespaceArray");
|
|
26
|
+
/** `Server_Namespaces`, the folder of `NamespaceMetadataType` objects */
|
|
27
|
+
const NAMESPACES_FOLDER = (0, node_opcua_nodeid_1.coerceNodeId)("i=11715");
|
|
28
|
+
/** `References`, so one browse per node covers every relation in both directions */
|
|
29
|
+
const REFERENCES = (0, node_opcua_nodeid_1.resolveNodeId)("References");
|
|
30
|
+
/** BrowseName, NodeClass and TypeDefinition of each target, which is all the mapper needs to name it */
|
|
31
|
+
const RESULT_MASK = 0x3f;
|
|
32
|
+
/**
|
|
33
|
+
* how many nodes to read attributes for at once.
|
|
34
|
+
*
|
|
35
|
+
* `browseAll` reads the server's own browse limits, but nothing here reads `MaxNodesPerRead`:
|
|
36
|
+
* honouring a server's operation limits belongs in a client that specialises in it, not in a
|
|
37
|
+
* bare exporter. This is a figure every server in practice accepts.
|
|
38
|
+
*/
|
|
39
|
+
const READ_CHUNK = 100;
|
|
40
|
+
function stubOf(reference) {
|
|
41
|
+
return {
|
|
42
|
+
nodeId: reference.nodeId,
|
|
43
|
+
nodeClass: reference.nodeClass,
|
|
44
|
+
browseName: reference.browseName,
|
|
45
|
+
references: []
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** the namespace array, which is the only thing that turns a uri into the index NodeIds use */
|
|
49
|
+
async function readNamespaceArray(session) {
|
|
50
|
+
const [dataValue] = await session.read([{ nodeId: NAMESPACE_ARRAY, attributeId: node_opcua_data_model_1.AttributeIds.Value }]);
|
|
51
|
+
const value = dataValue?.value?.value;
|
|
52
|
+
if (!value?.length) {
|
|
53
|
+
throw new Error("the server does not expose Server_NamespaceArray, so no namespace can be named");
|
|
54
|
+
}
|
|
55
|
+
return [...value];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* every node a crawl from Root reaches, with the references of those in the target namespace.
|
|
59
|
+
*
|
|
60
|
+
* References are kept only for the target namespace because they are all the mapper reads: for
|
|
61
|
+
* any other node it asks for a name. That also bounds memory on a server whose base namespace is
|
|
62
|
+
* far larger than the model being exported.
|
|
63
|
+
*/
|
|
64
|
+
async function crawl(session, targetIndex) {
|
|
65
|
+
const known = new Map();
|
|
66
|
+
const nodes = [];
|
|
67
|
+
const rootReference = { nodeId: ROOT, nodeClass: node_opcua_data_model_1.NodeClass.Object, browseName: new node_opcua_data_model_1.QualifiedName({ name: "Root" }) };
|
|
68
|
+
known.set(ROOT.toString(), { ...rootReference, references: [] });
|
|
69
|
+
let frontier = [ROOT];
|
|
70
|
+
const visited = new Set([ROOT.toString()]);
|
|
71
|
+
while (frontier.length) {
|
|
72
|
+
const results = await (0, node_opcua_pseudo_session_1.browseAll)(session, frontier.map((nodeId) => ({
|
|
73
|
+
nodeId,
|
|
74
|
+
browseDirection: node_opcua_service_browse_1.BrowseDirection.Both,
|
|
75
|
+
referenceTypeId: REFERENCES,
|
|
76
|
+
includeSubtypes: true,
|
|
77
|
+
nodeClassMask: 0,
|
|
78
|
+
resultMask: RESULT_MASK
|
|
79
|
+
})));
|
|
80
|
+
const next = [];
|
|
81
|
+
for (let index = 0; index < frontier.length; index++) {
|
|
82
|
+
const from = frontier[index];
|
|
83
|
+
const references = results[index]?.references ?? [];
|
|
84
|
+
const owner = known.get(from.toString());
|
|
85
|
+
for (const reference of references) {
|
|
86
|
+
const key = reference.nodeId.toString();
|
|
87
|
+
if (!known.has(key))
|
|
88
|
+
known.set(key, stubOf(reference));
|
|
89
|
+
if (owner && from.namespace === targetIndex) {
|
|
90
|
+
owner.references.push({
|
|
91
|
+
referenceTypeId: reference.referenceTypeId,
|
|
92
|
+
isForward: reference.isForward,
|
|
93
|
+
targetId: reference.nodeId
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (!visited.has(key) && reference.isForward) {
|
|
97
|
+
visited.add(key);
|
|
98
|
+
next.push(reference.nodeId);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (owner && from.namespace === targetIndex) {
|
|
102
|
+
nodes.push(owner);
|
|
103
|
+
// a node's own type definition is the target of its forward HasTypeDefinition
|
|
104
|
+
// edge. ReferenceDescription.typeDefinition is the *target's* type, not this
|
|
105
|
+
// node's, and reading it as this node's silently retypes half the model.
|
|
106
|
+
const typeDefinition = references.find((reference) => reference.isForward && isHasTypeDefinition(reference))?.nodeId;
|
|
107
|
+
if (typeDefinition)
|
|
108
|
+
owner.typeDefinition = typeDefinition;
|
|
109
|
+
const supertype = references.find((reference) => !reference.isForward && isHasSubtype(reference));
|
|
110
|
+
if (supertype)
|
|
111
|
+
owner.subtypeOf = supertype.nodeId;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
frontier = next;
|
|
115
|
+
}
|
|
116
|
+
return { nodes, known };
|
|
117
|
+
}
|
|
118
|
+
const HAS_SUBTYPE = (0, node_opcua_nodeid_1.resolveNodeId)("HasSubtype");
|
|
119
|
+
const HAS_TYPE_DEFINITION = (0, node_opcua_nodeid_1.resolveNodeId)("HasTypeDefinition");
|
|
120
|
+
const isHasSubtype = (reference) => reference.referenceTypeId.toString() === HAS_SUBTYPE.toString();
|
|
121
|
+
const isHasTypeDefinition = (reference) => reference.referenceTypeId.toString() === HAS_TYPE_DEFINITION.toString();
|
|
122
|
+
/**
|
|
123
|
+
* the reference-type hierarchy, which `isHierarchical` walks and a stub does not carry.
|
|
124
|
+
*
|
|
125
|
+
* Reference types are few, and almost all of them belong to the base namespace, so this is a
|
|
126
|
+
* handful of browses however large the model is.
|
|
127
|
+
*/
|
|
128
|
+
async function fillReferenceTypeChains(session, known) {
|
|
129
|
+
const pending = () => [...known.values()].filter((node) => node.nodeClass === node_opcua_data_model_1.NodeClass.ReferenceType && node.subtypeOf === undefined);
|
|
130
|
+
let batch = pending();
|
|
131
|
+
const asked = new Set();
|
|
132
|
+
while (batch.length) {
|
|
133
|
+
const fresh = batch.filter((node) => !asked.has(node.nodeId.toString()));
|
|
134
|
+
if (!fresh.length)
|
|
135
|
+
return;
|
|
136
|
+
for (const node of fresh)
|
|
137
|
+
asked.add(node.nodeId.toString());
|
|
138
|
+
const results = await (0, node_opcua_pseudo_session_1.browseAll)(session, fresh.map((node) => ({
|
|
139
|
+
nodeId: node.nodeId,
|
|
140
|
+
browseDirection: node_opcua_service_browse_1.BrowseDirection.Inverse,
|
|
141
|
+
referenceTypeId: HAS_SUBTYPE,
|
|
142
|
+
includeSubtypes: false,
|
|
143
|
+
nodeClassMask: 0,
|
|
144
|
+
resultMask: RESULT_MASK
|
|
145
|
+
})));
|
|
146
|
+
for (let index = 0; index < fresh.length; index++) {
|
|
147
|
+
const reference = results[index]?.references?.[0];
|
|
148
|
+
if (!reference)
|
|
149
|
+
continue;
|
|
150
|
+
fresh[index].subtypeOf = reference.nodeId;
|
|
151
|
+
const key = reference.nodeId.toString();
|
|
152
|
+
if (!known.has(key))
|
|
153
|
+
known.set(key, stubOf(reference));
|
|
154
|
+
}
|
|
155
|
+
batch = pending();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** the attributes a node carries that no browse reports */
|
|
159
|
+
async function readAttributes(session, nodes) {
|
|
160
|
+
const wanted = [];
|
|
161
|
+
for (const node of nodes) {
|
|
162
|
+
wanted.push({ node, attributeId: node_opcua_data_model_1.AttributeIds.Description });
|
|
163
|
+
if (node.nodeClass === node_opcua_data_model_1.NodeClass.Variable || node.nodeClass === node_opcua_data_model_1.NodeClass.VariableType) {
|
|
164
|
+
wanted.push({ node, attributeId: node_opcua_data_model_1.AttributeIds.DataType });
|
|
165
|
+
wanted.push({ node, attributeId: node_opcua_data_model_1.AttributeIds.ValueRank });
|
|
166
|
+
wanted.push({ node, attributeId: node_opcua_data_model_1.AttributeIds.ArrayDimensions });
|
|
167
|
+
wanted.push({ node, attributeId: node_opcua_data_model_1.AttributeIds.Value });
|
|
168
|
+
}
|
|
169
|
+
if (node.nodeClass === node_opcua_data_model_1.NodeClass.ReferenceType) {
|
|
170
|
+
wanted.push({ node, attributeId: node_opcua_data_model_1.AttributeIds.Symmetric });
|
|
171
|
+
wanted.push({ node, attributeId: node_opcua_data_model_1.AttributeIds.InverseName });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
for (let start = 0; start < wanted.length; start += READ_CHUNK) {
|
|
175
|
+
const chunk = wanted.slice(start, start + READ_CHUNK);
|
|
176
|
+
const dataValues = await session.read(chunk.map(({ node, attributeId }) => ({ nodeId: node.nodeId, attributeId })));
|
|
177
|
+
for (let index = 0; index < chunk.length; index++) {
|
|
178
|
+
const dataValue = dataValues[index];
|
|
179
|
+
if (!dataValue?.statusCode.isGood())
|
|
180
|
+
continue;
|
|
181
|
+
const { node, attributeId } = chunk[index];
|
|
182
|
+
const value = dataValue.value?.value;
|
|
183
|
+
switch (attributeId) {
|
|
184
|
+
case node_opcua_data_model_1.AttributeIds.Description:
|
|
185
|
+
if (value instanceof node_opcua_data_model_1.LocalizedText && value.text)
|
|
186
|
+
node.description = value;
|
|
187
|
+
break;
|
|
188
|
+
case node_opcua_data_model_1.AttributeIds.DataType:
|
|
189
|
+
if (value)
|
|
190
|
+
node.dataType = value;
|
|
191
|
+
break;
|
|
192
|
+
case node_opcua_data_model_1.AttributeIds.ValueRank:
|
|
193
|
+
if (typeof value === "number")
|
|
194
|
+
node.valueRank = value;
|
|
195
|
+
break;
|
|
196
|
+
case node_opcua_data_model_1.AttributeIds.ArrayDimensions:
|
|
197
|
+
if (value)
|
|
198
|
+
node.arrayDimensions = Array.from(value);
|
|
199
|
+
break;
|
|
200
|
+
case node_opcua_data_model_1.AttributeIds.Value:
|
|
201
|
+
if (dataValue.value)
|
|
202
|
+
node.value = dataValue.value;
|
|
203
|
+
break;
|
|
204
|
+
case node_opcua_data_model_1.AttributeIds.Symmetric:
|
|
205
|
+
node.symmetric = !!value;
|
|
206
|
+
break;
|
|
207
|
+
case node_opcua_data_model_1.AttributeIds.InverseName:
|
|
208
|
+
if (value instanceof node_opcua_data_model_1.LocalizedText && value.text)
|
|
209
|
+
node.inverseName = value;
|
|
210
|
+
break;
|
|
211
|
+
default:
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* the version and publication date a `NamespaceMetadataType` object states.
|
|
219
|
+
*
|
|
220
|
+
* There is no `RequiredModels` here to read: the type does not have one. That is why a
|
|
221
|
+
* session-sourced ontology node carries no `owl:imports`.
|
|
222
|
+
*/
|
|
223
|
+
async function readNamespaceMetadata(session, namespaceUri) {
|
|
224
|
+
try {
|
|
225
|
+
const folder = await (0, node_opcua_pseudo_session_1.browseAll)(session, {
|
|
226
|
+
nodeId: NAMESPACES_FOLDER,
|
|
227
|
+
browseDirection: node_opcua_service_browse_1.BrowseDirection.Forward,
|
|
228
|
+
referenceTypeId: REFERENCES,
|
|
229
|
+
includeSubtypes: true,
|
|
230
|
+
nodeClassMask: 0,
|
|
231
|
+
resultMask: RESULT_MASK
|
|
232
|
+
});
|
|
233
|
+
const entry = folder.references?.find((reference) => reference.browseName.name === namespaceUri);
|
|
234
|
+
if (!entry)
|
|
235
|
+
return {};
|
|
236
|
+
const properties = await (0, node_opcua_pseudo_session_1.browseAll)(session, {
|
|
237
|
+
nodeId: entry.nodeId,
|
|
238
|
+
browseDirection: node_opcua_service_browse_1.BrowseDirection.Forward,
|
|
239
|
+
referenceTypeId: REFERENCES,
|
|
240
|
+
includeSubtypes: true,
|
|
241
|
+
nodeClassMask: 0,
|
|
242
|
+
resultMask: RESULT_MASK
|
|
243
|
+
});
|
|
244
|
+
const find = (name) => properties.references?.find((reference) => reference.browseName.name === name)?.nodeId;
|
|
245
|
+
const versionId = find("NamespaceVersion");
|
|
246
|
+
const publicationId = find("NamespacePublicationDate");
|
|
247
|
+
if (!versionId && !publicationId)
|
|
248
|
+
return {};
|
|
249
|
+
const dataValues = await session.read([versionId, publicationId]
|
|
250
|
+
.filter((nodeId) => !!nodeId)
|
|
251
|
+
.map((nodeId) => ({ nodeId, attributeId: node_opcua_data_model_1.AttributeIds.Value })));
|
|
252
|
+
const out = {};
|
|
253
|
+
let cursor = 0;
|
|
254
|
+
if (versionId) {
|
|
255
|
+
const value = dataValues[cursor++]?.value?.value;
|
|
256
|
+
if (typeof value === "string" && value)
|
|
257
|
+
out.version = value;
|
|
258
|
+
}
|
|
259
|
+
if (publicationId) {
|
|
260
|
+
const value = dataValues[cursor]?.value?.value;
|
|
261
|
+
if (value instanceof Date)
|
|
262
|
+
out.publicationDate = value;
|
|
263
|
+
}
|
|
264
|
+
return out;
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// a server without Server/Namespaces states no version, which is not an error for an export
|
|
268
|
+
return {};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/** the model a namespace of a server describes, as far as a session can see it */
|
|
272
|
+
async function sessionToRdfModel(session, modelUri) {
|
|
273
|
+
const namespaceUris = await readNamespaceArray(session);
|
|
274
|
+
const targetIndex = modelUri ? namespaceUris.indexOf(modelUri) : namespaceUris.length - 1;
|
|
275
|
+
if (targetIndex < 0) {
|
|
276
|
+
throw new Error(`the server holds no namespace ${modelUri}`);
|
|
277
|
+
}
|
|
278
|
+
const namespaceUri = namespaceUris[targetIndex];
|
|
279
|
+
const { nodes, known } = await crawl(session, targetIndex);
|
|
280
|
+
await fillReferenceTypeChains(session, known);
|
|
281
|
+
await readAttributes(session, nodes);
|
|
282
|
+
const metadata = await readNamespaceMetadata(session, namespaceUri);
|
|
283
|
+
// a crawl reaches nodes in the order the hierarchy happens to lay them out, which is not an
|
|
284
|
+
// order anyone chose. Sorting makes two exports of the same server comparable.
|
|
285
|
+
nodes.sort((a, b) => a.nodeId.toString().localeCompare(b.nodeId.toString()));
|
|
286
|
+
return {
|
|
287
|
+
namespaceUris,
|
|
288
|
+
target: { index: targetIndex, namespaceUri, version: metadata.version, publicationDate: metadata.publicationDate },
|
|
289
|
+
nodes,
|
|
290
|
+
resolve: (nodeId) => known.get(nodeId.toString())
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=from_session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"from_session.js","sourceRoot":"","sources":["../source/from_session.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An OPC UA information model as JSON-LD, for loading into a SPARQL store.
|
|
3
|
+
*
|
|
4
|
+
* This is unlike the Annex I formats in every way that matters, which is why it lives in a
|
|
5
|
+
* package of its own.
|
|
6
|
+
*
|
|
7
|
+
* It is **not in the specification**. OPC 10000-6 Annex I runs I.1 to I.24 and has no RDF
|
|
8
|
+
* section. The vocabulary belongs to the reference implementation, whose `rdf_prototype.md` no
|
|
9
|
+
* longer describes what it emits, so its output is the specification. What we reverse-engineered
|
|
10
|
+
* is written down in `VOCABULARY.md` beside this file.
|
|
11
|
+
*
|
|
12
|
+
* It is **one-way**. There is no reader, so none of the checks that make the Annex I formats
|
|
13
|
+
* trustworthy apply: no round trip, no fixpoint, no digest equivalence. A diff against the
|
|
14
|
+
* reference implementation is the only oracle, which is why matching it exactly matters more here
|
|
15
|
+
* than for a format that can be checked against itself.
|
|
16
|
+
*
|
|
17
|
+
* There are two ways in, and each has an entry point of its own so that neither drags in what
|
|
18
|
+
* only the other needs:
|
|
19
|
+
*
|
|
20
|
+
* - `node-opcua-uanodeset-rdf/address-space` is the complete source, and the one to prefer where
|
|
21
|
+
* the model was loaded from its NodeSet2 document.
|
|
22
|
+
* - `node-opcua-uanodeset-rdf/session` works against a server whose nodeset file you do not have,
|
|
23
|
+
* which is the only way to get a vendor's model into a graph store at all. It never mentions
|
|
24
|
+
* `node-opcua-address-space`, so a client application does not load it.
|
|
25
|
+
*
|
|
26
|
+
* This module is both, for callers that want both.
|
|
27
|
+
*/
|
|
28
|
+
export * from "./address_space.js";
|
|
29
|
+
export { type RdfSession, sessionToRdfModel } from "./from_session.js";
|
|
30
|
+
export { sessionToJsonLd, sessionToJsonLdText } from "./session.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* An OPC UA information model as JSON-LD, for loading into a SPARQL store.
|
|
4
|
+
*
|
|
5
|
+
* This is unlike the Annex I formats in every way that matters, which is why it lives in a
|
|
6
|
+
* package of its own.
|
|
7
|
+
*
|
|
8
|
+
* It is **not in the specification**. OPC 10000-6 Annex I runs I.1 to I.24 and has no RDF
|
|
9
|
+
* section. The vocabulary belongs to the reference implementation, whose `rdf_prototype.md` no
|
|
10
|
+
* longer describes what it emits, so its output is the specification. What we reverse-engineered
|
|
11
|
+
* is written down in `VOCABULARY.md` beside this file.
|
|
12
|
+
*
|
|
13
|
+
* It is **one-way**. There is no reader, so none of the checks that make the Annex I formats
|
|
14
|
+
* trustworthy apply: no round trip, no fixpoint, no digest equivalence. A diff against the
|
|
15
|
+
* reference implementation is the only oracle, which is why matching it exactly matters more here
|
|
16
|
+
* than for a format that can be checked against itself.
|
|
17
|
+
*
|
|
18
|
+
* There are two ways in, and each has an entry point of its own so that neither drags in what
|
|
19
|
+
* only the other needs:
|
|
20
|
+
*
|
|
21
|
+
* - `node-opcua-uanodeset-rdf/address-space` is the complete source, and the one to prefer where
|
|
22
|
+
* the model was loaded from its NodeSet2 document.
|
|
23
|
+
* - `node-opcua-uanodeset-rdf/session` works against a server whose nodeset file you do not have,
|
|
24
|
+
* which is the only way to get a vendor's model into a graph store at all. It never mentions
|
|
25
|
+
* `node-opcua-address-space`, so a client application does not load it.
|
|
26
|
+
*
|
|
27
|
+
* This module is both, for callers that want both.
|
|
28
|
+
*/
|
|
29
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
32
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
33
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
34
|
+
}
|
|
35
|
+
Object.defineProperty(o, k2, desc);
|
|
36
|
+
}) : (function(o, m, k, k2) {
|
|
37
|
+
if (k2 === undefined) k2 = k;
|
|
38
|
+
o[k2] = m[k];
|
|
39
|
+
}));
|
|
40
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
41
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.sessionToJsonLdText = exports.sessionToJsonLd = exports.sessionToRdfModel = void 0;
|
|
45
|
+
__exportStar(require("./address_space.js"), exports);
|
|
46
|
+
var from_session_js_1 = require("./from_session.js");
|
|
47
|
+
Object.defineProperty(exports, "sessionToRdfModel", { enumerable: true, get: function () { return from_session_js_1.sessionToRdfModel; } });
|
|
48
|
+
var session_js_1 = require("./session.js");
|
|
49
|
+
Object.defineProperty(exports, "sessionToJsonLd", { enumerable: true, get: function () { return session_js_1.sessionToJsonLd; } });
|
|
50
|
+
Object.defineProperty(exports, "sessionToJsonLdText", { enumerable: true, get: function () { return session_js_1.sessionToJsonLdText; } });
|
|
51
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;;;;;;;;;;;;;;;;;AAEH,qDAAmC;AACnC,qDAAuE;AAA7C,oHAAA,iBAAiB,OAAA;AAC3C,2CAAoE;AAA3D,6GAAA,eAAe,OAAA;AAAE,iHAAA,mBAAmB,OAAA"}
|
package/dist/model.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the JSON-LD mapper needs to know about a model, and nothing more.
|
|
3
|
+
*
|
|
4
|
+
* The mapper used to read an `IAddressSpace` directly, which tied it to a source that answers
|
|
5
|
+
* synchronously and at random. A session answers asynchronously and in batches, and rewriting the
|
|
6
|
+
* mapper around `await` would have turned four passes over the nodes into thousands of round
|
|
7
|
+
* trips. So collection and mapping are separated instead: a collector fills this structure, the
|
|
8
|
+
* mapper reads it, and the mapper never awaits.
|
|
9
|
+
*
|
|
10
|
+
* The structure is deliberately close to what OPC UA can actually tell you about a node, since
|
|
11
|
+
* one of its two collectors has only Browse and Read to work with.
|
|
12
|
+
*/
|
|
13
|
+
import type { LocalizedText, NodeClass, QualifiedName } from "node-opcua-data-model";
|
|
14
|
+
import type { NodeId } from "node-opcua-nodeid";
|
|
15
|
+
import type { Variant } from "node-opcua-variant";
|
|
16
|
+
/** one edge, in the direction the source states it */
|
|
17
|
+
export interface RdfReference {
|
|
18
|
+
referenceTypeId: NodeId;
|
|
19
|
+
isForward: boolean;
|
|
20
|
+
targetId: NodeId;
|
|
21
|
+
}
|
|
22
|
+
/** a model the exporter names in its own right */
|
|
23
|
+
export interface RdfModelReference {
|
|
24
|
+
modelUri: string;
|
|
25
|
+
version?: string;
|
|
26
|
+
publicationDate?: Date;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* one node.
|
|
30
|
+
*
|
|
31
|
+
* A node the exporter merely has to *name* (a supertype in another model, say) needs only
|
|
32
|
+
* `nodeId`, `nodeClass` and `browseName`; the rest may be absent, and `references` may be empty.
|
|
33
|
+
* Only the nodes of the exported namespace are filled in completely.
|
|
34
|
+
*/
|
|
35
|
+
export interface RdfNode {
|
|
36
|
+
nodeId: NodeId;
|
|
37
|
+
nodeClass: NodeClass;
|
|
38
|
+
browseName: QualifiedName;
|
|
39
|
+
references: RdfReference[];
|
|
40
|
+
description?: LocalizedText;
|
|
41
|
+
/**
|
|
42
|
+
* NodeSet2 metadata, not an OPC UA attribute, so a session-sourced model never carries it.
|
|
43
|
+
* See "What a session cannot tell you" in VOCABULARY.md.
|
|
44
|
+
*/
|
|
45
|
+
symbolicName?: string;
|
|
46
|
+
typeDefinition?: NodeId;
|
|
47
|
+
/** Variable and VariableType */
|
|
48
|
+
dataType?: NodeId;
|
|
49
|
+
valueRank?: number;
|
|
50
|
+
arrayDimensions?: number[] | null;
|
|
51
|
+
value?: Variant;
|
|
52
|
+
/** ReferenceType */
|
|
53
|
+
inverseName?: LocalizedText;
|
|
54
|
+
symmetric?: boolean;
|
|
55
|
+
subtypeOf?: NodeId;
|
|
56
|
+
}
|
|
57
|
+
/** the namespace being exported, and what the ontology node says about it */
|
|
58
|
+
export interface RdfTarget {
|
|
59
|
+
index: number;
|
|
60
|
+
namespaceUri: string;
|
|
61
|
+
version?: string;
|
|
62
|
+
publicationDate?: Date;
|
|
63
|
+
requiredModels?: RdfModelReference[];
|
|
64
|
+
}
|
|
65
|
+
/** everything the mapper reads */
|
|
66
|
+
export interface RdfModel {
|
|
67
|
+
/** index to uri, as the source's own namespace array orders it */
|
|
68
|
+
namespaceUris: string[];
|
|
69
|
+
target: RdfTarget;
|
|
70
|
+
/** the exported namespace's nodes, in the order they are written */
|
|
71
|
+
nodes: RdfNode[];
|
|
72
|
+
/**
|
|
73
|
+
* any node the mapper may have to name, including nodes of other models.
|
|
74
|
+
*
|
|
75
|
+
* An address space answers this from itself on demand; a session collector has to have
|
|
76
|
+
* fetched the answer already, which is why the return is a node rather than a promise.
|
|
77
|
+
*/
|
|
78
|
+
resolve(nodeId: NodeId): RdfNode | undefined;
|
|
79
|
+
}
|
package/dist/model.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* What the JSON-LD mapper needs to know about a model, and nothing more.
|
|
4
|
+
*
|
|
5
|
+
* The mapper used to read an `IAddressSpace` directly, which tied it to a source that answers
|
|
6
|
+
* synchronously and at random. A session answers asynchronously and in batches, and rewriting the
|
|
7
|
+
* mapper around `await` would have turned four passes over the nodes into thousands of round
|
|
8
|
+
* trips. So collection and mapping are separated instead: a collector fills this structure, the
|
|
9
|
+
* mapper reads it, and the mapper never awaits.
|
|
10
|
+
*
|
|
11
|
+
* The structure is deliberately close to what OPC UA can actually tell you about a node, since
|
|
12
|
+
* one of its two collectors has only Browse and Read to work with.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../source/model.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The session entry point: `node-opcua-uanodeset-rdf/session`.
|
|
3
|
+
*
|
|
4
|
+
* Nothing reachable from here mentions `node-opcua-address-space`, at the type level or the
|
|
5
|
+
* runtime one, so a client application can export a server's model without loading the address
|
|
6
|
+
* space machinery it has no other use for. That is the whole reason this is a separate entry
|
|
7
|
+
* point rather than a second function in the root one.
|
|
8
|
+
*
|
|
9
|
+
* What a session cannot tell you is listed in `VOCABULARY.md`; the short version is that OPC UA
|
|
10
|
+
* has no service listing the nodes of a namespace, `SymbolicName` is not an attribute, and
|
|
11
|
+
* `NamespaceMetadataType` states no required models.
|
|
12
|
+
*/
|
|
13
|
+
import { type RdfSession } from "./from_session.js";
|
|
14
|
+
import { type JsonLdOptions } from "./to_jsonld.js";
|
|
15
|
+
export { type RdfSession, sessionToRdfModel } from "./from_session.js";
|
|
16
|
+
export type { RdfModel, RdfModelReference, RdfNode, RdfReference, RdfTarget } from "./model.js";
|
|
17
|
+
export { type JsonLdOptions, modelToJsonLd, OPCUA_NAMESPACE, prefixOfNamespace, UARDF } from "./to_jsonld.js";
|
|
18
|
+
/**
|
|
19
|
+
* a namespace of a server as a JSON-LD document.
|
|
20
|
+
*
|
|
21
|
+
* The session may be a real client session, or a `PseudoSession` over an address space. The
|
|
22
|
+
* latter is what makes the two paths comparable: the same model collected two ways, where the
|
|
23
|
+
* difference is exactly what a session cannot carry.
|
|
24
|
+
*/
|
|
25
|
+
export declare function sessionToJsonLd(session: RdfSession, options?: JsonLdOptions): Promise<Record<string, unknown>>;
|
|
26
|
+
/** a namespace of a server as a JSON-LD document, serialised */
|
|
27
|
+
export declare function sessionToJsonLdText(session: RdfSession, options?: JsonLdOptions): Promise<string>;
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The session entry point: `node-opcua-uanodeset-rdf/session`.
|
|
4
|
+
*
|
|
5
|
+
* Nothing reachable from here mentions `node-opcua-address-space`, at the type level or the
|
|
6
|
+
* runtime one, so a client application can export a server's model without loading the address
|
|
7
|
+
* space machinery it has no other use for. That is the whole reason this is a separate entry
|
|
8
|
+
* point rather than a second function in the root one.
|
|
9
|
+
*
|
|
10
|
+
* What a session cannot tell you is listed in `VOCABULARY.md`; the short version is that OPC UA
|
|
11
|
+
* has no service listing the nodes of a namespace, `SymbolicName` is not an attribute, and
|
|
12
|
+
* `NamespaceMetadataType` states no required models.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.UARDF = exports.prefixOfNamespace = exports.OPCUA_NAMESPACE = exports.modelToJsonLd = exports.sessionToRdfModel = void 0;
|
|
16
|
+
exports.sessionToJsonLd = sessionToJsonLd;
|
|
17
|
+
exports.sessionToJsonLdText = sessionToJsonLdText;
|
|
18
|
+
const from_session_js_1 = require("./from_session.js");
|
|
19
|
+
const to_jsonld_js_1 = require("./to_jsonld.js");
|
|
20
|
+
var from_session_js_2 = require("./from_session.js");
|
|
21
|
+
Object.defineProperty(exports, "sessionToRdfModel", { enumerable: true, get: function () { return from_session_js_2.sessionToRdfModel; } });
|
|
22
|
+
var to_jsonld_js_2 = require("./to_jsonld.js");
|
|
23
|
+
Object.defineProperty(exports, "modelToJsonLd", { enumerable: true, get: function () { return to_jsonld_js_2.modelToJsonLd; } });
|
|
24
|
+
Object.defineProperty(exports, "OPCUA_NAMESPACE", { enumerable: true, get: function () { return to_jsonld_js_2.OPCUA_NAMESPACE; } });
|
|
25
|
+
Object.defineProperty(exports, "prefixOfNamespace", { enumerable: true, get: function () { return to_jsonld_js_2.prefixOfNamespace; } });
|
|
26
|
+
Object.defineProperty(exports, "UARDF", { enumerable: true, get: function () { return to_jsonld_js_2.UARDF; } });
|
|
27
|
+
/**
|
|
28
|
+
* a namespace of a server as a JSON-LD document.
|
|
29
|
+
*
|
|
30
|
+
* The session may be a real client session, or a `PseudoSession` over an address space. The
|
|
31
|
+
* latter is what makes the two paths comparable: the same model collected two ways, where the
|
|
32
|
+
* difference is exactly what a session cannot carry.
|
|
33
|
+
*/
|
|
34
|
+
async function sessionToJsonLd(session, options = {}) {
|
|
35
|
+
return (0, to_jsonld_js_1.modelToJsonLd)(await (0, from_session_js_1.sessionToRdfModel)(session, options.modelUri), options);
|
|
36
|
+
}
|
|
37
|
+
/** a namespace of a server as a JSON-LD document, serialised */
|
|
38
|
+
async function sessionToJsonLdText(session, options = {}) {
|
|
39
|
+
return `${JSON.stringify(await sessionToJsonLd(session, options), null, 2)}\n`;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../source/session.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAgBH,0CAEC;AAGD,kDAEC;AArBD,uDAAuE;AACvE,iDAAmE;AAEnE,qDAAuE;AAA7C,oHAAA,iBAAiB,OAAA;AAE3C,+CAA8G;AAAjF,6GAAA,aAAa,OAAA;AAAE,+GAAA,eAAe,OAAA;AAAE,iHAAA,iBAAiB,OAAA;AAAE,qGAAA,KAAK,OAAA;AAErF;;;;;;GAMG;AACI,KAAK,UAAU,eAAe,CAAC,OAAmB,EAAE,UAAyB,EAAE;IAClF,OAAO,IAAA,4BAAa,EAAC,MAAM,IAAA,mCAAiB,EAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;AACtF,CAAC;AAED,gEAAgE;AACzD,KAAK,UAAU,mBAAmB,CAAC,OAAmB,EAAE,UAAyB,EAAE;IACtF,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AACnF,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vocabulary, and the mapping from a collected model to the JSON-LD document.
|
|
3
|
+
*
|
|
4
|
+
* Everything here is synchronous and reads only `RdfModel`, so the same code serves a model
|
|
5
|
+
* collected from an address space and one collected over a session. The vocabulary is the
|
|
6
|
+
* reference implementation's; `VOCABULARY.md` beside this file records what reading its output
|
|
7
|
+
* established.
|
|
8
|
+
*/
|
|
9
|
+
import type { RdfModel } from "./model.js";
|
|
10
|
+
/** the vocabulary the reference implementation writes its own terms under */
|
|
11
|
+
export declare const UARDF = "http://opcfoundation.org/rdf/uacore#";
|
|
12
|
+
/** the OPC UA base namespace, always abbreviated `opcua` */
|
|
13
|
+
export declare const OPCUA_NAMESPACE = "http://opcfoundation.org/UA/";
|
|
14
|
+
/** the prefix a namespace uri is abbreviated to: its last non-empty segment, lowercased */
|
|
15
|
+
export declare function prefixOfNamespace(uri: string): string;
|
|
16
|
+
export interface JsonLdOptions {
|
|
17
|
+
/** the model to export; the default is the last namespace the address space holds */
|
|
18
|
+
modelUri?: string;
|
|
19
|
+
/**
|
|
20
|
+
* two fields of the ontology node the address space does not retain.
|
|
21
|
+
*
|
|
22
|
+
* They are written in the source document's `Models` element and dropped by the loader, so a
|
|
23
|
+
* caller that wants them in the output supplies them again.
|
|
24
|
+
*/
|
|
25
|
+
model?: {
|
|
26
|
+
xmlSchemaUri?: string;
|
|
27
|
+
modelVersion?: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** a collected model as a JSON-LD document */
|
|
31
|
+
export declare function modelToJsonLd(model: RdfModel, options?: JsonLdOptions): Record<string, unknown>;
|