@effect-opcua/codegen 0.1.0-alpha.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 (102) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +6 -0
  3. package/dist/cli.d.mts +1 -0
  4. package/dist/cli.mjs +82 -0
  5. package/dist/cli.mjs.map +1 -0
  6. package/dist/client/src/Opcua.d.mts +5 -0
  7. package/dist/client/src/OpcuaClient.d.mts +3 -0
  8. package/dist/client/src/OpcuaError.d.mts +139 -0
  9. package/dist/client/src/OpcuaError.d.mts.map +1 -0
  10. package/dist/client/src/OpcuaMethod.d.mts +78 -0
  11. package/dist/client/src/OpcuaMethod.d.mts.map +1 -0
  12. package/dist/client/src/OpcuaSession.d.mts +215 -0
  13. package/dist/client/src/OpcuaSession.d.mts.map +1 -0
  14. package/dist/client/src/OpcuaSubscription.d.mts +144 -0
  15. package/dist/client/src/OpcuaSubscription.d.mts.map +1 -0
  16. package/dist/client/src/OpcuaVariable.d.mts +140 -0
  17. package/dist/client/src/OpcuaVariable.d.mts.map +1 -0
  18. package/dist/client/src/index.d.mts +7 -0
  19. package/dist/client/src/internal/common/node-id.d.mts +1 -0
  20. package/dist/client/src/internal/events/model.d.mts +51 -0
  21. package/dist/client/src/internal/events/model.d.mts.map +1 -0
  22. package/dist/client/src/internal/monitoring/runtime.d.mts +7 -0
  23. package/dist/client/src/internal/structures/model.d.mts +18 -0
  24. package/dist/client/src/internal/structures/model.d.mts.map +1 -0
  25. package/dist/client/src/internal/structures/runtime.d.mts +5 -0
  26. package/dist/client/src/internal/values/codec.d.mts +21 -0
  27. package/dist/client/src/internal/values/codec.d.mts.map +1 -0
  28. package/dist/client/src/internal/values/normalize.d.mts +2 -0
  29. package/dist/client/src/node-opcua.d.mts +2 -0
  30. package/dist/compile/builtin-types.d.mts +10 -0
  31. package/dist/compile/builtin-types.d.mts.map +1 -0
  32. package/dist/compile/builtin-types.mjs +38 -0
  33. package/dist/compile/builtin-types.mjs.map +1 -0
  34. package/dist/compile/enums.d.mts +16 -0
  35. package/dist/compile/enums.d.mts.map +1 -0
  36. package/dist/compile/enums.mjs +81 -0
  37. package/dist/compile/enums.mjs.map +1 -0
  38. package/dist/compile/model.d.mts +10 -0
  39. package/dist/compile/model.d.mts.map +1 -0
  40. package/dist/compile/model.mjs +92 -0
  41. package/dist/compile/model.mjs.map +1 -0
  42. package/dist/compile/names.d.mts +17 -0
  43. package/dist/compile/names.d.mts.map +1 -0
  44. package/dist/compile/names.mjs +95 -0
  45. package/dist/compile/names.mjs.map +1 -0
  46. package/dist/compile/policy.d.mts +7 -0
  47. package/dist/compile/policy.d.mts.map +1 -0
  48. package/dist/compile/policy.mjs +6 -0
  49. package/dist/compile/policy.mjs.map +1 -0
  50. package/dist/compile/structures.d.mts +16 -0
  51. package/dist/compile/structures.d.mts.map +1 -0
  52. package/dist/compile/structures.mjs +220 -0
  53. package/dist/compile/structures.mjs.map +1 -0
  54. package/dist/compile/type-graph.d.mts +20 -0
  55. package/dist/compile/type-graph.d.mts.map +1 -0
  56. package/dist/compile/type-graph.mjs +78 -0
  57. package/dist/compile/type-graph.mjs.map +1 -0
  58. package/dist/compile/variables.d.mts +16 -0
  59. package/dist/compile/variables.d.mts.map +1 -0
  60. package/dist/compile/variables.mjs +110 -0
  61. package/dist/compile/variables.mjs.map +1 -0
  62. package/dist/compile.d.mts +9 -0
  63. package/dist/compile.d.mts.map +1 -0
  64. package/dist/compile.mjs +29 -0
  65. package/dist/compile.mjs.map +1 -0
  66. package/dist/config.d.mts +12 -0
  67. package/dist/config.d.mts.map +1 -0
  68. package/dist/config.mjs +158 -0
  69. package/dist/config.mjs.map +1 -0
  70. package/dist/diagnostics.d.mts +16 -0
  71. package/dist/diagnostics.d.mts.map +1 -0
  72. package/dist/diagnostics.mjs +45 -0
  73. package/dist/diagnostics.mjs.map +1 -0
  74. package/dist/discover.d.mts +23 -0
  75. package/dist/discover.d.mts.map +1 -0
  76. package/dist/discover.mjs +356 -0
  77. package/dist/discover.mjs.map +1 -0
  78. package/dist/emit.d.mts +8 -0
  79. package/dist/emit.d.mts.map +1 -0
  80. package/dist/emit.mjs +233 -0
  81. package/dist/emit.mjs.map +1 -0
  82. package/dist/errors.d.mts +27 -0
  83. package/dist/errors.d.mts.map +1 -0
  84. package/dist/errors.mjs +18 -0
  85. package/dist/errors.mjs.map +1 -0
  86. package/dist/generate.d.mts +19 -0
  87. package/dist/generate.d.mts.map +1 -0
  88. package/dist/generate.mjs +172 -0
  89. package/dist/generate.mjs.map +1 -0
  90. package/dist/index.d.mts +5 -0
  91. package/dist/index.mjs +5 -0
  92. package/dist/internal/types.d.mts +192 -0
  93. package/dist/internal/types.d.mts.map +1 -0
  94. package/dist/internal/types.mjs +1 -0
  95. package/dist/issue-codes.d.mts +119 -0
  96. package/dist/issue-codes.d.mts.map +1 -0
  97. package/dist/issue-codes.mjs +44 -0
  98. package/dist/issue-codes.mjs.map +1 -0
  99. package/dist/types.d.mts +57 -0
  100. package/dist/types.d.mts.map +1 -0
  101. package/dist/types.mjs +1 -0
  102. package/package.json +58 -0
@@ -0,0 +1,2 @@
1
+ import { OpcuaDynamicValue, OpcuaExpandedNodeIdInfo, OpcuaLocalizedTextInfo, OpcuaNodeIdInfo, OpcuaQualifiedNameInfo, OpcuaStatusInfo, OpcuaVariantInfo } from "../../OpcuaVariable.mjs";
2
+ import { StatusCode, Variant } from "node-opcua";
@@ -0,0 +1,2 @@
1
+ import { OPCUAClientOptions, UserIdentityInfo } from "node-opcua";
2
+ export { type OPCUAClientOptions, type UserIdentityInfo };
@@ -0,0 +1,10 @@
1
+ import { ScalarSchema } from "../internal/types.mjs";
2
+
3
+ //#region src/compile/builtin-types.d.ts
4
+ declare const scalarSchema: (dataTypeNodeId: string | undefined) => ScalarSchema | undefined;
5
+ declare const isDynamicScalarDataType: (dataTypeNodeId: string | undefined) => boolean;
6
+ declare const requiresDataTypeDefinition: (dataTypeNodeId: string | undefined) => dataTypeNodeId is string;
7
+ declare const isUnsupportedArrayRank: (valueRank: number | undefined) => boolean;
8
+ //#endregion
9
+ export { isDynamicScalarDataType, isUnsupportedArrayRank, requiresDataTypeDefinition, scalarSchema };
10
+ //# sourceMappingURL=builtin-types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-types.d.mts","names":[],"sources":["../../src/compile/builtin-types.ts"],"sourcesContent":[],"mappings":";;;cAmBa,sDAEV;cAiBU;AAnBA,cA0BA,0BAxBE,EAAA,CAAA,cAAA,EAAA,MAAA,GAAA,SAAA,EAAA,GAAA,cAAA,IAAA,MAAA;AAiBF,cAeA,sBAVZ,EAAA,CAAA,SAAA,EAAA,MAAA,GAAA,SAAA,EAAA,GAAA,OAAA"}
@@ -0,0 +1,38 @@
1
+ //#region src/compile/builtin-types.ts
2
+ const numericDataTypeNodeIds = new Set([
3
+ "i=2",
4
+ "i=3",
5
+ "i=4",
6
+ "i=5",
7
+ "i=6",
8
+ "i=7",
9
+ "i=10",
10
+ "i=11",
11
+ "i=26",
12
+ "i=27",
13
+ "i=28",
14
+ "i=29"
15
+ ]);
16
+ const dynamicScalarDataTypeNodeIds = new Set(["i=8", "i=9"]);
17
+ const scalarSchema = (dataTypeNodeId) => {
18
+ const normalized = normalizeNamespaceZeroNodeId(dataTypeNodeId);
19
+ switch (normalized) {
20
+ case "i=1": return "Boolean";
21
+ case "i=12":
22
+ case "i=21": return "String";
23
+ case "i=13": return "Date";
24
+ default: return normalized && numericDataTypeNodeIds.has(normalized) ? "Number" : void 0;
25
+ }
26
+ };
27
+ const isDynamicScalarDataType = (dataTypeNodeId) => {
28
+ const normalized = normalizeNamespaceZeroNodeId(dataTypeNodeId);
29
+ return normalized ? dynamicScalarDataTypeNodeIds.has(normalized) : false;
30
+ };
31
+ const requiresDataTypeDefinition = (dataTypeNodeId) => !!dataTypeNodeId && !isNamespaceZeroNodeId(dataTypeNodeId) && !scalarSchema(dataTypeNodeId) && !isDynamicScalarDataType(dataTypeNodeId);
32
+ const isUnsupportedArrayRank = (valueRank) => valueRank !== void 0 && valueRank >= 0 && valueRank !== 1;
33
+ const normalizeNamespaceZeroNodeId = (nodeId) => nodeId?.startsWith("ns=0;") ? nodeId.slice(5) : nodeId;
34
+ const isNamespaceZeroNodeId = (nodeId) => /^i=\d+$/.test(nodeId) || /^ns=0;i=\d+$/.test(nodeId);
35
+
36
+ //#endregion
37
+ export { isDynamicScalarDataType, isUnsupportedArrayRank, requiresDataTypeDefinition, scalarSchema };
38
+ //# sourceMappingURL=builtin-types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-types.mjs","names":[],"sources":["../../src/compile/builtin-types.ts"],"sourcesContent":["import type { ScalarSchema } from \"../internal/types.js\";\n\nconst numericDataTypeNodeIds = new Set([\n \"i=2\",\n \"i=3\",\n \"i=4\",\n \"i=5\",\n \"i=6\",\n \"i=7\",\n \"i=10\",\n \"i=11\",\n \"i=26\",\n \"i=27\",\n \"i=28\",\n \"i=29\",\n]);\n\nconst dynamicScalarDataTypeNodeIds = new Set([\"i=8\", \"i=9\"]);\n\nexport const scalarSchema = (\n dataTypeNodeId: string | undefined,\n): ScalarSchema | undefined => {\n const normalized = normalizeNamespaceZeroNodeId(dataTypeNodeId);\n switch (normalized) {\n case \"i=1\":\n return \"Boolean\";\n case \"i=12\":\n case \"i=21\":\n return \"String\";\n case \"i=13\":\n return \"Date\";\n default:\n return normalized && numericDataTypeNodeIds.has(normalized)\n ? \"Number\"\n : undefined;\n }\n};\n\nexport const isDynamicScalarDataType = (\n dataTypeNodeId: string | undefined,\n): boolean => {\n const normalized = normalizeNamespaceZeroNodeId(dataTypeNodeId);\n return normalized ? dynamicScalarDataTypeNodeIds.has(normalized) : false;\n};\n\nexport const requiresDataTypeDefinition = (\n dataTypeNodeId: string | undefined,\n): dataTypeNodeId is string =>\n !!dataTypeNodeId &&\n !isNamespaceZeroNodeId(dataTypeNodeId) &&\n !scalarSchema(dataTypeNodeId) &&\n !isDynamicScalarDataType(dataTypeNodeId);\n\nexport const isUnsupportedArrayRank = (valueRank: number | undefined) =>\n valueRank !== undefined && valueRank >= 0 && valueRank !== 1;\n\nconst normalizeNamespaceZeroNodeId = (nodeId: string | undefined) =>\n nodeId?.startsWith(\"ns=0;\") ? nodeId.slice(\"ns=0;\".length) : nodeId;\n\nconst isNamespaceZeroNodeId = (nodeId: string) =>\n /^i=\\d+$/.test(nodeId) || /^ns=0;i=\\d+$/.test(nodeId);\n"],"mappings":";AAEA,MAAM,yBAAyB,IAAI,IAAI;CACrC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAM,+BAA+B,IAAI,IAAI,CAAC,OAAO,MAAM,CAAC;AAE5D,MAAa,gBACX,mBAC6B;CAC7B,MAAM,aAAa,6BAA6B,eAAe;AAC/D,SAAQ,YAAR;EACE,KAAK,MACH,QAAO;EACT,KAAK;EACL,KAAK,OACH,QAAO;EACT,KAAK,OACH,QAAO;EACT,QACE,QAAO,cAAc,uBAAuB,IAAI,WAAW,GACvD,WACA;;;AAIV,MAAa,2BACX,mBACY;CACZ,MAAM,aAAa,6BAA6B,eAAe;AAC/D,QAAO,aAAa,6BAA6B,IAAI,WAAW,GAAG;;AAGrE,MAAa,8BACX,mBAEA,CAAC,CAAC,kBACF,CAAC,sBAAsB,eAAe,IACtC,CAAC,aAAa,eAAe,IAC7B,CAAC,wBAAwB,eAAe;AAE1C,MAAa,0BAA0B,cACrC,cAAc,UAAa,aAAa,KAAK,cAAc;AAE7D,MAAM,gCAAgC,WACpC,QAAQ,WAAW,QAAQ,GAAG,OAAO,MAAM,EAAe,GAAG;AAE/D,MAAM,yBAAyB,WAC7B,UAAU,KAAK,OAAO,IAAI,eAAe,KAAK,OAAO"}
@@ -0,0 +1,16 @@
1
+ import { CodegenIssue } from "../types.mjs";
2
+ import { OpcuaDataTypeDefinition as OpcuaDataTypeDefinition$1 } from "../client/src/OpcuaSession.mjs";
3
+ import "../client/src/index.mjs";
4
+ import { EnumDefinition } from "../internal/types.mjs";
5
+
6
+ //#region src/compile/enums.d.ts
7
+ type OpcuaDataTypeDefinition = OpcuaDataTypeDefinition$1;
8
+ type EnumGraph = {
9
+ readonly enums: ReadonlyMap<string, EnumDefinition>;
10
+ readonly invalidEnums: ReadonlySet<string>;
11
+ readonly issues: readonly CodegenIssue[];
12
+ };
13
+ declare const compileEnums: (definitions: ReadonlyMap<string, OpcuaDataTypeDefinition>) => EnumGraph;
14
+ //#endregion
15
+ export { EnumGraph, compileEnums };
16
+ //# sourceMappingURL=enums.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enums.d.mts","names":[],"sources":["../../src/compile/enums.ts"],"sourcesContent":[],"mappings":";;;;;;KAUK,uBAAA,GAA0B;KAEnB,SAAA;kBACM,oBAAoB;EAHjC,SAAA,YAAA,EAIoB,WAJG,CAAA,MAAG,CAAA;EAEnB,SAAA,MAAS,EAAA,SAGO,YAHP,EAAA;CACiB;AAApB,cAKL,YALK,EAAA,CAAA,WAAA,EAMH,WANG,CAAA,MAAA,EAMiB,uBANjB,CAAA,EAAA,GAOf,SAPe"}
@@ -0,0 +1,81 @@
1
+ import { issue } from "../diagnostics.mjs";
2
+ import { sanitizePascal } from "./names.mjs";
3
+
4
+ //#region src/compile/enums.ts
5
+ const compileEnums = (definitions) => {
6
+ const issues = [];
7
+ const enums = /* @__PURE__ */ new Map();
8
+ const invalidEnums = /* @__PURE__ */ new Set();
9
+ const names = /* @__PURE__ */ new Map();
10
+ for (const [nodeId, definition] of definitions) {
11
+ if (definition._tag !== "Enum") continue;
12
+ const name = sanitizePascal(definition.name);
13
+ if (!name) {
14
+ invalidEnums.add(nodeId);
15
+ issues.push(issue("enum.emptyName", {
16
+ severity: "error",
17
+ message: `Enum ${nodeId} has no usable generated name`,
18
+ nodeId
19
+ }));
20
+ continue;
21
+ }
22
+ names.set(name, [...names.get(name) ?? [], nodeId]);
23
+ }
24
+ for (const [name, nodeIds] of names) if (nodeIds.length > 1) {
25
+ for (const nodeId of nodeIds) invalidEnums.add(nodeId);
26
+ issues.push(issue("enum.nameCollision", {
27
+ severity: "error",
28
+ message: `Multiple enum DataTypes generate ${name}`,
29
+ generatedPath: [name],
30
+ cause: { candidates: nodeIds }
31
+ }));
32
+ }
33
+ for (const [nodeId, definition] of definitions) {
34
+ if (definition._tag !== "Enum" || invalidEnums.has(nodeId)) continue;
35
+ const name = sanitizePascal(definition.name);
36
+ const memberGroups = /* @__PURE__ */ new Map();
37
+ const members = [];
38
+ for (const field of definition.fields) {
39
+ let memberName = sanitizePascal(field.name);
40
+ if (!memberName) {
41
+ memberName = `_Value${field.value}`;
42
+ issues.push(issue("enum.memberEmptyName", {
43
+ message: `Enum member for value ${field.value} has no usable generated name`,
44
+ nodeId
45
+ }));
46
+ }
47
+ memberGroups.set(memberName, [...memberGroups.get(memberName) ?? [], field.name]);
48
+ members.push({
49
+ name: memberName,
50
+ value: field.value
51
+ });
52
+ }
53
+ const collision = [...memberGroups].find(([, candidates]) => candidates.length > 1);
54
+ if (collision) {
55
+ invalidEnums.add(nodeId);
56
+ issues.push(issue("enum.memberNameCollision", {
57
+ severity: "error",
58
+ message: `Enum ${name} has colliding generated member ${collision[0]}`,
59
+ nodeId,
60
+ generatedPath: [name, collision[0]],
61
+ cause: { candidates: collision[1] }
62
+ }));
63
+ continue;
64
+ }
65
+ enums.set(nodeId, {
66
+ name,
67
+ dataTypeNodeId: nodeId,
68
+ browseName: definition.name,
69
+ members: members.sort((left, right) => left.value - right.value || left.name.localeCompare(right.name))
70
+ });
71
+ }
72
+ return {
73
+ enums,
74
+ invalidEnums,
75
+ issues
76
+ };
77
+ };
78
+
79
+ //#endregion
80
+ export { compileEnums };
81
+ //# sourceMappingURL=enums.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enums.mjs","names":["issues: CodegenIssue[]","members: EnumMemberDefinition[]"],"sources":["../../src/compile/enums.ts"],"sourcesContent":["import type { OpcuaSession } from \"@effect-opcua/client\";\n\nimport { issue } from \"../diagnostics.js\";\nimport type { CodegenIssue } from \"../types.js\";\nimport type {\n EnumDefinition,\n EnumMemberDefinition,\n} from \"../internal/types.js\";\nimport { sanitizePascal } from \"./names.js\";\n\ntype OpcuaDataTypeDefinition = OpcuaSession.OpcuaDataTypeDefinition;\n\nexport type EnumGraph = {\n readonly enums: ReadonlyMap<string, EnumDefinition>;\n readonly invalidEnums: ReadonlySet<string>;\n readonly issues: readonly CodegenIssue[];\n};\n\nexport const compileEnums = (\n definitions: ReadonlyMap<string, OpcuaDataTypeDefinition>,\n): EnumGraph => {\n const issues: CodegenIssue[] = [];\n const enums = new Map<string, EnumDefinition>();\n const invalidEnums = new Set<string>();\n const names = new Map<string, string[]>();\n for (const [nodeId, definition] of definitions) {\n if (definition._tag !== \"Enum\") continue;\n const name = sanitizePascal(definition.name);\n if (!name) {\n invalidEnums.add(nodeId);\n issues.push(\n issue(\"enum.emptyName\", {\n severity: \"error\",\n message: `Enum ${nodeId} has no usable generated name`,\n nodeId,\n }),\n );\n continue;\n }\n names.set(name, [...(names.get(name) ?? []), nodeId]);\n }\n\n for (const [name, nodeIds] of names) {\n if (nodeIds.length > 1) {\n for (const nodeId of nodeIds) invalidEnums.add(nodeId);\n issues.push(\n issue(\"enum.nameCollision\", {\n severity: \"error\",\n message: `Multiple enum DataTypes generate ${name}`,\n generatedPath: [name],\n cause: { candidates: nodeIds },\n }),\n );\n }\n }\n\n for (const [nodeId, definition] of definitions) {\n if (definition._tag !== \"Enum\" || invalidEnums.has(nodeId)) continue;\n const name = sanitizePascal(definition.name)!;\n const memberGroups = new Map<string, string[]>();\n const members: EnumMemberDefinition[] = [];\n for (const field of definition.fields) {\n let memberName = sanitizePascal(field.name);\n if (!memberName) {\n memberName = `_Value${field.value}`;\n issues.push(\n issue(\"enum.memberEmptyName\", {\n message: `Enum member for value ${field.value} has no usable generated name`,\n nodeId,\n }),\n );\n }\n memberGroups.set(memberName, [\n ...(memberGroups.get(memberName) ?? []),\n field.name,\n ]);\n members.push({ name: memberName, value: field.value });\n }\n\n const collision = [...memberGroups].find(\n ([, candidates]) => candidates.length > 1,\n );\n if (collision) {\n invalidEnums.add(nodeId);\n issues.push(\n issue(\"enum.memberNameCollision\", {\n severity: \"error\",\n message: `Enum ${name} has colliding generated member ${collision[0]}`,\n nodeId,\n generatedPath: [name, collision[0]],\n cause: { candidates: collision[1] },\n }),\n );\n continue;\n }\n\n enums.set(nodeId, {\n name,\n dataTypeNodeId: nodeId,\n browseName: definition.name,\n members: members.sort(\n (left, right) =>\n left.value - right.value || left.name.localeCompare(right.name),\n ),\n });\n }\n\n return { enums, invalidEnums, issues };\n};\n"],"mappings":";;;;AAkBA,MAAa,gBACX,gBACc;CACd,MAAMA,SAAyB,EAAE;CACjC,MAAM,wBAAQ,IAAI,KAA6B;CAC/C,MAAM,+BAAe,IAAI,KAAa;CACtC,MAAM,wBAAQ,IAAI,KAAuB;AACzC,MAAK,MAAM,CAAC,QAAQ,eAAe,aAAa;AAC9C,MAAI,WAAW,SAAS,OAAQ;EAChC,MAAM,OAAO,eAAe,WAAW,KAAK;AAC5C,MAAI,CAAC,MAAM;AACT,gBAAa,IAAI,OAAO;AACxB,UAAO,KACL,MAAM,kBAAkB;IACtB,UAAU;IACV,SAAS,QAAQ,OAAO;IACxB;IACD,CAAC,CACH;AACD;;AAEF,QAAM,IAAI,MAAM,CAAC,GAAI,MAAM,IAAI,KAAK,IAAI,EAAE,EAAG,OAAO,CAAC;;AAGvD,MAAK,MAAM,CAAC,MAAM,YAAY,MAC5B,KAAI,QAAQ,SAAS,GAAG;AACtB,OAAK,MAAM,UAAU,QAAS,cAAa,IAAI,OAAO;AACtD,SAAO,KACL,MAAM,sBAAsB;GAC1B,UAAU;GACV,SAAS,oCAAoC;GAC7C,eAAe,CAAC,KAAK;GACrB,OAAO,EAAE,YAAY,SAAS;GAC/B,CAAC,CACH;;AAIL,MAAK,MAAM,CAAC,QAAQ,eAAe,aAAa;AAC9C,MAAI,WAAW,SAAS,UAAU,aAAa,IAAI,OAAO,CAAE;EAC5D,MAAM,OAAO,eAAe,WAAW,KAAK;EAC5C,MAAM,+BAAe,IAAI,KAAuB;EAChD,MAAMC,UAAkC,EAAE;AAC1C,OAAK,MAAM,SAAS,WAAW,QAAQ;GACrC,IAAI,aAAa,eAAe,MAAM,KAAK;AAC3C,OAAI,CAAC,YAAY;AACf,iBAAa,SAAS,MAAM;AAC5B,WAAO,KACL,MAAM,wBAAwB;KAC5B,SAAS,yBAAyB,MAAM,MAAM;KAC9C;KACD,CAAC,CACH;;AAEH,gBAAa,IAAI,YAAY,CAC3B,GAAI,aAAa,IAAI,WAAW,IAAI,EAAE,EACtC,MAAM,KACP,CAAC;AACF,WAAQ,KAAK;IAAE,MAAM;IAAY,OAAO,MAAM;IAAO,CAAC;;EAGxD,MAAM,YAAY,CAAC,GAAG,aAAa,CAAC,MACjC,GAAG,gBAAgB,WAAW,SAAS,EACzC;AACD,MAAI,WAAW;AACb,gBAAa,IAAI,OAAO;AACxB,UAAO,KACL,MAAM,4BAA4B;IAChC,UAAU;IACV,SAAS,QAAQ,KAAK,kCAAkC,UAAU;IAClE;IACA,eAAe,CAAC,MAAM,UAAU,GAAG;IACnC,OAAO,EAAE,YAAY,UAAU,IAAI;IACpC,CAAC,CACH;AACD;;AAGF,QAAM,IAAI,QAAQ;GAChB;GACA,gBAAgB;GAChB,YAAY,WAAW;GACvB,SAAS,QAAQ,MACd,MAAM,UACL,KAAK,QAAQ,MAAM,SAAS,KAAK,KAAK,cAAc,MAAM,KAAK,CAClE;GACF,CAAC;;AAGJ,QAAO;EAAE;EAAO;EAAc;EAAQ"}
@@ -0,0 +1,10 @@
1
+ import { CodegenIssue } from "../types.mjs";
2
+ import { CodegenModel, VariableDefinition } from "../internal/types.mjs";
3
+ import { TypeGraph } from "./type-graph.mjs";
4
+
5
+ //#region src/compile/model.d.ts
6
+ declare const modelIssues: (variables: readonly VariableDefinition[], typeGraph: TypeGraph) => readonly CodegenIssue[];
7
+ declare const assembleModel: (variables: readonly VariableDefinition[], typeGraph: TypeGraph, issues: readonly CodegenIssue[]) => CodegenModel;
8
+ //#endregion
9
+ export { assembleModel, modelIssues };
10
+ //# sourceMappingURL=model.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.mts","names":[],"sources":["../../src/compile/model.ts"],"sourcesContent":[],"mappings":";;;;;cAYa,kCACS,iCACT,uBACD;cAMC,oCACS,iCACT,4BACM,mBAChB"}
@@ -0,0 +1,92 @@
1
+ import { errorIssue } from "../diagnostics.mjs";
2
+ import { displayPath, pathKey } from "./names.mjs";
3
+
4
+ //#region src/compile/model.ts
5
+ const modelIssues = (variables, typeGraph) => [
6
+ ...generatedPathCollisionIssues(variables),
7
+ ...branchLeafCollisionIssues(variables),
8
+ ...reservedDataTypesCollisionIssues(variables, typeGraph)
9
+ ];
10
+ const assembleModel = (variables, typeGraph, issues) => ({
11
+ nodeIds: variables.map((variable) => ({
12
+ nodeId: variable.nodeId,
13
+ path: variable.path,
14
+ generatedPath: variable.generatedPath
15
+ })),
16
+ dataTypeNodeIds: dataTypeNodeIdDefinitions(typeGraph),
17
+ variables: [...variables].sort((left, right) => pathKey(left.generatedPath).localeCompare(pathKey(right.generatedPath))),
18
+ enums: [...typeGraph.enums.values()].sort((left, right) => left.name.localeCompare(right.name)),
19
+ structures: sortStructures([...typeGraph.structures.values()]),
20
+ issues
21
+ });
22
+ const generatedPathCollisionIssues = (variables) => {
23
+ const groups = /* @__PURE__ */ new Map();
24
+ for (const variable of variables) {
25
+ const key = pathKey(variable.generatedPath);
26
+ groups.set(key, [...groups.get(key) ?? [], displayPath(variable.path)]);
27
+ }
28
+ return [...groups].flatMap(([key, candidates]) => candidates.length > 1 ? [errorIssue("path.generatedPathCollision", {
29
+ message: "Two variables generate the same TypeScript path",
30
+ generatedPath: key.split("."),
31
+ cause: { candidates }
32
+ })] : []);
33
+ };
34
+ const branchLeafCollisionIssues = (variables) => {
35
+ const byPath = new Map(variables.map((variable) => [pathKey(variable.generatedPath), variable]));
36
+ const issues = [];
37
+ for (const variable of variables) for (let index = 1; index < variable.generatedPath.length; index++) {
38
+ const prefix = variable.generatedPath.slice(0, index);
39
+ const parent = byPath.get(pathKey(prefix));
40
+ if (!parent) continue;
41
+ issues.push(errorIssue("path.branchLeafCollision", {
42
+ message: "A generated variable path is both a leaf variable and an object branch",
43
+ generatedPath: prefix,
44
+ cause: { candidates: [displayPath(parent.path), displayPath(variable.path)] }
45
+ }));
46
+ }
47
+ return issues;
48
+ };
49
+ const reservedDataTypesCollisionIssues = (variables, typeGraph) => {
50
+ if (!variables.some((variable) => variable.generatedPath[0] === "DataTypes") || typeGraph.enums.size === 0 && typeGraph.structures.size === 0) return [];
51
+ return [errorIssue("path.topLevelExportCollision", {
52
+ message: "A top-level browse path sanitizes to reserved generated group \"DataTypes\"",
53
+ generatedPath: ["DataTypes"]
54
+ })];
55
+ };
56
+ const dataTypeNodeIdDefinitions = (typeGraph) => {
57
+ return [...[...typeGraph.enums.values()].map((item) => ({
58
+ name: item.name,
59
+ nodeId: item.dataTypeNodeId
60
+ })), ...[...typeGraph.structures.values()].map((item) => ({
61
+ name: item.name,
62
+ nodeId: item.dataTypeNodeId
63
+ }))].sort((left, right) => left.name.localeCompare(right.name));
64
+ };
65
+ const sortStructures = (structures) => {
66
+ const byName = new Map(structures.map((structure) => [structure.name, structure]));
67
+ const sorted = [];
68
+ const seen = /* @__PURE__ */ new Set();
69
+ const visit = (structure) => {
70
+ if (seen.has(structure.name)) return;
71
+ seen.add(structure.name);
72
+ const dependencies = structure.fields.flatMap((field) => schemaStructureDependencies(field.schema));
73
+ for (const dependency of dependencies.sort()) {
74
+ const target = byName.get(dependency);
75
+ if (target) visit(target);
76
+ }
77
+ sorted.push(structure);
78
+ };
79
+ for (const structure of [...structures].sort((left, right) => left.name.localeCompare(right.name))) visit(structure);
80
+ return sorted;
81
+ };
82
+ const schemaStructureDependencies = (schema) => {
83
+ switch (schema._tag) {
84
+ case "Structure": return [schema.name];
85
+ case "Array": return schemaStructureDependencies(schema.item);
86
+ default: return [];
87
+ }
88
+ };
89
+
90
+ //#endregion
91
+ export { assembleModel, modelIssues };
92
+ //# sourceMappingURL=model.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.mjs","names":["issues: CodegenIssue[]","sorted: StructureDefinition[]"],"sources":["../../src/compile/model.ts"],"sourcesContent":["import { errorIssue } from \"../diagnostics.js\";\nimport type { CodegenIssue } from \"../types.js\";\nimport type {\n CodegenModel,\n DataTypeNodeIdDefinition,\n SchemaExpression,\n StructureDefinition,\n VariableDefinition,\n} from \"../internal/types.js\";\nimport { displayPath, pathKey } from \"./names.js\";\nimport type { TypeGraph } from \"./type-graph.js\";\n\nexport const modelIssues = (\n variables: readonly VariableDefinition[],\n typeGraph: TypeGraph,\n): readonly CodegenIssue[] => [\n ...generatedPathCollisionIssues(variables),\n ...branchLeafCollisionIssues(variables),\n ...reservedDataTypesCollisionIssues(variables, typeGraph),\n];\n\nexport const assembleModel = (\n variables: readonly VariableDefinition[],\n typeGraph: TypeGraph,\n issues: readonly CodegenIssue[],\n): CodegenModel => ({\n nodeIds: variables.map((variable) => ({\n nodeId: variable.nodeId,\n path: variable.path,\n generatedPath: variable.generatedPath,\n })),\n dataTypeNodeIds: dataTypeNodeIdDefinitions(typeGraph),\n variables: [...variables].sort((left, right) =>\n pathKey(left.generatedPath).localeCompare(pathKey(right.generatedPath)),\n ),\n enums: [...typeGraph.enums.values()].sort((left, right) =>\n left.name.localeCompare(right.name),\n ),\n structures: sortStructures([...typeGraph.structures.values()]),\n issues,\n});\n\nconst generatedPathCollisionIssues = (\n variables: readonly VariableDefinition[],\n): readonly CodegenIssue[] => {\n const groups = new Map<string, string[]>();\n for (const variable of variables) {\n const key = pathKey(variable.generatedPath);\n groups.set(key, [...(groups.get(key) ?? []), displayPath(variable.path)]);\n }\n return [...groups].flatMap(([key, candidates]) =>\n candidates.length > 1\n ? [\n errorIssue(\"path.generatedPathCollision\", {\n message: \"Two variables generate the same TypeScript path\",\n generatedPath: key.split(\".\"),\n cause: { candidates },\n }),\n ]\n : [],\n );\n};\n\nconst branchLeafCollisionIssues = (\n variables: readonly VariableDefinition[],\n): readonly CodegenIssue[] => {\n const byPath = new Map(\n variables.map((variable) => [pathKey(variable.generatedPath), variable]),\n );\n const issues: CodegenIssue[] = [];\n for (const variable of variables) {\n for (let index = 1; index < variable.generatedPath.length; index++) {\n const prefix = variable.generatedPath.slice(0, index);\n const parent = byPath.get(pathKey(prefix));\n if (!parent) continue;\n issues.push(\n errorIssue(\"path.branchLeafCollision\", {\n message:\n \"A generated variable path is both a leaf variable and an object branch\",\n generatedPath: prefix,\n cause: {\n candidates: [displayPath(parent.path), displayPath(variable.path)],\n },\n }),\n );\n }\n }\n return issues;\n};\n\nconst reservedDataTypesCollisionIssues = (\n variables: readonly VariableDefinition[],\n typeGraph: TypeGraph,\n): readonly CodegenIssue[] => {\n if (\n !variables.some((variable) => variable.generatedPath[0] === \"DataTypes\") ||\n (typeGraph.enums.size === 0 && typeGraph.structures.size === 0)\n ) {\n return [];\n }\n return [\n errorIssue(\"path.topLevelExportCollision\", {\n message:\n 'A top-level browse path sanitizes to reserved generated group \"DataTypes\"',\n generatedPath: [\"DataTypes\"],\n }),\n ];\n};\n\nconst dataTypeNodeIdDefinitions = (\n typeGraph: TypeGraph,\n): readonly DataTypeNodeIdDefinition[] => {\n const entries = [\n ...[...typeGraph.enums.values()].map((item) => ({\n name: item.name,\n nodeId: item.dataTypeNodeId,\n })),\n ...[...typeGraph.structures.values()].map((item) => ({\n name: item.name,\n nodeId: item.dataTypeNodeId,\n })),\n ];\n return entries.sort((left, right) => left.name.localeCompare(right.name));\n};\n\nconst sortStructures = (structures: readonly StructureDefinition[]) => {\n const byName = new Map(\n structures.map((structure) => [structure.name, structure]),\n );\n const sorted: StructureDefinition[] = [];\n const seen = new Set<string>();\n const visit = (structure: StructureDefinition) => {\n if (seen.has(structure.name)) return;\n seen.add(structure.name);\n const dependencies = structure.fields.flatMap((field) =>\n schemaStructureDependencies(field.schema),\n );\n for (const dependency of dependencies.sort()) {\n const target = byName.get(dependency);\n if (target) visit(target);\n }\n sorted.push(structure);\n };\n for (const structure of [...structures].sort((left, right) =>\n left.name.localeCompare(right.name),\n )) {\n visit(structure);\n }\n return sorted;\n};\n\nconst schemaStructureDependencies = (\n schema: SchemaExpression,\n): readonly string[] => {\n switch (schema._tag) {\n case \"Structure\":\n return [schema.name];\n case \"Array\":\n return schemaStructureDependencies(schema.item);\n default:\n return [];\n }\n};\n"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { CodegenIssue } from "../types.mjs";
2
+ import { DiscoveredNode, DiscoveryModel, GeneratedPath } from "../internal/types.mjs";
3
+
4
+ //#region src/compile/names.d.ts
5
+ type SurfaceNode = GeneratedPath & {
6
+ readonly node: DiscoveredNode;
7
+ };
8
+ declare const surfaceNodes: (discovery: DiscoveryModel) => readonly SurfaceNode[];
9
+ declare const pathIssues: (items: readonly SurfaceNode[]) => readonly CodegenIssue[];
10
+ declare const sanitizePascal: (value: string) => string | undefined;
11
+ declare const sanitizeCamel: (value: string) => string | undefined;
12
+ declare const nodeOpcuaFieldName: (value: string) => string;
13
+ declare const pathKey: (path: readonly string[]) => string;
14
+ declare const displayPath: (path: readonly string[]) => string;
15
+ //#endregion
16
+ export { SurfaceNode, displayPath, nodeOpcuaFieldName, pathIssues, pathKey, sanitizeCamel, sanitizePascal, surfaceNodes };
17
+ //# sourceMappingURL=names.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"names.d.mts","names":[],"sources":["../../src/compile/names.ts"],"sourcesContent":[],"mappings":";;;;KAQY,WAAA,GAAc;iBACT;AADjB,CAAA;AAIa,cAAA,YACA,EAAA,CAAA,SAAA,EAAA,cACU,EAAA,GAAA,SAAX,WAAW,EAAA;AAQV,cAAA,UACK,EAAA,CAAA,KAAA,EAAA,SAAA,WACM,EAAA,EAAA,GAAA,SAAZ,YAAY,EAAA;AAyCX,cAAA,cAKZ,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,MAAA,GAAA,SAAA;AAEY,cAAA,aASZ,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,MAAA,GAAA,SAAA;AAEY,cAAA,kBASZ,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,MAAA;AAEY,cAAA,OAAqD,EAAA,CAAA,IAAA,EAAA,SAAA,MAAA,EAAA,EAAA,GAAA,MAAA;AAErD,cAAA,WAA2D,EAAA,CAAA,IAAA,EAAA,SAAA,MAAA,EAAA,EAAA,GAAA,MAAA"}
@@ -0,0 +1,95 @@
1
+ import { errorIssue } from "../diagnostics.mjs";
2
+
3
+ //#region src/compile/names.ts
4
+ const surfaceNodes = (discovery) => [...discovery.nodes.values()].map((node) => ({
5
+ node,
6
+ ...relativeGeneratedPath(discovery, node)
7
+ })).filter((item) => item.path.length > 0).sort((left, right) => pathKey(left.path).localeCompare(pathKey(right.path)));
8
+ const pathIssues = (items) => {
9
+ const issues = [];
10
+ for (const item of items) {
11
+ const index = item.generatedPath.findIndex((segment) => segment === "");
12
+ if (index >= 0) issues.push(errorIssue("path.emptyGeneratedKey", {
13
+ message: "BrowseName segment does not produce a TypeScript key",
14
+ path: item.path,
15
+ generatedPath: item.generatedPath,
16
+ nodeId: item.node.nodeId,
17
+ cause: { segment: item.path[index] }
18
+ }));
19
+ }
20
+ for (const [, siblings] of groupByParent(items)) {
21
+ const groups = /* @__PURE__ */ new Map();
22
+ for (const item of siblings) {
23
+ const key = item.generatedPath.at(-1);
24
+ const original = item.path.at(-1);
25
+ if (!key || !original) continue;
26
+ groups.set(key, [...groups.get(key) ?? [], original]);
27
+ }
28
+ for (const [generatedKey, candidates] of groups) if (new Set(candidates).size > 1) issues.push(errorIssue("path.generatedKeyCollision", {
29
+ message: "Two sibling BrowseName segments generate the same TypeScript key",
30
+ path: siblings[0]?.path.slice(0, -1),
31
+ generatedPath: siblings[0]?.generatedPath.slice(0, -1),
32
+ cause: {
33
+ generatedKey,
34
+ candidates
35
+ }
36
+ }));
37
+ }
38
+ return issues;
39
+ };
40
+ const sanitizePascal = (value) => {
41
+ const parts = value.match(/[A-Za-z0-9]+/g) ?? [];
42
+ if (parts.length === 0) return void 0;
43
+ const joined = parts.map(capitalize).join("");
44
+ return /^[0-9]/.test(joined) ? `_${joined}` : joined;
45
+ };
46
+ const sanitizeCamel = (value) => {
47
+ const parts = identifierWords(value);
48
+ if (parts.length === 0) return void 0;
49
+ const joined = parts.map((part, index) => index === 0 ? part.toLowerCase() : capitalize(part.toLowerCase())).join("");
50
+ return /^[0-9]/.test(joined) ? `_${joined}` : joined;
51
+ };
52
+ const nodeOpcuaFieldName = (value) => {
53
+ if (value.length >= 2 && isAllUpperAlpha(value)) return value;
54
+ if (value.includes("_")) return value.split("_").map(nodeOpcuaFieldName).join("_");
55
+ let result = `${value.charAt(0).toLowerCase()}${value.slice(1)}`;
56
+ if (result.length > 3 && isUpper(value[1] ?? "") && isUpper(value[2] ?? "")) result = `${value.slice(0, 2).toLowerCase()}${value.slice(2)}`;
57
+ return result;
58
+ };
59
+ const pathKey = (path) => path.join(".");
60
+ const displayPath = (path) => path.join(" / ");
61
+ const relativeGeneratedPath = (discovery, node) => {
62
+ const root = discovery.roots.find((item) => item.rootIndex === node.rootIndex);
63
+ if (!root) return generatedPath(node.path);
64
+ const stripped = node.path.slice(root.path.length);
65
+ return generatedPath(root.exportPrefix ? [root.exportPrefix, ...stripped] : stripped);
66
+ };
67
+ const generatedPath = (path) => ({
68
+ path,
69
+ generatedPath: path.map((segment) => sanitizePascal(segment) ?? "")
70
+ });
71
+ const groupByParent = (items) => {
72
+ const groups = /* @__PURE__ */ new Map();
73
+ for (const item of items) {
74
+ const key = item.path.slice(0, -1).join("\0");
75
+ groups.set(key, [...groups.get(key) ?? [], item]);
76
+ }
77
+ return groups;
78
+ };
79
+ const capitalize = (word) => word.length === 0 ? word : `${word.charAt(0).toUpperCase()}${word.slice(1)}`;
80
+ const identifierWords = (value) => (value.match(/[A-Za-z0-9]+/g) ?? []).flatMap(splitIdentifierPart);
81
+ const splitIdentifierPart = (part) => part.replace(/([a-z0-9])([A-Z])/g, "$1 $2").match(/[A-Za-z0-9]+/g) ?? [];
82
+ const isAllUpperAlpha = (value) => {
83
+ let alpha = 0;
84
+ for (const char of value) {
85
+ if (isLower(char)) return false;
86
+ if (isUpper(char)) alpha++;
87
+ }
88
+ return alpha > 0;
89
+ };
90
+ const isLower = (char) => char >= "a" && char <= "z";
91
+ const isUpper = (char) => char >= "A" && char <= "Z";
92
+
93
+ //#endregion
94
+ export { displayPath, nodeOpcuaFieldName, pathIssues, pathKey, sanitizeCamel, sanitizePascal, surfaceNodes };
95
+ //# sourceMappingURL=names.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"names.mjs","names":["issues: CodegenIssue[]"],"sources":["../../src/compile/names.ts"],"sourcesContent":["import { errorIssue } from \"../diagnostics.js\";\nimport type { CodegenIssue } from \"../types.js\";\nimport type {\n DiscoveredNode,\n DiscoveryModel,\n GeneratedPath,\n} from \"../internal/types.js\";\n\nexport type SurfaceNode = GeneratedPath & {\n readonly node: DiscoveredNode;\n};\n\nexport const surfaceNodes = (\n discovery: DiscoveryModel,\n): readonly SurfaceNode[] =>\n [...discovery.nodes.values()]\n .map((node) => ({ node, ...relativeGeneratedPath(discovery, node) }))\n .filter((item) => item.path.length > 0)\n .sort((left, right) =>\n pathKey(left.path).localeCompare(pathKey(right.path)),\n );\n\nexport const pathIssues = (\n items: readonly SurfaceNode[],\n): readonly CodegenIssue[] => {\n const issues: CodegenIssue[] = [];\n for (const item of items) {\n const index = item.generatedPath.findIndex((segment) => segment === \"\");\n if (index >= 0) {\n issues.push(\n errorIssue(\"path.emptyGeneratedKey\", {\n message: \"BrowseName segment does not produce a TypeScript key\",\n path: item.path,\n generatedPath: item.generatedPath,\n nodeId: item.node.nodeId,\n cause: { segment: item.path[index] },\n }),\n );\n }\n }\n for (const [, siblings] of groupByParent(items)) {\n const groups = new Map<string, string[]>();\n for (const item of siblings) {\n const key = item.generatedPath.at(-1);\n const original = item.path.at(-1);\n if (!key || !original) continue;\n groups.set(key, [...(groups.get(key) ?? []), original]);\n }\n for (const [generatedKey, candidates] of groups) {\n if (new Set(candidates).size > 1) {\n issues.push(\n errorIssue(\"path.generatedKeyCollision\", {\n message:\n \"Two sibling BrowseName segments generate the same TypeScript key\",\n path: siblings[0]?.path.slice(0, -1),\n generatedPath: siblings[0]?.generatedPath.slice(0, -1),\n cause: { generatedKey, candidates },\n }),\n );\n }\n }\n }\n return issues;\n};\n\nexport const sanitizePascal = (value: string): string | undefined => {\n const parts = value.match(/[A-Za-z0-9]+/g) ?? [];\n if (parts.length === 0) return undefined;\n const joined = parts.map(capitalize).join(\"\");\n return /^[0-9]/.test(joined) ? `_${joined}` : joined;\n};\n\nexport const sanitizeCamel = (value: string): string | undefined => {\n const parts = identifierWords(value);\n if (parts.length === 0) return undefined;\n const joined = parts\n .map((part, index) =>\n index === 0 ? part.toLowerCase() : capitalize(part.toLowerCase()),\n )\n .join(\"\");\n return /^[0-9]/.test(joined) ? `_${joined}` : joined;\n};\n\nexport const nodeOpcuaFieldName = (value: string): string => {\n if (value.length >= 2 && isAllUpperAlpha(value)) return value;\n if (value.includes(\"_\"))\n return value.split(\"_\").map(nodeOpcuaFieldName).join(\"_\");\n let result = `${value.charAt(0).toLowerCase()}${value.slice(1)}`;\n if (result.length > 3 && isUpper(value[1] ?? \"\") && isUpper(value[2] ?? \"\")) {\n result = `${value.slice(0, 2).toLowerCase()}${value.slice(2)}`;\n }\n return result;\n};\n\nexport const pathKey = (path: readonly string[]) => path.join(\".\");\n\nexport const displayPath = (path: readonly string[]) => path.join(\" / \");\n\nconst relativeGeneratedPath = (\n discovery: DiscoveryModel,\n node: DiscoveredNode,\n): GeneratedPath => {\n const root = discovery.roots.find(\n (item) => item.rootIndex === node.rootIndex,\n );\n if (!root) return generatedPath(node.path);\n const stripped = node.path.slice(root.path.length);\n return generatedPath(\n root.exportPrefix ? [root.exportPrefix, ...stripped] : stripped,\n );\n};\n\nconst generatedPath = (path: readonly string[]): GeneratedPath => ({\n path,\n generatedPath: path.map((segment) => sanitizePascal(segment) ?? \"\"),\n});\n\nconst groupByParent = (items: readonly SurfaceNode[]) => {\n const groups = new Map<string, readonly SurfaceNode[]>();\n for (const item of items) {\n const key = item.path.slice(0, -1).join(\"\\u0000\");\n groups.set(key, [...(groups.get(key) ?? []), item]);\n }\n return groups;\n};\n\nconst capitalize = (word: string) =>\n word.length === 0 ? word : `${word.charAt(0).toUpperCase()}${word.slice(1)}`;\n\nconst identifierWords = (value: string): readonly string[] =>\n (value.match(/[A-Za-z0-9]+/g) ?? []).flatMap(splitIdentifierPart);\n\nconst splitIdentifierPart = (part: string): readonly string[] =>\n part.replace(/([a-z0-9])([A-Z])/g, \"$1 $2\").match(/[A-Za-z0-9]+/g) ?? [];\n\nconst isAllUpperAlpha = (value: string) => {\n let alpha = 0;\n for (const char of value) {\n if (isLower(char)) return false;\n if (isUpper(char)) alpha++;\n }\n return alpha > 0;\n};\n\nconst isLower = (char: string) => char >= \"a\" && char <= \"z\";\nconst isUpper = (char: string) => char >= \"A\" && char <= \"Z\";\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { NormalizedCodegenConfig } from "../internal/types.mjs";
2
+
3
+ //#region src/compile/policy.d.ts
4
+ declare const typeFallbackSeverity: (config: NormalizedCodegenConfig) => "error" | "warning";
5
+ //#endregion
6
+ export { typeFallbackSeverity };
7
+ //# sourceMappingURL=policy.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.mts","names":[],"sources":["../../src/compile/policy.ts"],"sourcesContent":[],"mappings":";;;cAEa,+BACH"}
@@ -0,0 +1,6 @@
1
+ //#region src/compile/policy.ts
2
+ const typeFallbackSeverity = (config) => config.diagnostics.typeFallback === "fail" ? "error" : "warning";
3
+
4
+ //#endregion
5
+ export { typeFallbackSeverity };
6
+ //# sourceMappingURL=policy.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.mjs","names":[],"sources":["../../src/compile/policy.ts"],"sourcesContent":["import type { NormalizedCodegenConfig } from \"../internal/types.js\";\n\nexport const typeFallbackSeverity = (\n config: NormalizedCodegenConfig,\n): \"error\" | \"warning\" =>\n config.diagnostics.typeFallback === \"fail\" ? \"error\" : \"warning\";\n"],"mappings":";AAEA,MAAa,wBACX,WAEA,OAAO,YAAY,iBAAiB,SAAS,UAAU"}
@@ -0,0 +1,16 @@
1
+ import { CodegenIssue } from "../types.mjs";
2
+ import { OpcuaDataTypeDefinition as OpcuaDataTypeDefinition$1 } from "../client/src/OpcuaSession.mjs";
3
+ import "../client/src/index.mjs";
4
+ import { EnumDefinition, NormalizedCodegenConfig, StructureDefinition } from "../internal/types.mjs";
5
+
6
+ //#region src/compile/structures.d.ts
7
+ type OpcuaDataTypeDefinition = OpcuaDataTypeDefinition$1;
8
+ type StructureGraph = {
9
+ readonly structures: ReadonlyMap<string, StructureDefinition>;
10
+ readonly invalidStructures: ReadonlySet<string>;
11
+ readonly issues: readonly CodegenIssue[];
12
+ };
13
+ declare const compileStructures: (config: NormalizedCodegenConfig, definitions: ReadonlyMap<string, OpcuaDataTypeDefinition>, enums: ReadonlyMap<string, EnumDefinition>, invalidEnums: ReadonlySet<string>) => StructureGraph;
14
+ //#endregion
15
+ export { StructureGraph, compileStructures };
16
+ //# sourceMappingURL=structures.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structures.d.mts","names":[],"sources":["../../src/compile/structures.ts"],"sourcesContent":[],"mappings":";;;;;;KAmBK,uBAAA,GAA0B;KAGnB,cAAA;uBACW,oBAAoB;EAJtC,SAAA,iBAAuB,EAKE,WALC,CAAA,MAAA,CAAA;EAGnB,SAAA,MAAA,EAAc,SAGE,YAHF,EAAA;CACiB;AAApB,cAKV,iBALU,EAAA,CAAA,MAAA,EAMb,uBANa,EAAA,WAAA,EAOR,WAPQ,CAAA,MAAA,EAOY,uBAPZ,CAAA,EAAA,KAAA,EAQd,WARc,CAAA,MAAA,EAQM,cARN,CAAA,EAAA,YAAA,EASP,WATO,CAAA,MAAA,CAAA,EAAA,GAUpB,cAVoB"}