node-opcua-address-space 2.173.0 → 2.174.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/dist/source/loader/load_nodeset2.js +26 -1
- package/dist/source/loader/load_nodeset2.js.map +1 -1
- package/dist/source/session_context.d.ts +45 -24
- package/dist/source/session_context.js +43 -29
- package/dist/source/session_context.js.map +1 -1
- package/dist/src/nodeid_manager.js +19 -1
- package/dist/src/nodeid_manager.js.map +1 -1
- package/dist/src/nodeset_tools/construct_namespace_dependency.d.ts +6 -15
- package/dist/src/nodeset_tools/construct_namespace_dependency.js +21 -10
- package/dist/src/nodeset_tools/construct_namespace_dependency.js.map +1 -1
- package/dist/tsconfig_base.tsbuildinfo +1 -1
- package/package.json +28 -28
- package/source/loader/load_nodeset2.ts +28 -1
- package/source/session_context.ts +71 -25
- package/src/nodeid_manager.ts +19 -1
- package/src/nodeset_tools/construct_namespace_dependency.ts +30 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-opcua-address-space",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.174.0",
|
|
4
4
|
"description": "pure nodejs OPCUA SDK - module address-space",
|
|
5
5
|
"main": "./dist/src/index_current.js",
|
|
6
6
|
"types": "./dist/source/index.d.ts",
|
|
@@ -21,37 +21,37 @@
|
|
|
21
21
|
"@types/semver": "7.7.1",
|
|
22
22
|
"chalk": "4.1.2",
|
|
23
23
|
"dequeue": "^1.0.5",
|
|
24
|
-
"node-opcua-address-space-base": "2.
|
|
24
|
+
"node-opcua-address-space-base": "2.174.0",
|
|
25
25
|
"node-opcua-assert": "2.164.0",
|
|
26
|
-
"node-opcua-basic-types": "2.
|
|
26
|
+
"node-opcua-basic-types": "2.174.0",
|
|
27
27
|
"node-opcua-binary-stream": "2.173.0",
|
|
28
|
-
"node-opcua-client-dynamic-extension-object": "2.
|
|
29
|
-
"node-opcua-constants": "2.
|
|
28
|
+
"node-opcua-client-dynamic-extension-object": "2.174.0",
|
|
29
|
+
"node-opcua-constants": "2.174.0",
|
|
30
30
|
"node-opcua-crypto": "5.3.6",
|
|
31
|
-
"node-opcua-data-access": "2.
|
|
32
|
-
"node-opcua-data-model": "2.
|
|
33
|
-
"node-opcua-data-value": "2.
|
|
34
|
-
"node-opcua-date-time": "2.
|
|
31
|
+
"node-opcua-data-access": "2.174.0",
|
|
32
|
+
"node-opcua-data-model": "2.174.0",
|
|
33
|
+
"node-opcua-data-value": "2.174.0",
|
|
34
|
+
"node-opcua-date-time": "2.174.0",
|
|
35
35
|
"node-opcua-debug": "2.172.0",
|
|
36
36
|
"node-opcua-enum": "2.173.0",
|
|
37
|
-
"node-opcua-extension-object": "2.
|
|
38
|
-
"node-opcua-factory": "2.
|
|
39
|
-
"node-opcua-nodeid": "2.
|
|
40
|
-
"node-opcua-nodeset-ua": "2.
|
|
41
|
-
"node-opcua-numeric-range": "2.
|
|
37
|
+
"node-opcua-extension-object": "2.174.0",
|
|
38
|
+
"node-opcua-factory": "2.174.0",
|
|
39
|
+
"node-opcua-nodeid": "2.174.0",
|
|
40
|
+
"node-opcua-nodeset-ua": "2.174.0",
|
|
41
|
+
"node-opcua-numeric-range": "2.174.0",
|
|
42
42
|
"node-opcua-object-registry": "2.172.0",
|
|
43
|
-
"node-opcua-pseudo-session": "2.
|
|
44
|
-
"node-opcua-service-browse": "2.
|
|
45
|
-
"node-opcua-service-call": "2.
|
|
46
|
-
"node-opcua-service-history": "2.
|
|
47
|
-
"node-opcua-service-translate-browse-path": "2.
|
|
48
|
-
"node-opcua-service-write": "2.
|
|
43
|
+
"node-opcua-pseudo-session": "2.174.0",
|
|
44
|
+
"node-opcua-service-browse": "2.174.0",
|
|
45
|
+
"node-opcua-service-call": "2.174.0",
|
|
46
|
+
"node-opcua-service-history": "2.174.0",
|
|
47
|
+
"node-opcua-service-translate-browse-path": "2.174.0",
|
|
48
|
+
"node-opcua-service-write": "2.174.0",
|
|
49
49
|
"node-opcua-status-code": "2.173.0",
|
|
50
|
-
"node-opcua-types": "2.
|
|
50
|
+
"node-opcua-types": "2.174.0",
|
|
51
51
|
"node-opcua-utils": "2.173.0",
|
|
52
|
-
"node-opcua-variant": "2.
|
|
52
|
+
"node-opcua-variant": "2.174.0",
|
|
53
53
|
"node-opcua-xml2json": "2.173.0",
|
|
54
|
-
"semver": "^7.8.
|
|
54
|
+
"semver": "^7.8.5",
|
|
55
55
|
"thenify-ex": "4.4.0",
|
|
56
56
|
"xml-writer": "^1.7.0"
|
|
57
57
|
},
|
|
@@ -59,10 +59,10 @@
|
|
|
59
59
|
"humanize": "0.0.9",
|
|
60
60
|
"node-opcua-benchmarker": "2.173.0",
|
|
61
61
|
"node-opcua-leak-detector": "2.172.0",
|
|
62
|
-
"node-opcua-nodesets": "2.
|
|
63
|
-
"node-opcua-packet-analyzer": "2.
|
|
64
|
-
"node-opcua-schemas": "2.
|
|
65
|
-
"node-opcua-service-filter": "2.
|
|
62
|
+
"node-opcua-nodesets": "2.174.0",
|
|
63
|
+
"node-opcua-packet-analyzer": "2.174.0",
|
|
64
|
+
"node-opcua-schemas": "2.174.0",
|
|
65
|
+
"node-opcua-service-filter": "2.174.0",
|
|
66
66
|
"node-opcua-test-fixtures": "2.157.0"
|
|
67
67
|
},
|
|
68
68
|
"author": "Etienne Rossignon",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"internet of things"
|
|
81
81
|
],
|
|
82
82
|
"homepage": "http://node-opcua.github.io/",
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "011657a3a4805ad106df7381c24ed84e2a18d8f1",
|
|
84
84
|
"files": [
|
|
85
85
|
"dist",
|
|
86
86
|
"distHelpers",
|
|
@@ -133,6 +133,28 @@ function makeDefaultVariant(
|
|
|
133
133
|
}
|
|
134
134
|
return variant;
|
|
135
135
|
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* a Matrix variant is "uninitialized" when it carries no element (value=[]) but declares
|
|
139
|
+
* non-zero dimensions (e.g. ArrayDimensions="256,128"). Such a variant is internally inconsistent
|
|
140
|
+
* (value.length !== product(dimensions)) and, if serialized, produces a spec-violating wire form.
|
|
141
|
+
*/
|
|
142
|
+
function isUninitializedMatrix(value: VariantOptions): boolean {
|
|
143
|
+
if (value.arrayType !== VariantArrayType.Matrix) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
const length = Array.isArray(value.value) ? value.value.length : 0;
|
|
147
|
+
if (length !== 0) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
const dimensions = value.dimensions;
|
|
151
|
+
if (!dimensions || dimensions.length === 0) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
const product = dimensions.reduce((n, p) => n * p, 1);
|
|
155
|
+
return product > 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
136
158
|
export interface NodeSet2ParserEngine {
|
|
137
159
|
addNodeSet: (xmlData: string) => Promise<void>;
|
|
138
160
|
terminate: () => Promise<void>;
|
|
@@ -731,7 +753,12 @@ function makeNodeSetParserEngine(addressSpace: IAddressSpace, options: NodeSetLo
|
|
|
731
753
|
if (false && doDebug) {
|
|
732
754
|
debugLog("2 setting value to ", cv.nodeId.toString(), value);
|
|
733
755
|
}
|
|
734
|
-
|
|
756
|
+
// a Matrix variable declared with fixed ArrayDimensions but no <Value> is built with
|
|
757
|
+
// an empty value (value=[]) yet non-zero declared dimensions. This is an *uninitialized*
|
|
758
|
+
// and internally inconsistent matrix (value.length !== product(dimensions)). Advertising
|
|
759
|
+
// it as Good would put a spec-violating matrix on the wire (ArraySize 0 + non-empty
|
|
760
|
+
// ArrayDimensions), so flag it as BadWaitingForInitialData like any other missing value.
|
|
761
|
+
if (value.dataType === DataType.Null || isUninitializedMatrix(value)) {
|
|
735
762
|
cv.setValueFromSource(value, StatusCodes.BadWaitingForInitialData);
|
|
736
763
|
} else {
|
|
737
764
|
cv.setValueFromSource(value, StatusCodes.Good);
|
|
@@ -22,7 +22,7 @@ import type { NamespacePrivate } from "../src/namespace_private";
|
|
|
22
22
|
|
|
23
23
|
export { PermissionType, RolePermissionType, RolePermissionTypeOptions } from "node-opcua-types";
|
|
24
24
|
|
|
25
|
-
type AnyUserIdentityToken = UserNameIdentityToken | AnonymousIdentityToken | X509IdentityToken;
|
|
25
|
+
export type AnyUserIdentityToken = UserNameIdentityToken | AnonymousIdentityToken | X509IdentityToken;
|
|
26
26
|
|
|
27
27
|
function getUserName(userIdentityToken: AnyUserIdentityToken): string {
|
|
28
28
|
if (userIdentityToken instanceof AnonymousIdentityToken) {
|
|
@@ -48,29 +48,23 @@ function getUserName(userIdentityToken: AnyUserIdentityToken): string {
|
|
|
48
48
|
throw new Error("Invalid user identity token");
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Engineer = ObjectIds.WellKnownRole_Engineer,
|
|
69
|
-
Observer = ObjectIds.WellKnownRole_Observer,
|
|
70
|
-
Operator = ObjectIds.WellKnownRole_Operator,
|
|
71
|
-
SecurityAdmin = ObjectIds.WellKnownRole_SecurityAdmin,
|
|
72
|
-
Supervisor = ObjectIds.WellKnownRole_Supervisor
|
|
73
|
-
}
|
|
51
|
+
// Re-exported from node-opcua-constants for backward compatibility.
|
|
52
|
+
// The canonical definition now lives in node-opcua-constants so that
|
|
53
|
+
// client-side packages can use it without pulling in address-space.
|
|
54
|
+
import { WellKnownRoles } from "node-opcua-constants";
|
|
55
|
+
export { WellKnownRoles } from "node-opcua-constants";
|
|
56
|
+
|
|
57
|
+
/** @deprecated Use WellKnownRoles instead */
|
|
58
|
+
export const WellKnownRolesNodeId = {
|
|
59
|
+
Anonymous: ObjectIds.WellKnownRole_Anonymous,
|
|
60
|
+
AuthenticatedUser: ObjectIds.WellKnownRole_AuthenticatedUser,
|
|
61
|
+
ConfigureAdmin: ObjectIds.WellKnownRole_ConfigureAdmin,
|
|
62
|
+
Engineer: ObjectIds.WellKnownRole_Engineer,
|
|
63
|
+
Observer: ObjectIds.WellKnownRole_Observer,
|
|
64
|
+
Operator: ObjectIds.WellKnownRole_Operator,
|
|
65
|
+
SecurityAdmin: ObjectIds.WellKnownRole_SecurityAdmin,
|
|
66
|
+
Supervisor: ObjectIds.WellKnownRole_Supervisor
|
|
67
|
+
} as const;
|
|
74
68
|
/**
|
|
75
69
|
* OPC Unified Architecture, Part 3 13 Release 1.04
|
|
76
70
|
* 4.8.2 Well Known Roles
|
|
@@ -114,9 +108,38 @@ export interface IRolePolicyOverride {
|
|
|
114
108
|
getUserRoles(username: string): NodeId[] | null;
|
|
115
109
|
}
|
|
116
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Session attributes a resolver may use to evaluate application/endpoint
|
|
113
|
+
* restrictions on a Role (OPC 10000-18 §4.4.1).
|
|
114
|
+
*/
|
|
115
|
+
export interface IRoleResolutionContext {
|
|
116
|
+
/** ApplicationUri from the Client certificate, if any. */
|
|
117
|
+
applicationUri?: string | null;
|
|
118
|
+
/** SecureChannel security mode. */
|
|
119
|
+
securityMode?: MessageSecurityMode;
|
|
120
|
+
/** SecureChannel security policy URI. */
|
|
121
|
+
securityPolicyUri?: string;
|
|
122
|
+
/** Endpoint URL used by the Session, if known. */
|
|
123
|
+
endpointUrl?: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Pluggable role resolver (OPC 10000-18 §4.4).
|
|
128
|
+
*
|
|
129
|
+
* Receives the full UserIdentityToken so implementations can match by
|
|
130
|
+
* Thumbprint, X509Subject, UserName, etc., plus an optional resolution context
|
|
131
|
+
* to enforce application/endpoint restrictions. Registered on
|
|
132
|
+
* IServerBase.roleResolvers by packages like node-opcua-role-set-server.
|
|
133
|
+
*/
|
|
134
|
+
export interface IRoleResolver {
|
|
135
|
+
resolveRoles(userIdentityToken: AnyUserIdentityToken, context?: IRoleResolutionContext): NodeId[];
|
|
136
|
+
}
|
|
137
|
+
|
|
117
138
|
export interface IServerBase {
|
|
118
139
|
userManager?: IUserManager;
|
|
119
140
|
rolePolicyOverride?: IRolePolicyOverride | null;
|
|
141
|
+
/** Additional role resolvers (identity stores, LDAP, etc.) */
|
|
142
|
+
roleResolvers?: IRoleResolver[];
|
|
120
143
|
}
|
|
121
144
|
|
|
122
145
|
export interface SessionContextOptions {
|
|
@@ -252,6 +275,11 @@ export class SessionContext implements ISessionContext {
|
|
|
252
275
|
}
|
|
253
276
|
}
|
|
254
277
|
|
|
278
|
+
/** The URL of the Endpoint the Session was created on, or `null` if unknown. */
|
|
279
|
+
public get endpointUrl(): string | null {
|
|
280
|
+
return this.session?.getEndpointUrl?.() ?? null;
|
|
281
|
+
}
|
|
282
|
+
|
|
255
283
|
public toJSON(): Record<string, string | null> {
|
|
256
284
|
return {
|
|
257
285
|
userName: this.getUserName(),
|
|
@@ -325,7 +353,25 @@ export class SessionContext implements ISessionContext {
|
|
|
325
353
|
return anonymous;
|
|
326
354
|
}
|
|
327
355
|
|
|
328
|
-
const rolesNodeId = this.server.userManager.getUserRoles(username);
|
|
356
|
+
const rolesNodeId = this.server.userManager.getUserRoles(username) || [];
|
|
357
|
+
|
|
358
|
+
// OPC 10000-18 §4.4: check registered role resolvers
|
|
359
|
+
if (this.server.roleResolvers && this.session?.userIdentityToken) {
|
|
360
|
+
const resolutionContext: IRoleResolutionContext = {
|
|
361
|
+
applicationUri: this.clientApplicationUri,
|
|
362
|
+
securityMode: this.session.channel?.securityMode,
|
|
363
|
+
securityPolicyUri: this.session.channel?.securityPolicy,
|
|
364
|
+
endpointUrl: this.endpointUrl ?? undefined
|
|
365
|
+
};
|
|
366
|
+
for (const resolver of this.server.roleResolvers) {
|
|
367
|
+
const extra = resolver.resolveRoles(this.session.userIdentityToken, resolutionContext);
|
|
368
|
+
for (const r of extra) {
|
|
369
|
+
if (!rolesNodeId.find((e) => sameNodeId(e, r))) {
|
|
370
|
+
rolesNodeId.push(r);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
329
375
|
|
|
330
376
|
if (rolesNodeId.findIndex((r) => r.namespace === 0 && r.value === WellKnownRoles.AuthenticatedUser) < 0) {
|
|
331
377
|
rolesNodeId.push(resolveNodeId(WellKnownRoles.AuthenticatedUser));
|
package/src/nodeid_manager.ts
CHANGED
|
@@ -180,7 +180,25 @@ export class NodeIdManager {
|
|
|
180
180
|
}
|
|
181
181
|
return nodeId;
|
|
182
182
|
}
|
|
183
|
-
|
|
183
|
+
const nodeId = this._constructNodeId(options);
|
|
184
|
+
// When registerSymbolicNames is true and a nodeId was already
|
|
185
|
+
// provided (e.g. loaded from XML during reverse engineering),
|
|
186
|
+
// also record the BrowseName → NodeId mapping in the symbol
|
|
187
|
+
// cache so that getSymbols() returns the original NodeIds.
|
|
188
|
+
if (options.registerSymbolicNames && nodeId.identifierType === NodeIdType.NUMERIC) {
|
|
189
|
+
const parentInfo = this.findParentNodeId(options);
|
|
190
|
+
let fullParentName = "";
|
|
191
|
+
if (parentInfo) {
|
|
192
|
+
const [parentNodeId, suffix] = parentInfo;
|
|
193
|
+
fullParentName = buildUpName2(parentNodeId, suffix);
|
|
194
|
+
}
|
|
195
|
+
const fullName = compose(fullParentName, prepareName(options.browseName!));
|
|
196
|
+
if (!this._cacheSymbolicName[fullName]) {
|
|
197
|
+
this._cacheSymbolicName[fullName] = [nodeId.value as number, options.nodeClass!];
|
|
198
|
+
this._cacheSymbolicNameRev.add(nodeId.value as number);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return nodeId;
|
|
184
202
|
}
|
|
185
203
|
|
|
186
204
|
private _constructNodeId(options: ConstructNodeIdOptions): NodeId {
|
|
@@ -14,17 +14,18 @@ import type { UAVariableImpl } from "../ua_variable_impl";
|
|
|
14
14
|
const warningLog = make_warningLog(__filename);
|
|
15
15
|
const _debugLog = make_debugLog(__filename);
|
|
16
16
|
|
|
17
|
+
interface RequiredModel {
|
|
18
|
+
requiredNamespaceIndexes: number[];
|
|
19
|
+
nbTypes: number;
|
|
20
|
+
}
|
|
17
21
|
// eslint-disable-next-line max-statements, complexity
|
|
18
|
-
export function _recomputeRequiredModelsFromTypes(
|
|
19
|
-
namespace: INamespace,
|
|
20
|
-
cache?: Map<number, { requiredNamespaceIndexes: number[]; nbTypes: number }>
|
|
21
|
-
): { requiredNamespaceIndexes: number[]; nbTypes: number } {
|
|
22
|
+
export function _recomputeRequiredModelsFromTypes(namespace: INamespace, cache?: Map<number, RequiredModel>): RequiredModel {
|
|
22
23
|
if (namespace.index === 0) {
|
|
23
24
|
return { requiredNamespaceIndexes: [], nbTypes: 1 };
|
|
24
25
|
}
|
|
25
26
|
if (cache) {
|
|
26
27
|
if (cache.has(namespace.index)) {
|
|
27
|
-
return cache.get(namespace.index)
|
|
28
|
+
return cache.get(namespace.index) as RequiredModel;
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
const requiredNamespaceIndexes = [0];
|
|
@@ -155,17 +156,14 @@ export function _recomputeRequiredModelsFromTypes(
|
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
const result = { requiredNamespaceIndexes: requiredNamespaceIndexes, nbTypes: nbTypes };
|
|
159
|
+
const result: RequiredModel = { requiredNamespaceIndexes: requiredNamespaceIndexes, nbTypes: nbTypes };
|
|
159
160
|
if (cache) {
|
|
160
161
|
cache.set(namespace.index, result);
|
|
161
162
|
}
|
|
162
163
|
return result;
|
|
163
164
|
}
|
|
164
165
|
|
|
165
|
-
export function _recomputeRequiredModelsFromTypes2(
|
|
166
|
-
namespace: INamespace,
|
|
167
|
-
cache?: Map<number, { requiredNamespaceIndexes: number[]; nbTypes: number }>
|
|
168
|
-
): { requiredNamespaceIndexes: number[] } {
|
|
166
|
+
export function _recomputeRequiredModelsFromTypes2(namespace: INamespace, cache?: Map<number, RequiredModel>): RequiredModel {
|
|
169
167
|
const addressSpace = namespace.addressSpace;
|
|
170
168
|
|
|
171
169
|
const { requiredNamespaceIndexes } = _recomputeRequiredModelsFromTypes(namespace, cache);
|
|
@@ -187,13 +185,13 @@ export function _recomputeRequiredModelsFromTypes2(
|
|
|
187
185
|
pass2.push(r);
|
|
188
186
|
}
|
|
189
187
|
|
|
190
|
-
return { requiredNamespaceIndexes: pass2 };
|
|
188
|
+
return { requiredNamespaceIndexes: pass2, nbTypes: 0 };
|
|
191
189
|
}
|
|
192
190
|
|
|
193
191
|
export function _getCompleteRequiredModelsFromValuesAndReferences(
|
|
194
192
|
namespace: INamespace,
|
|
195
193
|
priorityList: number[],
|
|
196
|
-
cache?: Map<number,
|
|
194
|
+
cache?: Map<number, RequiredModel>
|
|
197
195
|
): number[] {
|
|
198
196
|
const namespace_ = namespace as NamespacePrivate;
|
|
199
197
|
|
|
@@ -230,16 +228,27 @@ export function _getCompleteRequiredModelsFromValuesAndReferences(
|
|
|
230
228
|
if (refPriority <= thisPriority) {
|
|
231
229
|
consider(namespaceIndexOfTargetNode);
|
|
232
230
|
} else {
|
|
233
|
-
// For forward NonHierarchicalReferences (e.g. HasInterface),
|
|
234
|
-
// always include the target namespace as a dependency
|
|
235
|
-
// regardless of priority, since the current node owns
|
|
236
|
-
// this relationship.
|
|
237
231
|
const referenceType = getReferenceType(reference);
|
|
238
|
-
if (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
232
|
+
if (referenceType) {
|
|
233
|
+
// For forward NonHierarchicalReferences (e.g. HasInterface),
|
|
234
|
+
// always include the target namespace as a dependency
|
|
235
|
+
// regardless of priority, since the current node owns
|
|
236
|
+
// this relationship.
|
|
237
|
+
if (reference.isForward
|
|
238
|
+
&& nonHierarchicalReferencesType
|
|
239
|
+
&& referenceType.isSubtypeOf(nonHierarchicalReferencesType)) {
|
|
240
|
+
consider(namespaceIndexOfTargetNode);
|
|
241
|
+
}
|
|
242
|
+
// For inverse HierarchicalReferences (e.g. Organizes),
|
|
243
|
+
// always include the target namespace as a dependency
|
|
244
|
+
// regardless of priority, since the reference is
|
|
245
|
+
// stored on this node (organizedBy pattern).
|
|
246
|
+
const hierarchicalReferencesType = addressSpace.findReferenceType("HierarchicalReferences");
|
|
247
|
+
if (!reference.isForward
|
|
248
|
+
&& hierarchicalReferencesType
|
|
249
|
+
&& referenceType.isSubtypeOf(hierarchicalReferencesType)) {
|
|
250
|
+
consider(namespaceIndexOfTargetNode);
|
|
251
|
+
}
|
|
243
252
|
}
|
|
244
253
|
}
|
|
245
254
|
}
|