node-opcua-convert-nodeset-to-javascript 2.51.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.
Files changed (48) hide show
  1. package/.mocharc.yml +10 -0
  2. package/LICENSE +20 -0
  3. package/dist/convert_namespace_to_typescript.d.ts +3 -0
  4. package/dist/convert_namespace_to_typescript.js +158 -0
  5. package/dist/convert_namespace_to_typescript.js.map +1 -0
  6. package/dist/convert_to_typescript.d.ts +109 -0
  7. package/dist/convert_to_typescript.js +879 -0
  8. package/dist/convert_to_typescript.js.map +1 -0
  9. package/dist/index.d.ts +3 -0
  10. package/dist/index.js +16 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/main.d.ts +1 -0
  13. package/dist/main.js +66 -0
  14. package/dist/main.js.map +1 -0
  15. package/dist/official_namespaces.d.ts +23 -0
  16. package/dist/official_namespaces.js +36 -0
  17. package/dist/official_namespaces.js.map +1 -0
  18. package/dist/options.d.ts +4 -0
  19. package/dist/options.js +3 -0
  20. package/dist/options.js.map +1 -0
  21. package/dist/private/cache.d.ts +58 -0
  22. package/dist/private/cache.js +213 -0
  23. package/dist/private/cache.js.map +1 -0
  24. package/dist/private/to_filename.d.ts +1 -0
  25. package/dist/private/to_filename.js +10 -0
  26. package/dist/private/to_filename.js.map +1 -0
  27. package/dist/private/utils.d.ts +24 -0
  28. package/dist/private/utils.js +261 -0
  29. package/dist/private/utils.js.map +1 -0
  30. package/dist/private-stuff.d.ts +4 -0
  31. package/dist/private-stuff.js +17 -0
  32. package/dist/private-stuff.js.map +1 -0
  33. package/dist/walk_through.d.ts +13 -0
  34. package/dist/walk_through.js +87 -0
  35. package/dist/walk_through.js.map +1 -0
  36. package/package.json +58 -0
  37. package/source/convert_namespace_to_typescript.ts +171 -0
  38. package/source/convert_to_typescript.ts +1095 -0
  39. package/source/index.ts +3 -0
  40. package/source/main.ts +56 -0
  41. package/source/official_namespaces.ts +35 -0
  42. package/source/options.ts +4 -0
  43. package/source/private/cache.ts +228 -0
  44. package/source/private/to_filename.ts +6 -0
  45. package/source/private/utils.ts +212 -0
  46. package/source/private-stuff.ts +6 -0
  47. package/source/walk_through.ts +73 -0
  48. package/tsconfig-generated.json +13 -0
@@ -0,0 +1,1095 @@
1
+ import * as wrap from "wordwrap";
2
+ import { LocalizedText, NodeClass, QualifiedName } from "node-opcua-data-model";
3
+ import { NodeId } from "node-opcua-nodeid";
4
+ import { IBasicSession } from "node-opcua-pseudo-session";
5
+ import { EnumDefinition, ReferenceDescription, StructureDefinition, _enumerationDataChangeTrigger } from "node-opcua-types";
6
+ import { LineFile, lowerFirstLetter } from "node-opcua-utils";
7
+ import { DataType } from "node-opcua-variant";
8
+ import assert from "node-opcua-assert";
9
+ import { ModellingRuleType } from "node-opcua-address-space-base";
10
+ import * as chalk from "chalk";
11
+ import {
12
+ convertNodeIdToDataTypeAsync,
13
+ getBrowseName,
14
+ getIsAbstract,
15
+ getDefinition,
16
+ getDescription,
17
+ getModellingRule,
18
+ getNodeClass,
19
+ getSubtypeNodeId,
20
+ getSubtypeNodeIdIfAny,
21
+ getTypeDefOrBaseType,
22
+ getChildrenOrFolderElements,
23
+ getDataTypeNodeId,
24
+ extractBasicDataType,
25
+ getValueRank
26
+ } from "./private/utils";
27
+
28
+ import { Cache, constructCache, Import, makeTypeNameNew, referenceExtensionObject, RequestedSubSymbol } from "./private/cache";
29
+ import { Options } from "./options";
30
+ import { toFilename } from "./private/to_filename";
31
+
32
+ const wrapText = wrap(0, 50);
33
+ const f2 = (str: string) => str.padEnd(50, "-");
34
+ const f1 = (str: string) => str.padEnd(50, " ");
35
+ const baseExtension = "_Base";
36
+
37
+ export async function convertDataTypeToTypescript(session: IBasicSession, dataTypeId: NodeId): Promise<void> {
38
+ const definition = await getDefinition(session, dataTypeId);
39
+ const browseName = await getBrowseName(session, dataTypeId);
40
+
41
+ const dataTypeTypescriptName = `UA${browseName.name!.toString()}`;
42
+ const f = new LineFile();
43
+ if (definition && definition instanceof StructureDefinition) {
44
+ f.write(`interface ${dataTypeTypescriptName} {`);
45
+ for (const field of definition.fields || []) {
46
+ /** */
47
+ }
48
+ f.write(`}`);
49
+ }
50
+ }
51
+
52
+ // to avoid clashes
53
+ function toJavascritPropertyName(childName: string): string {
54
+ childName = lowerFirstLetter(childName);
55
+ if (childName === "namespaceUri") {
56
+ childName = "$namespaceUri";
57
+ }
58
+ if (childName === "rolePermissions") {
59
+ childName = "$rolePermissions";
60
+ }
61
+ if (childName === "displayName") {
62
+ childName = "$displayName";
63
+ }
64
+ if (childName === "eventNotifier") {
65
+ childName = "$eventNotifier";
66
+ }
67
+ return childName.replace(/</g, "$").replace(/>/g, "$").replace(/ |\./g, "_").replace(/#/g, "_");
68
+ }
69
+
70
+ function quotifyIfNecessary(s: string): string {
71
+ if (s.match(/(^[^a-zA-Z])|([^a-zA-Z_0-9])/)) {
72
+ return `"${s}"`;
73
+ }
74
+ if (s === "nodeClass") {
75
+ return `["$nodeClass"]`;
76
+ }
77
+ return s;
78
+ }
79
+
80
+ async function getCorrepondingJavascriptType2(
81
+ session: IBasicSession,
82
+ nodeId: NodeId,
83
+ dataTypeNodeId: NodeId,
84
+ cache: Cache,
85
+ importCollect?: (t: Import) => void
86
+ ): Promise<{ dataType: DataType; jtype: string }> {
87
+ const q = await getCorrepondingJavascriptType(session, dataTypeNodeId, cache, importCollect);
88
+ const valueRank = await getValueRank(session, nodeId);
89
+ return { dataType: q.dataType, jtype: q.jtype + (valueRank >= 1 ? "[]" : "") };
90
+ }
91
+
92
+ // eslint-disable-next-line complexity
93
+ async function getCorrepondingJavascriptType(
94
+ session: IBasicSession,
95
+ dataTypeNodeId: NodeId,
96
+ cache: Cache,
97
+ importCollect?: (t: Import) => void
98
+ ): Promise<{ dataType: DataType; jtype: string }> {
99
+ const dataType = await convertNodeIdToDataTypeAsync(session, dataTypeNodeId);
100
+
101
+ const referenceBasicType = (name: string): string => {
102
+ const t = { name, namespace: -1, module: "BasicType" };
103
+ importCollect && importCollect(t);
104
+ cache.ensureImported(t);
105
+ return t.name;
106
+ };
107
+ if (dataType === DataType.ExtensionObject) {
108
+ const jtypeImport = await referenceExtensionObject(session, dataTypeNodeId);
109
+ const jtype = jtypeImport.name;
110
+ importCollect && importCollect(jtypeImport);
111
+ return { dataType, jtype: jtype };
112
+ }
113
+ switch (dataType) {
114
+ case DataType.Null:
115
+ return { dataType, jtype: "undefined" };
116
+ case DataType.Boolean:
117
+ return { dataType, jtype: "boolean" };
118
+ case DataType.Byte:
119
+ return { dataType, jtype: referenceBasicType("Byte") };
120
+ case DataType.ByteString:
121
+ return { dataType, jtype: "Buffer" };
122
+ case DataType.DataValue:
123
+ return { dataType, jtype: referenceBasicType("DataValue") };
124
+ case DataType.DateTime:
125
+ return { dataType, jtype: "Date" };
126
+ case DataType.DiagnosticInfo:
127
+ return { dataType, jtype: referenceBasicType("DiagnosticInfo") };
128
+ case DataType.Double:
129
+ return { dataType, jtype: "number" };
130
+ case DataType.Float:
131
+ return { dataType, jtype: "number" };
132
+ case DataType.Guid:
133
+ return { dataType, jtype: referenceBasicType("Guid") };
134
+ case DataType.Int16:
135
+ return { dataType, jtype: referenceBasicType("Int16") };
136
+ case DataType.Int32:
137
+ return { dataType, jtype: referenceBasicType("Int32") };
138
+ case DataType.UInt16:
139
+ return { dataType, jtype: referenceBasicType("UInt16") };
140
+ case DataType.UInt32:
141
+ return { dataType, jtype: referenceBasicType("UInt32") };
142
+ case DataType.UInt64:
143
+ return { dataType, jtype: referenceBasicType("UInt64") };
144
+ case DataType.Int64:
145
+ return { dataType, jtype: referenceBasicType("Int64") };
146
+ case DataType.LocalizedText:
147
+ return { dataType, jtype: referenceBasicType("LocalizedText") };
148
+ case DataType.NodeId:
149
+ return { dataType, jtype: referenceBasicType("NodeId") };
150
+ case DataType.ExpandedNodeId:
151
+ return { dataType, jtype: referenceBasicType("ExpandedNodeId") };
152
+ case DataType.QualifiedName:
153
+ return { dataType, jtype: referenceBasicType("QualifiedName") };
154
+ case DataType.SByte:
155
+ return { dataType, jtype: referenceBasicType("SByte") };
156
+ case DataType.StatusCode:
157
+ return { dataType, jtype: referenceBasicType("StatusCode") };
158
+ case DataType.String:
159
+ return { dataType, jtype: referenceBasicType("UAString") };
160
+ case DataType.Variant:
161
+ return { dataType, jtype: referenceBasicType("Variant") };
162
+ case DataType.XmlElement:
163
+ return { dataType, jtype: referenceBasicType("UAString") };
164
+ default:
165
+ throw new Error("Unsupported " + dataType + " " + DataType[dataType]);
166
+ }
167
+ }
168
+
169
+ interface ClassDefinition {
170
+ nodeClass: NodeClass.VariableType | NodeClass.ObjectType;
171
+ browseName: QualifiedName;
172
+ isAbstract: boolean;
173
+ description: LocalizedText;
174
+ //
175
+ superType?: ReferenceDescription;
176
+ baseClassDef?: ClassDefinition | null;
177
+ //
178
+ children: ReferenceDescription[];
179
+ members: ClassMember[];
180
+ //
181
+ interfaceName: Import;
182
+ baseInterfaceName: Import | null;
183
+ // for variables:!
184
+ dataTypeNodeId: NodeId | null;
185
+ dataType: DataType;
186
+ dataTypeName: string;
187
+ dataTypeImport?: Import[];
188
+ }
189
+
190
+ export function makeTypeName2(nodeClass: NodeClass, browseName: QualifiedName, suffix?: string): Import {
191
+ assert(browseName);
192
+ if (nodeClass === NodeClass.Method) {
193
+ return { name: "UAMethod", namespace: 0, module: "UAMethod" };
194
+ }
195
+ return makeTypeNameNew(nodeClass, null, browseName, suffix);
196
+ }
197
+
198
+ export async function extractClassDefinition(session: IBasicSession, nodeId: NodeId, cache: Cache): Promise<ClassDefinition> {
199
+ const extraImports: Import[] = [];
200
+ const _c = (cache as any).classDefCache || {};
201
+ (cache as any).classDefCache = _c;
202
+
203
+ let classDef: ClassDefinition | null = _c[nodeId.toString()];
204
+ if (classDef) {
205
+ return classDef;
206
+ }
207
+ const nodeClass = await getNodeClass(session, nodeId);
208
+ if (nodeClass !== NodeClass.VariableType && nodeClass !== NodeClass.ObjectType) {
209
+ throw new Error("Invalid nodeClass " + NodeClass[nodeClass] + " nodeId " + nodeId.toString());
210
+ }
211
+
212
+ const browseName = await getBrowseName(session, nodeId);
213
+ const isAbstract = await getIsAbstract(session, nodeId);
214
+ const superType = (await getSubtypeNodeIdIfAny(session, nodeId)) || undefined;
215
+
216
+ const dataTypeNodeId = await getDataTypeNodeId(session, nodeId);
217
+ let dataTypeName = "";
218
+ let dataType: DataType = DataType.Null;
219
+ let dataTypeImport: Import[] | undefined = undefined;
220
+ if (nodeClass === NodeClass.VariableType) {
221
+ dataType = await extractBasicDataType(session, dataTypeNodeId!);
222
+ const importCollector = (i: Import) => {
223
+ extraImports.push(i);
224
+ cache.ensureImported(i);
225
+ };
226
+ const { jtype } = await getCorrepondingJavascriptType2(session, nodeId, dataTypeNodeId!, cache, importCollector);
227
+ dataTypeName = jtype; // with decoration
228
+ if (!dataTypeNodeId?.isEmpty()) {
229
+ // "DT" + (await getBrowseName(session, dataTypeNodeId!))?.name! || "";
230
+ // const bn = await getBrowseName(session, dataTypeNodeId!);
231
+ dataTypeImport = extraImports; // makeTypeName2(NodeClass.DataType, bn);
232
+ }
233
+ }
234
+
235
+ const baseClassDef = !superType ? null : await extractClassDefinition(session, superType.nodeId, cache);
236
+
237
+ const description = await getDescription(session, nodeId);
238
+ // const definition = await getDefinition(session, nodeId);
239
+
240
+ const interfaceName: Import = makeTypeName2(nodeClass, browseName);
241
+
242
+ const baseInterfaceName: Import | null = !superType ? null : makeTypeName2(nodeClass, superType.browseName);
243
+
244
+ // extract member
245
+ const children = await getChildrenOrFolderElements(session, nodeId);
246
+
247
+ const members: ClassMember[] = [];
248
+
249
+ classDef = {
250
+ nodeClass,
251
+ browseName,
252
+ isAbstract,
253
+
254
+ dataType,
255
+ dataTypeNodeId,
256
+ dataTypeName,
257
+ dataTypeImport,
258
+
259
+ superType,
260
+
261
+ baseClassDef,
262
+
263
+ description,
264
+ // definition,
265
+ children,
266
+ members,
267
+
268
+ interfaceName,
269
+ baseInterfaceName
270
+ };
271
+ _c[nodeId.toString()] = classDef;
272
+
273
+ for (const child of children) {
274
+ const c = await extractClassMemberDef(session, child.nodeId, classDef, cache);
275
+ classDef.members.push(c);
276
+ }
277
+ return classDef;
278
+ }
279
+
280
+ interface ClassMemberBasic {
281
+ name: string;
282
+ childType: Import;
283
+ isOptional: boolean;
284
+ modellingRule: ModellingRuleType | null;
285
+ description: LocalizedText;
286
+ suffix?: string;
287
+ suffixInstantiate?: string;
288
+ chevrons: any;
289
+ typeToReference: Import[];
290
+ }
291
+
292
+ interface ClassMember extends ClassMemberBasic {
293
+ /**
294
+ * the OPCUA name of the class member
295
+ */
296
+ browseName: QualifiedName;
297
+ nodeClass: NodeClass.Object | NodeClass.Method | NodeClass.Variable;
298
+ /**
299
+ * the Typescript name of the class Member
300
+ */
301
+ name: string;
302
+
303
+ modellingRule: ModellingRuleType | null;
304
+ isOptional: boolean;
305
+
306
+ /**
307
+ * class Def
308
+ */
309
+ classDef: ClassDefinition | null;
310
+
311
+ description: LocalizedText;
312
+ //
313
+ typeDefinition: ReferenceDescription;
314
+
315
+ childType: Import;
316
+
317
+ children: ReferenceDescription[];
318
+ children2: ClassMemberBasic[];
319
+
320
+ // for variables:
321
+ dataTypeNodeId?: NodeId | null;
322
+ dataType?: DataType;
323
+ jtype?: string;
324
+ suffix?: string;
325
+ suffix2?: string;
326
+ suffix3?: string;
327
+ innerClass?: Import | null;
328
+ childBase?: Import | null;
329
+ }
330
+
331
+ interface Classified {
332
+ Mandatory: ReferenceDescription[];
333
+ Optional: ReferenceDescription[];
334
+ MandatoryPlaceholder: ReferenceDescription[];
335
+ OptionalPlaceholder: ReferenceDescription[];
336
+ ExposesItsArray: ReferenceDescription[];
337
+ }
338
+ async function classify(session: IBasicSession, refs: ReferenceDescription[]): Promise<Classified> {
339
+ const r: Classified = {
340
+ Mandatory: [],
341
+ Optional: [],
342
+ MandatoryPlaceholder: [],
343
+ OptionalPlaceholder: [],
344
+ ExposesItsArray: []
345
+ };
346
+
347
+ for (const mm of refs) {
348
+ const modellingRule = await getModellingRule(session, mm.nodeId);
349
+ if (modellingRule) {
350
+ r[modellingRule] = r[modellingRule] || [];
351
+ r[modellingRule].push(mm);
352
+ }
353
+ }
354
+ return r;
355
+ }
356
+
357
+ async function extractAllMembers(session: IBasicSession, classDef: ClassDefinition, cache: Cache) {
358
+ const m = [...classDef.children];
359
+ let s = classDef;
360
+ while (s.baseClassDef) {
361
+ s = s.baseClassDef;
362
+ // start from top most class
363
+ // do not overwrite most top member definition, so we get mandatory stuff
364
+ for (const mm of s.children) {
365
+ const found = m.findIndex((r) => r.browseName.toString() === mm.browseName.toString());
366
+ if (found < 0) {
367
+ m.push(mm);
368
+ }
369
+ }
370
+ }
371
+ // now separate mandatory and optionals
372
+ const members = await classify(session, m);
373
+ return members;
374
+ }
375
+ export async function findClassMember(
376
+ session: IBasicSession,
377
+ browseName: QualifiedName,
378
+ baseParentDef: ClassDefinition,
379
+ cache: Cache
380
+ ): Promise<ClassMember | null> {
381
+ const str = browseName.toString();
382
+ const r = baseParentDef.children.find((a) => a.browseName.toString() === str);
383
+ if (r) {
384
+ const d = await extractClassMemberDef(session, r!.nodeId, baseParentDef, cache);
385
+ return d;
386
+ }
387
+ const baseBaseParentDef =
388
+ baseParentDef.superType && (await extractClassDefinition(session, baseParentDef.superType!.nodeId, cache));
389
+ if (!baseBaseParentDef) {
390
+ return null;
391
+ }
392
+ return await findClassMember(session, browseName, baseBaseParentDef, cache);
393
+ }
394
+ function hasNewMaterial(referenceMembers: ReferenceDescription[], instanceMembers: ReferenceDescription[]) {
395
+ const ref = referenceMembers.map((x) => x.browseName.toString()).sort();
396
+ const instance = instanceMembers.map((x) => x.browseName.toString()).sort();
397
+ for (const n of instance) {
398
+ if (ref.findIndex((x) => x === n) < 0) {
399
+ return true;
400
+ }
401
+ }
402
+ return false;
403
+ }
404
+
405
+ // we should expose an inner definition if
406
+ // - at least one mandatory in instnace doesn't exist in main.Mandatory
407
+ // - at least one optional in instnace doesn't exist in main.Mandatory
408
+ export function checkIfShouldExposeInnerDefinition(main: Classified, instance: Classified): boolean {
409
+ const hasNewStuff = hasNewMaterial(main.Mandatory, instance.Mandatory) || hasNewMaterial(main.Optional, instance.Optional);
410
+ return hasNewStuff;
411
+ }
412
+
413
+ function dump1(a: Classified) {
414
+ console.log(
415
+ "Mandatory = ",
416
+ a.Mandatory.map((x) => x.browseName.toString())
417
+ .sort()
418
+ .join(" ")
419
+ );
420
+ console.log(
421
+ "Optional = ",
422
+ a.Optional.map((x) => x.browseName.toString())
423
+ .sort()
424
+ .join(" ")
425
+ );
426
+ }
427
+
428
+ async function _extractLocalMembers(session: IBasicSession, classMember: ClassMember, cache: Cache): Promise<ClassMemberBasic[]> {
429
+ const children2: ClassMemberBasic[] = [];
430
+ for (const child of classMember.children) {
431
+ const nodeId = child.nodeId;
432
+ const browseName = await getBrowseName(session, nodeId);
433
+ const name = toJavascritPropertyName(browseName.name!);
434
+ if (name === "cartesianCoordinates") {
435
+ // debugger;
436
+ }
437
+ const description = await getDescription(session, nodeId);
438
+ const modellingRule = await getModellingRule(session, nodeId);
439
+ const isOptional = modellingRule === "Optional";
440
+
441
+ const typeDefinition = await getTypeDefOrBaseType(session, nodeId);
442
+
443
+ const childInBase: ClassMember | undefined = classMember.classDef?.members.find(
444
+ (a) => a.browseName.toString() === browseName.toString()
445
+ );
446
+
447
+ let childType: Import;
448
+ if (childInBase) {
449
+ childType = childInBase.childType;
450
+ } else {
451
+ const d = typeDefinition.nodeId.isEmpty() ? null : await extractClassDefinition(session, typeDefinition.nodeId, cache);
452
+ childType = d?.interfaceName || { name: "UAMethod", module: "BasicType", namespace: -1 };
453
+ }
454
+
455
+ // may be childType is already
456
+ const { suffix, suffixInstantiate, typeToReference, chevrons } = await extractVariableExtra(
457
+ session,
458
+ child.nodeId,
459
+ cache,
460
+ classMember
461
+ );
462
+
463
+ const c: ClassMemberBasic = {
464
+ childType,
465
+ description,
466
+ isOptional,
467
+ modellingRule,
468
+ name,
469
+ suffix,
470
+ suffixInstantiate,
471
+ typeToReference,
472
+ chevrons
473
+ };
474
+ children2.push(c);
475
+ }
476
+ return children2;
477
+ }
478
+ function isUnspecifiedDataType(dataType?: DataType): boolean {
479
+ return dataType === DataType.Null || dataType === DataType.Variant;
480
+ }
481
+ async function extractVariableExtra(session: IBasicSession, nodeId: NodeId, cache: Cache, classMember: ClassMember) {
482
+ const typeToReference: Import[] = [];
483
+ const importCollector = (i: Import) => {
484
+ typeToReference.push(i);
485
+ cache.ensureImported(i);
486
+ };
487
+ const nodeClass = await getNodeClass(session, nodeId);
488
+ if (nodeClass === NodeClass.Variable) {
489
+ const dataTypeNodeId = await getDataTypeNodeId(session, nodeId);
490
+
491
+ const { dataType, jtype } = await getCorrepondingJavascriptType2(session, nodeId, dataTypeNodeId!, cache, importCollector);
492
+
493
+ cache && cache.referenceBasicType("DataType");
494
+ importCollector({ name: "DataType", namespace: -1, module: "BasicType" });
495
+
496
+ const t = isUnspecifiedDataType(classMember.classDef?.dataType);
497
+ const suffix =
498
+ jtype === "undefined" || isUnspecifiedDataType(dataType)
499
+ ? `<any, any>`
500
+ : `<${jtype}${t ? `, /*c*/DataType.${DataType[dataType]}` : ""}>`;
501
+
502
+ // const suffix2 = `<T${t ? `, /*a*/DT extends DataType` : ""}>`;
503
+ const suffix3 = `<T${t ? `, /*b*/DT` : ""}>`;
504
+
505
+ const typeDef = await getTypeDefOrBaseType(session, nodeId);
506
+ const typeDefCD = await extractClassDefinition(session, typeDef.nodeId!, cache);
507
+ const chevrons = calculateChevrons(typeDefCD, { dataType });
508
+ const suffix2 = chevrons.chevronsDef;
509
+
510
+ /** Suffix for instantiation
511
+ * if typeDef.dataType is not null, then we need to add a type argument
512
+ */
513
+ let suffixInstantiate = "";
514
+ if (isUnspecifiedDataType(dataType)) {
515
+ if (!isUnspecifiedDataType(typeDefCD.dataType)) {
516
+ suffixInstantiate = "<any>";
517
+ } else {
518
+ suffixInstantiate = "<any, any>";
519
+ }
520
+ } else {
521
+ if (!isUnspecifiedDataType(typeDefCD.dataType)) {
522
+ suffixInstantiate = `<${jtype}>`;
523
+ } else {
524
+ suffixInstantiate = `<${jtype}, /*z*/DataType.${DataType[dataType]}>`;
525
+ }
526
+ }
527
+
528
+ return { suffixInstantiate, suffix, suffix2, suffix3, dataTypeNodeId, dataType, jtype, typeToReference, chevrons };
529
+ }
530
+ return { suffix: "", typeToReference };
531
+ }
532
+
533
+ interface ClassDefinitionB {
534
+ superType?: {
535
+ nodeId: NodeId;
536
+ };
537
+ interfaceName: Import;
538
+ }
539
+ // eslint-disable-next-line max-statements
540
+ export async function extractClassMemberDef(
541
+ session: IBasicSession,
542
+ nodeId: NodeId,
543
+ parentDef: ClassDefinitionB,
544
+ cache: Cache
545
+ ): Promise<ClassMember> {
546
+ const nodeClass = await getNodeClass(session, nodeId);
547
+ const browseName = await getBrowseName(session, nodeId);
548
+ const name = toJavascritPropertyName(browseName.name!);
549
+
550
+ if (nodeClass !== NodeClass.Method && nodeClass !== NodeClass.Object && nodeClass !== NodeClass.Variable) {
551
+ throw new Error("Invalid property " + NodeClass[nodeClass] + " " + browseName?.toString() + " " + nodeId.toString());
552
+ }
553
+
554
+ const description = await getDescription(session, nodeId);
555
+ const children = await getChildrenOrFolderElements(session, nodeId);
556
+
557
+ const modellingRule = await getModellingRule(session, nodeId);
558
+ const isOptional = modellingRule === "Optional";
559
+
560
+ const typeDefinition = await getTypeDefOrBaseType(session, nodeId);
561
+
562
+ if (!typeDefinition.browseName) {
563
+ console.log("cannot find typeDefinition for ", browseName.toString(), "( is the namespace loaded ?)");
564
+ }
565
+ let childType = makeTypeName2(nodeClass, typeDefinition.browseName);
566
+
567
+ const classDef = typeDefinition.nodeId.isEmpty() ? null : await extractClassDefinition(session, typeDefinition.nodeId, cache);
568
+
569
+ let innerClass: Import | null = null;
570
+ let childBase: Import | null = null;
571
+
572
+ let shouldExposeInnerDefinition = false;
573
+ // find member exposed by type definition
574
+ const baseParentDef = parentDef.superType && (await extractClassDefinition(session, parentDef.superType!.nodeId, cache));
575
+ if (classDef && baseParentDef) {
576
+ const chevrons1 = calculateChevrons(classDef, baseParentDef);
577
+ assert(!innerClass);
578
+
579
+ // let's extract the member that are theorically defined in the member
580
+ const membersReference = await extractAllMembers(session, classDef, cache);
581
+ // find member exposed by this member
582
+ const membersInstance: Classified = await classify(session, children);
583
+
584
+ // if (name==="powerup") {
585
+ // dump1(membersReference);
586
+ // dump1(membersInstance);
587
+ // await extractAllMembers(session, classDef, cache);
588
+ // }
589
+
590
+ shouldExposeInnerDefinition = checkIfShouldExposeInnerDefinition(membersReference, membersInstance);
591
+
592
+ const sameMemberInBaseClass = baseParentDef && (await findClassMember(session, browseName, baseParentDef, cache));
593
+
594
+ if (shouldExposeInnerDefinition) {
595
+ if (sameMemberInBaseClass) {
596
+ innerClass = {
597
+ module: parentDef.interfaceName.module,
598
+ name: parentDef.interfaceName.name + "_" + name,
599
+ namespace: nodeId.namespace
600
+ };
601
+ childBase = sameMemberInBaseClass.childType;
602
+ childType = innerClass;
603
+ } else {
604
+ innerClass = {
605
+ module: parentDef.interfaceName.module,
606
+ name: parentDef.interfaceName.name + "_" + name,
607
+ namespace: nodeId.namespace
608
+ };
609
+ childBase = childType;
610
+ childType = innerClass;
611
+ }
612
+ assert(innerClass);
613
+ assert(childBase);
614
+ } else {
615
+ // may not expose definition but we may want to used the augment typescript class defined in the definition
616
+ // we don't need to create an inner class ...
617
+ childType = sameMemberInBaseClass ? sameMemberInBaseClass?.childType : childType;
618
+ assert(!innerClass);
619
+ assert(!childBase);
620
+ }
621
+ } else {
622
+ // the lass member has no HasTypeDefinition reference
623
+ // may be is a method
624
+ assert(!innerClass);
625
+ assert(!childBase);
626
+ }
627
+
628
+ let classMember: ClassMember = {
629
+ name,
630
+ nodeClass,
631
+ browseName,
632
+ modellingRule,
633
+ isOptional,
634
+ classDef,
635
+ description,
636
+ typeDefinition,
637
+ childType,
638
+ suffix2: "",
639
+ suffix: "",
640
+ suffix3: "",
641
+ suffixInstantiate: "",
642
+ children,
643
+ children2: [],
644
+
645
+ typeToReference: [],
646
+ //
647
+ innerClass,
648
+ childBase,
649
+ chevrons: null
650
+ };
651
+ classMember.children2 = await _extractLocalMembers(session, classMember, cache);
652
+ if (nodeClass === NodeClass.Variable) {
653
+ const extra = await extractVariableExtra(session, nodeId, cache, classMember);
654
+ classMember = {
655
+ ...classMember,
656
+ ...extra
657
+ };
658
+ }
659
+
660
+ return classMember;
661
+ }
662
+
663
+ async function preDumpChildren(session: IBasicSession, padding: string, classDef: ClassDefinition, f: LineFile, cache: Cache) {
664
+ f = f || new LineFile();
665
+
666
+ for (const memberDef of classDef.members) {
667
+ const { innerClass, suffix2, suffix3, nodeClass, childBase, chevrons } = memberDef;
668
+ if (!innerClass || !childBase) {
669
+ continue; // no need to expose inner class
670
+ }
671
+ cache.ensureImported(childBase);
672
+ if (innerClass.name === "UAPubSubDiagnostics_counters" || innerClass.name === "UAProgramStateMachine_currentState") {
673
+ // debugger;
674
+ }
675
+ const baseStuff = getBaseClassWithOmit2(memberDef);
676
+
677
+ //f.write(`export interface ${innerClass.name}${suffix2} extends ${childBase.name}${suffix3} { // ${NodeClass[nodeClass]}`);
678
+ f.write(`export interface ${innerClass.name}${suffix2} extends ${baseStuff} { // ${NodeClass[nodeClass]}`);
679
+ await dumpChildren(session, padding + " ", memberDef.children2, f, cache);
680
+ f.write("}");
681
+ }
682
+ }
683
+
684
+ function dumpChildren(session: IBasicSession, padding: string, children: ClassMemberBasic[], f: LineFile, cache: Cache): void {
685
+ f = f || new LineFile();
686
+
687
+ for (const def of children) {
688
+ const { suffixInstantiate, name, childType, modellingRule, isOptional, description } = def;
689
+ def.typeToReference.forEach((t) => cache.ensureImported(t));
690
+
691
+ if (modellingRule === "MandatoryPlaceholder" || modellingRule === "OptionalPlaceholder") continue;
692
+ cache.ensureImported(childType);
693
+ const adjustedName = toJavascritPropertyName(name);
694
+ if (description.text) {
695
+ f.write(`${padding}/**`);
696
+ f.write(`${padding} * ${name || ""}`);
697
+ f.write(toComment(`${padding} * `, description.text || ""));
698
+ f.write(`${padding} */`);
699
+ }
700
+ f.write(
701
+ `${padding}${quotifyIfNecessary(adjustedName)}${isOptional ? "?" : ""}: ${childType.name}${suffixInstantiate || ""};`
702
+ );
703
+ }
704
+ }
705
+ // now from other namespace
706
+ const getSubSymbolList = (s: RequestedSubSymbol) => {
707
+ const subSymbolList: string[] = [];
708
+ for (const [subSymbol, count] of Object.entries(s.subSymbols)) {
709
+ subSymbolList.push(subSymbol);
710
+ }
711
+ return subSymbolList;
712
+ };
713
+ export function findUsedImport(namespaceIndex: number, cache: Cache): string[] {
714
+ const usedImport: string[] = [];
715
+ // from standard types
716
+ for (const imp of Object.keys(cache.imports)) {
717
+ const symbolToImport = Object.keys(cache.imports[imp]).filter((f) =>
718
+ Object.prototype.hasOwnProperty.call(cache.requestedBasicTypes, f)
719
+ );
720
+ if (symbolToImport.length == 0) {
721
+ continue;
722
+ }
723
+ usedImport.push(imp);
724
+ }
725
+
726
+ // from namespace
727
+ for (let ns = 0; ns < cache.requestedSymbols.namespace.length; ns++) {
728
+ if (ns === namespaceIndex) {
729
+ continue; // avoid self reference
730
+ }
731
+ const module = cache.namespace[ns].module;
732
+ if (cache.requestedSymbols.namespace[ns] && Object.values(cache.requestedSymbols.namespace[ns]).length > 0) {
733
+ usedImport.push(module);
734
+ }
735
+ }
736
+
737
+ return usedImport;
738
+ }
739
+
740
+ function dumpUsedExport(currentType: string, namespaceIndex: number, cache: Cache, f?: LineFile): string {
741
+ f = f || new LineFile();
742
+
743
+ for (const imp of Object.keys(cache.imports)) {
744
+ const symbolToImport = Object.keys(cache.imports[imp]).filter(
745
+ (f) => f !== currentType && Object.prototype.hasOwnProperty.call(cache.requestedBasicTypes, f)
746
+ );
747
+ if (symbolToImport.length == 0) {
748
+ continue;
749
+ }
750
+ f.write(`import { ${symbolToImport.join(", ")} } from "${imp}"`);
751
+ }
752
+ for (let ns = 0; ns < cache.requestedSymbols.namespace.length; ns++) {
753
+ const n = cache.namespace[ns];
754
+ const sourceFolder = n.sourceFolder;
755
+ const module = n.module;
756
+ if (ns === namespaceIndex) {
757
+ // include individuals stuff
758
+ for (const [symbol, s] of Object.entries(cache.requestedSymbols.namespace[ns].symbols).filter(
759
+ (a) => a[0] !== currentType
760
+ )) {
761
+ const filename = toFilename(symbol);
762
+ const subSymbolList = getSubSymbolList(s);
763
+ f.write(`import { ${subSymbolList.join(", ")} } from "./${filename}"`);
764
+ }
765
+ } else {
766
+ if (cache.requestedSymbols.namespace[ns]) {
767
+ for (const [symbol, s] of Object.entries(cache.requestedSymbols.namespace[ns].symbols)) {
768
+ const subSymbolList = getSubSymbolList(s);
769
+ const filename = toFilename(symbol);
770
+ f.write(`import { ${subSymbolList.join(", ")} } from "${module}/source/${filename}"`);
771
+ }
772
+ }
773
+ }
774
+ }
775
+ return f.toString();
776
+ }
777
+
778
+ function toComment(prefix: string, description: string) {
779
+ const d = wrapText(description);
780
+ return d
781
+ .split("\n")
782
+ .map((x) => prefix + x)
783
+ .join("\n");
784
+ }
785
+ export type Type = "enum" | "basic" | "structure" | "ua";
786
+ // eslint-disable-next-line max-statements
787
+ export async function _exportDataTypeToTypescript(
788
+ session: IBasicSession,
789
+ nodeId: NodeId,
790
+ cache: Cache,
791
+ f?: LineFile
792
+ ): Promise<{ type: Type; content: string; typeName: string }> {
793
+ f = f || new LineFile();
794
+
795
+ const importCollector = (i: Import) => {
796
+ cache.ensureImported(i);
797
+ };
798
+ const nodeClass = NodeClass.DataType;
799
+ const description = await getDescription(session, nodeId);
800
+ const definition = await getDefinition(session, nodeId);
801
+ const browseName = await getBrowseName(session, nodeId);
802
+ const isAbstract = await getIsAbstract(session, nodeId);
803
+
804
+ const interfaceImport: Import = makeTypeNameNew(nodeClass, definition, browseName);
805
+ const interfaceName = interfaceImport.name;
806
+
807
+ const superType = await getSubtypeNodeId(session, nodeId);
808
+ const baseInterfaceImport: Import = makeTypeNameNew(nodeClass, definition, superType.browseName);
809
+
810
+ cache.ensureImported(baseInterfaceImport);
811
+
812
+ const baseInterfaceName = baseInterfaceImport.name;
813
+ // f.write(superType.toString());
814
+ f.write(`/**`);
815
+ if (description.text) {
816
+ f.write(toComment(" * ", description.text || ""));
817
+ f.write(` *`);
818
+ }
819
+ f.write(` * | |${f1(" ")}|`);
820
+ f.write(` * |-----------|${f2("-")}|`);
821
+ f.write(` * | namespace |${f1(cache.namespace[nodeId.namespace].namespaceUri)}|`);
822
+ f.write(` * | nodeClass |${f1(NodeClass[nodeClass])}|`);
823
+ f.write(` * | name |${f1(browseName.toString())}|`);
824
+ f.write(` * | isAbstract|${f1(isAbstract.toString())}|`);
825
+ f.write(` */`);
826
+
827
+ let type: "basic" | "structure" | "enum" | "ua" = "basic";
828
+ if (definition instanceof EnumDefinition) {
829
+ type = "enum";
830
+ f.write(`export enum ${interfaceName} {`);
831
+ for (const field of definition.fields!) {
832
+ if (field.description.text) {
833
+ f.write(` /**`);
834
+ f.write(toComment(" * ", field.description.text || ""));
835
+ f.write(` */`);
836
+ }
837
+ f.write(` ${quotifyIfNecessary(field.name!)} = ${field.value[1]},`);
838
+ }
839
+ f.write(`}`);
840
+ } else if (definition instanceof StructureDefinition) {
841
+ type = "structure";
842
+ if (interfaceName === "DTStructure") {
843
+ f.write(`export interface ${interfaceName} {`);
844
+ } else {
845
+ f.write(`export interface ${interfaceName} extends ${baseInterfaceName} {`);
846
+ }
847
+ for (const field of definition.fields!) {
848
+ const fieldName = toJavascritPropertyName(field.name!);
849
+ // special case ! fieldName=
850
+ if (field.description.text) {
851
+ f.write(`/** ${field.description.text}*/`);
852
+ }
853
+ let ar = "";
854
+ if (field.valueRank >= 1) {
855
+ ar = "[]";
856
+ }
857
+ const { dataType, jtype } = await getCorrepondingJavascriptType(session, field.dataType, cache, importCollector);
858
+ f.write(` ${quotifyIfNecessary(fieldName)}: ${jtype}${ar}; // ${DataType[dataType]} ${field.dataType.toString()}`);
859
+ }
860
+ f.write(`}`);
861
+ } else {
862
+ type = "basic";
863
+ f.write(`// NO DEFINITION`);
864
+ f.write(`export interface ${interfaceName} extends ${baseInterfaceName} {`);
865
+ f.write(`}`);
866
+ // throw new Error("Invalid " + definition?.constructor.name);
867
+ }
868
+ return { type, content: f.toString(), typeName: interfaceName };
869
+ }
870
+
871
+ function calculateChevrons(classDef: ClassDefinition, classDefDerived?: { dataType: DataType }) {
872
+ const { nodeClass, dataType, dataTypeName } = classDef;
873
+ let chevronsDef = "";
874
+ let chevronsUse = "";
875
+ let chevronsExtend = "";
876
+ if (nodeClass !== NodeClass.VariableType) {
877
+ return { chevronsDef, chevronsUse, chevronsExtend };
878
+ }
879
+
880
+ if (!isUnspecifiedDataType(dataType)) {
881
+ chevronsDef = `<T extends ${dataTypeName}/*j*/>`;
882
+ chevronsUse = "<T/*k*/>";
883
+ if (classDefDerived) {
884
+ if (isUnspecifiedDataType(classDefDerived.dataType)) {
885
+ chevronsExtend = `<T, /*i*/DataType.${DataType[dataType]}>`;
886
+ } else {
887
+ chevronsExtend = `<T/*h*/>`;
888
+ }
889
+ }
890
+ } else {
891
+ // classDef.dataType === DataType.Null
892
+ chevronsDef = `<T, DT extends DataType>`;
893
+ if (classDefDerived) {
894
+ if (isUnspecifiedDataType(classDefDerived.dataType)) {
895
+ chevronsUse = "<T, /*m*/DT>";
896
+ chevronsExtend = `<T/*g*/, DT>`;
897
+ } else {
898
+ chevronsUse = `<T, /*n*/DataType.${DataType[classDefDerived.dataType]}>`;
899
+ chevronsExtend = `<T, /*e*/DataType.${DataType[classDefDerived.dataType]}>`;
900
+ }
901
+ }
902
+ }
903
+
904
+ return { chevronsDef, chevronsUse, chevronsExtend };
905
+ }
906
+ // find the structure member that are already in base structure definition and that are replicated here
907
+ // we will have to use the Omit<Base,"member1" |"member2"> typescript pattern to avoid issues
908
+ function extractMembersRecursively(classDef?: ClassDefinition | null): string[] {
909
+ if (!classDef) {
910
+ return [];
911
+ }
912
+ const m = classDef.members.map((m) => m.name);
913
+ if (classDef.baseClassDef) {
914
+ const m2 = extractMembersRecursively(classDef.baseClassDef);
915
+ return m.concat(m2);
916
+ }
917
+ return m;
918
+ }
919
+ function getBaseClassWithOmit(classDef: ClassDefinition) {
920
+ const { baseInterfaceName, members } = classDef;
921
+
922
+ const allMembers = extractMembersRecursively(classDef.baseClassDef);
923
+ const conflictingMembers = members.filter((m) => allMembers.indexOf(m.name) !== -1);
924
+ //console.log(allMembers.join(" "));
925
+ if (conflictingMembers.length) {
926
+ // console.log("conflictingMembers = ", conflictingMembers.map((a) => a.name).join(" "));
927
+ }
928
+ const chBase = calculateChevrons(classDef.baseClassDef!, classDef);
929
+
930
+ let baseStuff = `${baseInterfaceName?.name}${chBase.chevronsUse}`;
931
+ if (conflictingMembers.length) {
932
+ baseStuff = `Omit<${baseStuff}, ${conflictingMembers.map((a) => `"${a.name}"`).join("|")}>`;
933
+ }
934
+ return baseStuff;
935
+ }
936
+ function getBaseClassWithOmit2(classMember: ClassMember) {
937
+ const members = classMember.children2;
938
+ const allMembers = extractMembersRecursively(classMember.classDef);
939
+ const conflictingMembers = members.filter((m) => allMembers.indexOf(m.name) !== -1);
940
+ //console.log(allMembers.join(" "));
941
+ if (conflictingMembers.length) {
942
+ console.log("conflictingMembers = ", conflictingMembers.map((a) => a.name).join(" "));
943
+ }
944
+ const childBase = classMember.childBase;
945
+
946
+ let baseStuff = `${childBase?.name}${classMember.suffix3}`;
947
+ if (conflictingMembers.length) {
948
+ baseStuff = `Omit<${baseStuff}, ${conflictingMembers.map((a) => `"${a.name}"`).join("|")}>`;
949
+ }
950
+ return baseStuff;
951
+ }
952
+ /**
953
+ * nodeId : a DataType, ReferenceType,AObjectType, VariableType node
954
+ */
955
+ // eslint-disable-next-line max-statements
956
+ export async function _convertTypeToTypescript(
957
+ session: IBasicSession,
958
+ nodeId: NodeId,
959
+ cache: Cache,
960
+ f?: LineFile
961
+ ): Promise<{ type: Type; content: string; typeName: string }> {
962
+ f = f || new LineFile();
963
+
964
+ const nodeClass = await getNodeClass(session, nodeId);
965
+ if (nodeClass === NodeClass.DataType) {
966
+ return await _exportDataTypeToTypescript(session, nodeId, cache, f);
967
+ }
968
+
969
+ const classDef = await extractClassDefinition(session, nodeId, cache);
970
+ // if (classDef.browseName.toString().match(/PubSubDiagnosticsWriterGroupType/)) {
971
+ // debugger;
972
+ // }
973
+ const {
974
+ dataTypeName,
975
+ dataType,
976
+ dataTypeNodeId,
977
+ interfaceName,
978
+ baseInterfaceName,
979
+ browseName,
980
+ description,
981
+ isAbstract,
982
+ members
983
+ } = classDef;
984
+
985
+ await preDumpChildren(session, " ", classDef, f, cache);
986
+
987
+ // f.write(superType.toString());
988
+ f.write(`/**`);
989
+ if (description.text) {
990
+ f.write(toComment(" * ", description.text || ""));
991
+ f.write(` *`);
992
+ }
993
+ f.write(` * | |${f1(" ")}|`);
994
+ f.write(` * |----------------|${f2("-")}|`);
995
+ f.write(` * |namespace |${f1(cache.namespace[nodeId.namespace].namespaceUri)}|`);
996
+ f.write(` * |nodeClass |${f1(NodeClass[nodeClass])}|`);
997
+ f.write(` * |typedDefinition |${f1(browseName.toString() + " " + nodeId.toString())}|`);
998
+ if (nodeClass === NodeClass.VariableType) {
999
+ f.write(` * |dataType |${f1(DataType[dataType])}|`);
1000
+ f.write(` * |dataType Name |${f1(dataTypeName + " " + dataTypeNodeId?.toString())}|`);
1001
+ }
1002
+ f.write(` * |isAbstract |${f1(isAbstract.toString())}|`);
1003
+ f.write(` */`);
1004
+
1005
+ // if (interfaceName.name === "UAOperationLimits") {
1006
+ // debugger;
1007
+ // }
1008
+ cache.ensureImported(baseInterfaceName!);
1009
+ cache.ensureImported({ ...baseInterfaceName!, name: baseInterfaceName!.name + `${baseExtension}` });
1010
+
1011
+ const ch = calculateChevrons(classDef);
1012
+
1013
+ if (nodeClass === NodeClass.VariableType) {
1014
+ if (classDef.dataTypeImport) {
1015
+ console.log(chalk.red(" ----------------> ", classDef.browseName));
1016
+ classDef.dataTypeImport.forEach((a) => {
1017
+ console.log(chalk.red(" ------------------------> ", a.module, a.name, a.namespace));
1018
+ });
1019
+ classDef.dataTypeImport.forEach(cache.ensureImported.bind(cache));
1020
+ }
1021
+
1022
+ cache.referenceBasicType("DataType");
1023
+ const chevrons = calculateChevrons(classDef);
1024
+ const chevronsBase = calculateChevrons(classDef.baseClassDef!, classDef);
1025
+ // Shall we cache.ensureImported({ ...baseInterfaceName!, module: dataTypeName, name: dataTypeName });
1026
+ const classBaseName = `${interfaceName.name}${baseExtension}${chevrons.chevronsDef}`;
1027
+
1028
+ if (baseInterfaceName?.name === "UAVariableT") {
1029
+ f.write(`export interface ${classBaseName} {`);
1030
+ } else {
1031
+ const baseName = `${baseInterfaceName?.name}${baseExtension}${chevronsBase.chevronsExtend}`;
1032
+ f.write(`export interface ${classBaseName} extends ${baseName} {`);
1033
+ }
1034
+ } else {
1035
+ const classBaseName = `${interfaceName.name}${baseExtension}`;
1036
+ if (baseInterfaceName?.name === "UAObject") {
1037
+ f.write(`export interface ${classBaseName} {`);
1038
+ } else {
1039
+ const baseName = `${baseInterfaceName?.name}${baseExtension}`;
1040
+ f.write(`export interface ${classBaseName} extends ${baseName} {`);
1041
+ }
1042
+ }
1043
+ await dumpChildren(session, " ", members, f, cache);
1044
+ f.write(`}`);
1045
+
1046
+ const baseStuff = getBaseClassWithOmit(classDef);
1047
+
1048
+ if (nodeClass === NodeClass.VariableType) {
1049
+ cache.referenceBasicType("DataType");
1050
+ // if dataType is a extension object we can simpligy by forcing DT
1051
+ const className = `${interfaceName.name}${ch.chevronsDef}`;
1052
+ const c = isUnspecifiedDataType(dataType) ? "<T, DT /*A*/>" : "<T /*B*/>";
1053
+ const classBaseName = `${interfaceName.name}${baseExtension}${c}`;
1054
+ f.write(`export interface ${className} extends ${baseStuff}, ${classBaseName} {`);
1055
+ } else {
1056
+ const className = `${interfaceName.name}`;
1057
+ const classBaseName = `${interfaceName.name}${baseExtension}`;
1058
+ f.write(`export interface ${className} extends ${baseStuff}, ${classBaseName} {`);
1059
+ }
1060
+ f.write(`}`);
1061
+ return { type: "ua", content: f.toString(), typeName: interfaceName.name };
1062
+ }
1063
+
1064
+ export async function convertTypeToTypescript(
1065
+ session: IBasicSession,
1066
+ nodeId: NodeId,
1067
+ options: Options,
1068
+ cache?: Cache,
1069
+ f?: LineFile
1070
+ ): Promise<{
1071
+ type: Type;
1072
+ content: string;
1073
+ module: string;
1074
+ folder: string;
1075
+ filename: string;
1076
+ dependencies: string[];
1077
+ }> {
1078
+ f = new LineFile();
1079
+
1080
+ cache = cache || (await constructCache(session, options));
1081
+
1082
+ const { type, content, typeName } = await _convertTypeToTypescript(session, nodeId, cache);
1083
+
1084
+ f.write(`// ----- this file has been automatically generated - do not edit`);
1085
+ f.write(dumpUsedExport(typeName, nodeId.namespace, cache));
1086
+ f.write(content);
1087
+
1088
+ const folder = cache.namespace[nodeId.namespace].sourceFolder;
1089
+ const module = cache.namespace[nodeId.namespace].module;
1090
+ const filename = toFilename(typeName);
1091
+
1092
+ const dependencies = findUsedImport(nodeId.namespace, cache);
1093
+
1094
+ return { type, content: f.toString(), folder, module, filename, dependencies };
1095
+ }