@distrohelena/canton-typescript-sdk 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -5
- package/dist/daml-interface/analysis/analyzed-choice.d.ts +5 -5
- package/dist/daml-interface/analysis/analyzed-daml-type-definition.d.ts +6 -0
- package/dist/daml-interface/analysis/analyzed-daml-type-definition.js +1 -0
- package/dist/daml-interface/analysis/analyzed-daml-type.d.ts +54 -0
- package/dist/daml-interface/analysis/analyzed-daml-type.js +1 -0
- package/dist/daml-interface/analysis/analyzed-template.d.ts +3 -3
- package/dist/daml-interface/analysis/daml-interface-analyzer.d.ts +3 -1
- package/dist/daml-interface/analysis/daml-interface-analyzer.js +183 -19
- package/dist/daml-interface/emission/named-type-emitter.d.ts +41 -0
- package/dist/daml-interface/emission/named-type-emitter.js +441 -0
- package/dist/daml-interface/emission/project-emitter.d.ts +5 -1
- package/dist/daml-interface/emission/project-emitter.js +20 -3
- package/dist/daml-interface/emission/registry-emitter.d.ts +1 -0
- package/dist/daml-interface/emission/registry-emitter.js +15 -8
- package/dist/daml-interface/emission/support-file-emitter.d.ts +16 -1
- package/dist/daml-interface/emission/support-file-emitter.js +206 -6
- package/dist/daml-interface/emission/template-binding-emitter.d.ts +25 -1
- package/dist/daml-interface/emission/template-binding-emitter.js +373 -72
- package/dist/daml-interface/emission/type-script-name-resolver.d.ts +50 -3
- package/dist/daml-interface/emission/type-script-name-resolver.js +369 -11
- package/dist/daml-interface/emission-model/generated-choice-binding.d.ts +7 -0
- package/dist/daml-interface/emission-model/generated-choice-binding.js +6 -0
- package/dist/daml-interface/emission-model/generated-daml-interface-project.d.ts +3 -0
- package/dist/daml-interface/emission-model/generated-daml-interface-project.js +2 -0
- package/dist/daml-interface/emission-model/generated-named-type-file.d.ts +23 -0
- package/dist/daml-interface/emission-model/generated-named-type-file.js +23 -0
- package/dist/daml-interface/emission-model/generated-template-binding.d.ts +9 -0
- package/dist/daml-interface/emission-model/generated-template-binding.js +8 -0
- package/dist/daml-interface/index.d.ts +12 -0
- package/dist/daml-interface/index.js +9 -0
- package/dist/daml-interface/runtime/daml-event-source-normalizer.d.ts +52 -0
- package/dist/daml-interface/runtime/daml-event-source-normalizer.js +364 -0
- package/dist/daml-interface/runtime/daml-materialization-error.d.ts +5 -0
- package/dist/daml-interface/runtime/daml-materialization-error.js +9 -0
- package/dist/daml-interface/runtime/daml-template.d.ts +6 -0
- package/dist/daml-interface/runtime/daml-template.js +10 -0
- package/dist/daml-interface/runtime/daml-type-descriptor.d.ts +71 -0
- package/dist/daml-interface/runtime/daml-type-descriptor.js +1 -0
- package/dist/daml-interface/runtime/daml-value-converter.d.ts +7 -0
- package/dist/daml-interface/runtime/daml-value-converter.js +370 -0
- package/dist/daml-interface/runtime/daml-value-materializer.d.ts +3 -0
- package/dist/daml-interface/runtime/daml-value-materializer.js +23 -0
- package/dist/daml-interface/writing/daml-interface-writer.js +1 -0
- package/dist/daml-lf/daml-lf-compilation.d.ts +1 -0
- package/dist/daml-lf/daml-lf-compilation.js +24 -3
- package/dist/daml-lf/model/daml-lf-builtin-type.d.ts +9 -0
- package/dist/daml-lf/model/daml-lf-builtin-type.js +9 -0
- package/dist/daml-lf/model/daml-lf-data-type.d.ts +18 -1
- package/dist/daml-lf/model/daml-lf-data-type.js +8 -1
- package/dist/daml-lf/model/daml-lf-type.d.ts +2 -0
- package/dist/daml-lf/model/daml-lf-type.js +2 -0
- package/dist/daml-lf/model/lf-2-model-mapper.d.ts +1 -0
- package/dist/daml-lf/model/lf-2-model-mapper.js +81 -25
- package/dist/daml-lf/semantics/daml-lf-semantic-model.d.ts +3 -0
- package/dist/daml-lf/semantics/daml-lf-semantic-model.js +5 -1
- package/dist/query/pqs/pqs-query-client.js +15 -0
- package/dist/query/pqs/pqs-sql-compiler.js +35 -7
- package/package.json +1 -1
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import { DamlLfBuiltinType } from "../../daml-lf/model/daml-lf-builtin-type.js";
|
|
2
|
+
import { GeneratedNamedTypeFile } from "../emission-model/generated-named-type-file.js";
|
|
3
|
+
import { TypeScriptNameResolver } from "./type-script-name-resolver.js";
|
|
4
|
+
/** Emits TypeScript declarations for reachable named DAML records, variants, and enums. */
|
|
5
|
+
export class NamedTypeEmitter {
|
|
6
|
+
nameResolver;
|
|
7
|
+
constructor(nameResolver = new TypeScriptNameResolver()) {
|
|
8
|
+
this.nameResolver = nameResolver;
|
|
9
|
+
void this.nameResolver;
|
|
10
|
+
}
|
|
11
|
+
/** Prepares shared package/module output mappings with template emission. */
|
|
12
|
+
prepareProjectOrThrow(templates, definitions) {
|
|
13
|
+
this.nameResolver.prepareProjectOrThrow(templates, definitions);
|
|
14
|
+
}
|
|
15
|
+
/** Emits one `types.ts` module for every reachable DAML package/module identity. */
|
|
16
|
+
emitNamedTypeFiles(definitions) {
|
|
17
|
+
this.nameResolver.prepareProjectOrThrow([], definitions);
|
|
18
|
+
return this.emitPreparedNamedTypeFiles(definitions);
|
|
19
|
+
}
|
|
20
|
+
/** Emits named type files from an already prepared shared name resolver. */
|
|
21
|
+
emitPreparedNamedTypeFiles(definitions, templateFiles = []) {
|
|
22
|
+
const modules = this.resolveModulesOrThrow(definitions);
|
|
23
|
+
const names = this.resolveDefinitionNamesOrThrow(definitions, this.mergeReservedNames(this.getReservedModuleExports(templateFiles), this.getReservedRuntimeBindings(definitions)));
|
|
24
|
+
const fieldPropertyNames = this.resolveFieldPropertyNames(definitions);
|
|
25
|
+
return [...modules.values()].map((module) => {
|
|
26
|
+
const moduleDefinitions = definitions.filter((definition) => definition.identity.packageId === module.packageId
|
|
27
|
+
&& definition.identity.moduleName === module.moduleName);
|
|
28
|
+
const externalTypeAliases = this.resolveExternalTypeAliases(module, moduleDefinitions, names);
|
|
29
|
+
const imports = this.emitImports(module, moduleDefinitions, modules, names, externalTypeAliases);
|
|
30
|
+
return new GeneratedNamedTypeFile({
|
|
31
|
+
path: module.path,
|
|
32
|
+
contents: [
|
|
33
|
+
...imports,
|
|
34
|
+
...(imports.length === 0 ? [] : [""]),
|
|
35
|
+
...moduleDefinitions.map((definition) => this.emitDefinition(definition, names, externalTypeAliases, fieldPropertyNames)),
|
|
36
|
+
"",
|
|
37
|
+
].join("\n"),
|
|
38
|
+
packageId: module.packageId,
|
|
39
|
+
moduleName: module.moduleName,
|
|
40
|
+
namespaceAlias: module.namespaceAlias,
|
|
41
|
+
exportedTypeNames: moduleDefinitions.map((definition) => this.getDefinitionName(definition, names)),
|
|
42
|
+
exportedTypeNamesByIdentity: new Map(moduleDefinitions.map((definition) => [
|
|
43
|
+
this.getDefinitionKey(definition.identity.packageId, definition.identity.moduleName, definition.identity.name),
|
|
44
|
+
this.getDefinitionName(definition, names),
|
|
45
|
+
])),
|
|
46
|
+
fieldPropertyNames: new Map([...fieldPropertyNames.entries()].filter(([key]) => key.startsWith(`${module.key}\u0000`))),
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
emitDefinition(definition, names, externalTypeAliases, fieldPropertyNames) {
|
|
51
|
+
const name = this.getDefinitionName(definition, names);
|
|
52
|
+
if (definition.kind === "record") {
|
|
53
|
+
return [
|
|
54
|
+
`export interface ${name} {`,
|
|
55
|
+
...definition.fields.map((field, index) => ` readonly ${this.getFieldPropertyName(definition, index, fieldPropertyNames)}: ${this.getTypeName(field.type, names, externalTypeAliases)};`),
|
|
56
|
+
"}",
|
|
57
|
+
].join("\n");
|
|
58
|
+
}
|
|
59
|
+
else if (definition.kind === "variant") {
|
|
60
|
+
return [
|
|
61
|
+
`export type ${name} =`,
|
|
62
|
+
...definition.constructors.map((constructor) => ` | { readonly tag: ${JSON.stringify(constructor.constructor)}; readonly value: ${this.getTypeName(constructor.payload, names, externalTypeAliases)}; }`),
|
|
63
|
+
].map((line, index, lines) => index === lines.length - 1 ? `${line};` : line).join("\n");
|
|
64
|
+
}
|
|
65
|
+
return `export type ${name} = ${definition.constructors.map((constructor) => JSON.stringify(constructor)).join(" | ")};`;
|
|
66
|
+
}
|
|
67
|
+
emitImports(module, definitions, modules, names, externalTypeAliases) {
|
|
68
|
+
const imports = new Map();
|
|
69
|
+
const runtimeTypes = new Set();
|
|
70
|
+
for (const definition of definitions) {
|
|
71
|
+
for (const primitive of this.getRuntimePrimitiveTypes(definition)) {
|
|
72
|
+
runtimeTypes.add(primitive);
|
|
73
|
+
}
|
|
74
|
+
for (const reference of this.getNamedReferences(definition)) {
|
|
75
|
+
const referencedModuleKey = this.getModuleKey(reference.identity.packageId, reference.identity.moduleName);
|
|
76
|
+
if (referencedModuleKey === module.key) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const referencedModule = modules.get(referencedModuleKey);
|
|
80
|
+
if (referencedModule === undefined) {
|
|
81
|
+
throw new Error(`Cannot emit unresolved named DAML type '${reference.identity.name}'`);
|
|
82
|
+
}
|
|
83
|
+
const importPath = this.relativeFilePath(module.path, referencedModule.path);
|
|
84
|
+
const importedNames = imports.get(importPath) ?? new Map();
|
|
85
|
+
importedNames.set(this.getNamedReferenceTypeName(reference.identity, names), this.getExternalTypeAlias(reference.identity, externalTypeAliases));
|
|
86
|
+
imports.set(importPath, importedNames);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return [
|
|
90
|
+
...(runtimeTypes.size === 0 ? [] : [
|
|
91
|
+
`import type { ${[...runtimeTypes].sort().join(", ")} } from ${JSON.stringify(this.relativeFilePath(module.path, "generated/support/runtime.ts"))};`,
|
|
92
|
+
]),
|
|
93
|
+
...[...imports.entries()]
|
|
94
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
95
|
+
.map(([path, importedNames]) => `import type { ${[...importedNames.entries()]
|
|
96
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
97
|
+
.map(([exportedName, alias]) => `${exportedName} as ${alias}`)
|
|
98
|
+
.join(", ")} } from ${JSON.stringify(path)};`),
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
resolveExternalTypeAliases(module, definitions, names) {
|
|
102
|
+
const references = new Map();
|
|
103
|
+
for (const definition of definitions) {
|
|
104
|
+
for (const reference of this.getNamedReferences(definition)) {
|
|
105
|
+
const moduleKey = this.getModuleKey(reference.identity.packageId, reference.identity.moduleName);
|
|
106
|
+
if (moduleKey !== module.key) {
|
|
107
|
+
const key = this.getDefinitionKey(reference.identity.packageId, reference.identity.moduleName, reference.identity.name);
|
|
108
|
+
references.set(key, reference.identity);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const aliases = new Map();
|
|
113
|
+
const usedNames = new Set(definitions.map((definition) => this.getDefinitionName(definition, names)));
|
|
114
|
+
for (const [key, identity] of [...references.entries()].sort(([left], [right]) => left.localeCompare(right))) {
|
|
115
|
+
const baseName = this.safeTypeName(`${identity.packageId} ${identity.moduleName} ${identity.name}`);
|
|
116
|
+
let alias = baseName;
|
|
117
|
+
let escalation = 2;
|
|
118
|
+
if (usedNames.has(alias)) {
|
|
119
|
+
alias = `${baseName}_${this.shortHash(key)}`;
|
|
120
|
+
}
|
|
121
|
+
while (usedNames.has(alias)) {
|
|
122
|
+
alias = `${baseName}_${this.shortHash(key)}_${escalation}`;
|
|
123
|
+
escalation += 1;
|
|
124
|
+
}
|
|
125
|
+
usedNames.add(alias);
|
|
126
|
+
aliases.set(key, alias);
|
|
127
|
+
}
|
|
128
|
+
return aliases;
|
|
129
|
+
}
|
|
130
|
+
getExternalTypeAlias(identity, aliases) {
|
|
131
|
+
const alias = aliases.get(this.getDefinitionKey(identity.packageId, identity.moduleName, identity.name));
|
|
132
|
+
if (alias === undefined) {
|
|
133
|
+
throw new Error(`Cannot resolve external named DAML type '${identity.name}'`);
|
|
134
|
+
}
|
|
135
|
+
return alias;
|
|
136
|
+
}
|
|
137
|
+
*getNamedReferences(type) {
|
|
138
|
+
switch (type.kind) {
|
|
139
|
+
case "namedReference":
|
|
140
|
+
yield type;
|
|
141
|
+
return;
|
|
142
|
+
case "contractId": return;
|
|
143
|
+
case "optional":
|
|
144
|
+
case "list":
|
|
145
|
+
yield* this.getNamedReferences(type.element);
|
|
146
|
+
return;
|
|
147
|
+
case "textMap":
|
|
148
|
+
yield* this.getNamedReferences(type.value);
|
|
149
|
+
return;
|
|
150
|
+
case "genMap":
|
|
151
|
+
yield* this.getNamedReferences(type.key);
|
|
152
|
+
yield* this.getNamedReferences(type.value);
|
|
153
|
+
return;
|
|
154
|
+
case "record":
|
|
155
|
+
for (const field of type.fields) {
|
|
156
|
+
yield* this.getNamedReferences(field.type);
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
case "variant":
|
|
160
|
+
for (const constructor of type.constructors) {
|
|
161
|
+
yield* this.getNamedReferences(constructor.payload);
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
case "primitive":
|
|
165
|
+
case "enum":
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
getTypeName(type, names, externalTypeAliases) {
|
|
170
|
+
switch (type.kind) {
|
|
171
|
+
case "primitive":
|
|
172
|
+
return this.getPrimitiveTypeName(type.builtinType);
|
|
173
|
+
case "contractId":
|
|
174
|
+
return "string";
|
|
175
|
+
case "optional":
|
|
176
|
+
return `${this.getTypeName(type.element, names, externalTypeAliases)} | undefined`;
|
|
177
|
+
case "list":
|
|
178
|
+
return `readonly ${this.getTypeName(type.element, names, externalTypeAliases)}[]`;
|
|
179
|
+
case "textMap":
|
|
180
|
+
return `ReadonlyMap<string, ${this.getTypeName(type.value, names, externalTypeAliases)}>`;
|
|
181
|
+
case "genMap":
|
|
182
|
+
return `ReadonlyMap<${this.getTypeName(type.key, names, externalTypeAliases)}, ${this.getTypeName(type.value, names, externalTypeAliases)}>`;
|
|
183
|
+
case "record":
|
|
184
|
+
case "variant":
|
|
185
|
+
case "enum":
|
|
186
|
+
throw new Error("Named DAML declarations must not contain anonymous record, variant, or enum shapes");
|
|
187
|
+
case "namedReference":
|
|
188
|
+
return externalTypeAliases.get(this.getDefinitionKey(type.identity.packageId, type.identity.moduleName, type.identity.name)) ?? this.getNamedReferenceTypeName(type.identity, names);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
getPrimitiveTypeName(type) {
|
|
192
|
+
switch (type) {
|
|
193
|
+
case DamlLfBuiltinType.unit:
|
|
194
|
+
return "DamlUnit";
|
|
195
|
+
case DamlLfBuiltinType.bool:
|
|
196
|
+
return "boolean";
|
|
197
|
+
case DamlLfBuiltinType.int64:
|
|
198
|
+
return "bigint";
|
|
199
|
+
case DamlLfBuiltinType.date:
|
|
200
|
+
return "DamlDate";
|
|
201
|
+
case DamlLfBuiltinType.timestamp:
|
|
202
|
+
return "DamlTimestamp";
|
|
203
|
+
case DamlLfBuiltinType.numeric:
|
|
204
|
+
return "DamlNumeric";
|
|
205
|
+
case DamlLfBuiltinType.party:
|
|
206
|
+
return "DamlParty";
|
|
207
|
+
case DamlLfBuiltinType.text:
|
|
208
|
+
return "string";
|
|
209
|
+
default:
|
|
210
|
+
throw new Error(`Cannot emit unsupported primitive DAML type '${type}'`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
resolveModulesOrThrow(definitions) {
|
|
214
|
+
const identities = new Map();
|
|
215
|
+
for (const definition of definitions) {
|
|
216
|
+
const key = this.getModuleKey(definition.identity.packageId, definition.identity.moduleName);
|
|
217
|
+
identities.set(key, {
|
|
218
|
+
packageId: definition.identity.packageId,
|
|
219
|
+
moduleName: definition.identity.moduleName,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return new Map([...identities.entries()].map(([key, identity]) => [
|
|
223
|
+
key,
|
|
224
|
+
{
|
|
225
|
+
...identity,
|
|
226
|
+
key,
|
|
227
|
+
path: `${this.nameResolver.getNamedTypeModuleDirectoryPath(identity.packageId, identity.moduleName)}/types.ts`,
|
|
228
|
+
namespaceAlias: this.nameResolver.getNamedTypeModuleNamespaceAlias(identity.packageId, identity.moduleName),
|
|
229
|
+
},
|
|
230
|
+
]));
|
|
231
|
+
}
|
|
232
|
+
resolveDefinitionNamesOrThrow(definitions, reservedNamesByModule) {
|
|
233
|
+
const values = definitions.map((definition) => [
|
|
234
|
+
this.getDefinitionKey(definition.identity.packageId, definition.identity.moduleName, definition.identity.name),
|
|
235
|
+
definition,
|
|
236
|
+
]);
|
|
237
|
+
const duplicate = new Set();
|
|
238
|
+
for (const [key] of values) {
|
|
239
|
+
if (duplicate.has(key)) {
|
|
240
|
+
throw new Error(`Cannot emit duplicate named DAML type '${key.replaceAll("\u0000", ":")}'`);
|
|
241
|
+
}
|
|
242
|
+
duplicate.add(key);
|
|
243
|
+
}
|
|
244
|
+
const resolvedNames = this.resolveCollisionSafeNames(values, ([, definition]) => this.safeTypeName(definition.identity.name), ([, definition]) => this.getModuleKey(definition.identity.packageId, definition.identity.moduleName), "_", reservedNamesByModule);
|
|
245
|
+
return new Map(values.map((value) => [
|
|
246
|
+
value[0],
|
|
247
|
+
resolvedNames.get(value),
|
|
248
|
+
]));
|
|
249
|
+
}
|
|
250
|
+
resolveCollisionSafeNames(values, getBaseName, getScope, collisionSeparator = "_", reservedNamesByScope = new Map()) {
|
|
251
|
+
const counts = new Map();
|
|
252
|
+
for (const value of values) {
|
|
253
|
+
const key = `${getScope(value)}\u0000${getBaseName(value)}`;
|
|
254
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
255
|
+
}
|
|
256
|
+
const names = new Map();
|
|
257
|
+
const allocated = new Map();
|
|
258
|
+
for (const value of [...values].sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)))) {
|
|
259
|
+
const scope = getScope(value);
|
|
260
|
+
const baseName = getBaseName(value);
|
|
261
|
+
const groupKey = `${scope}\u0000${baseName}`;
|
|
262
|
+
const suffix = counts.get(groupKey) === 1 ? "" : `${collisionSeparator}${this.shortHash(JSON.stringify(value))}`;
|
|
263
|
+
const baseCandidate = `${baseName}${suffix}`;
|
|
264
|
+
const used = allocated.get(scope) ?? new Set(reservedNamesByScope.get(scope));
|
|
265
|
+
let candidate = used.has(baseCandidate) ? `${baseCandidate}Type` : baseCandidate;
|
|
266
|
+
let escalation = 2;
|
|
267
|
+
while (used.has(candidate)) {
|
|
268
|
+
candidate = `${baseCandidate}_${escalation}`;
|
|
269
|
+
escalation += 1;
|
|
270
|
+
}
|
|
271
|
+
used.add(candidate);
|
|
272
|
+
allocated.set(scope, used);
|
|
273
|
+
names.set(value, candidate);
|
|
274
|
+
}
|
|
275
|
+
return names;
|
|
276
|
+
}
|
|
277
|
+
getReservedModuleExports(templateFiles) {
|
|
278
|
+
const exportsByModule = new Map();
|
|
279
|
+
for (const file of templateFiles) {
|
|
280
|
+
const binding = file.binding;
|
|
281
|
+
const moduleKey = this.getModuleKeyFromTemplateIdentity(binding.templateIdentityKey);
|
|
282
|
+
const exports = exportsByModule.get(moduleKey) ?? new Set();
|
|
283
|
+
exports.add(binding.className);
|
|
284
|
+
exports.add(binding.createFieldsTypeName);
|
|
285
|
+
exports.add(binding.createdEventTypeName);
|
|
286
|
+
for (const choice of binding.choices) {
|
|
287
|
+
exports.add(choice.choiceTypeName);
|
|
288
|
+
exports.add(choice.exercisedEventTypeName);
|
|
289
|
+
}
|
|
290
|
+
exportsByModule.set(moduleKey, exports);
|
|
291
|
+
}
|
|
292
|
+
return exportsByModule;
|
|
293
|
+
}
|
|
294
|
+
getReservedRuntimeBindings(definitions) {
|
|
295
|
+
const bindings = new Set([
|
|
296
|
+
"DamlDate",
|
|
297
|
+
"DamlNumeric",
|
|
298
|
+
"DamlParty",
|
|
299
|
+
"DamlTimestamp",
|
|
300
|
+
"DamlUnit",
|
|
301
|
+
]);
|
|
302
|
+
return new Map([...new Set(definitions.map((definition) => this.getModuleKey(definition.identity.packageId, definition.identity.moduleName)))].map((moduleKey) => [
|
|
303
|
+
moduleKey,
|
|
304
|
+
bindings,
|
|
305
|
+
]));
|
|
306
|
+
}
|
|
307
|
+
mergeReservedNames(...reservations) {
|
|
308
|
+
const merged = new Map();
|
|
309
|
+
for (const reservation of reservations) {
|
|
310
|
+
for (const [moduleKey, names] of reservation) {
|
|
311
|
+
const mergedNames = merged.get(moduleKey) ?? new Set();
|
|
312
|
+
for (const name of names) {
|
|
313
|
+
mergedNames.add(name);
|
|
314
|
+
}
|
|
315
|
+
merged.set(moduleKey, mergedNames);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return merged;
|
|
319
|
+
}
|
|
320
|
+
resolveFieldPropertyNames(definitions) {
|
|
321
|
+
const fields = definitions.flatMap((definition) => definition.kind === "record"
|
|
322
|
+
? definition.fields.map((field, index) => ({ definition, field, index }))
|
|
323
|
+
: []);
|
|
324
|
+
const counts = new Map();
|
|
325
|
+
for (const item of fields) {
|
|
326
|
+
const baseName = this.safePropertyName(item.field.propertyName);
|
|
327
|
+
const groupKey = `${this.getDefinitionKey(item.definition.identity.packageId, item.definition.identity.moduleName, item.definition.identity.name)}\u0000${baseName}`;
|
|
328
|
+
counts.set(groupKey, (counts.get(groupKey) ?? 0) + 1);
|
|
329
|
+
}
|
|
330
|
+
const names = new Map();
|
|
331
|
+
for (const item of [...fields].sort((left, right) => this.getFieldKey(left.definition, left.index).localeCompare(this.getFieldKey(right.definition, right.index)))) {
|
|
332
|
+
const baseName = this.safePropertyName(item.field.propertyName);
|
|
333
|
+
const definitionKey = this.getDefinitionKey(item.definition.identity.packageId, item.definition.identity.moduleName, item.definition.identity.name);
|
|
334
|
+
const groupKey = `${definitionKey}\u0000${baseName}`;
|
|
335
|
+
const name = counts.get(groupKey) === 1
|
|
336
|
+
? baseName
|
|
337
|
+
: `${baseName}_${this.shortHash(this.getFieldKey(item.definition, item.index))}`;
|
|
338
|
+
names.set(this.getFieldKey(item.definition, item.index), name);
|
|
339
|
+
}
|
|
340
|
+
return names;
|
|
341
|
+
}
|
|
342
|
+
getFieldPropertyName(definition, index, names) {
|
|
343
|
+
const name = names.get(this.getFieldKey(definition, index));
|
|
344
|
+
if (name === undefined) {
|
|
345
|
+
throw new Error(`Cannot resolve property name for named DAML type '${definition.identity.name}'`);
|
|
346
|
+
}
|
|
347
|
+
return name;
|
|
348
|
+
}
|
|
349
|
+
getFieldKey(definition, index) {
|
|
350
|
+
return `${this.getDefinitionKey(definition.identity.packageId, definition.identity.moduleName, definition.identity.name)}\u0000field\u0000${index}`;
|
|
351
|
+
}
|
|
352
|
+
safePropertyName(value) {
|
|
353
|
+
const name = value.replace(/[^A-Za-z0-9_$]/g, "_");
|
|
354
|
+
if (name.length === 0) {
|
|
355
|
+
return "field";
|
|
356
|
+
}
|
|
357
|
+
return /^[0-9]/.test(name) ? `_${name}` : name;
|
|
358
|
+
}
|
|
359
|
+
getModuleKeyFromTemplateIdentity(identityKey) {
|
|
360
|
+
const [packageId, moduleName] = identityKey.split("\u0000");
|
|
361
|
+
return this.getModuleKey(packageId, moduleName);
|
|
362
|
+
}
|
|
363
|
+
relativeFilePath(fromPath, toPath) {
|
|
364
|
+
const from = fromPath.split("/").slice(0, -1);
|
|
365
|
+
const to = toPath.split("/");
|
|
366
|
+
while (from[0] === to[0] && from.length > 0) {
|
|
367
|
+
from.shift();
|
|
368
|
+
to.shift();
|
|
369
|
+
}
|
|
370
|
+
const relativePath = from.map(() => "..").concat(to).join("/") || ".";
|
|
371
|
+
return `${relativePath.startsWith(".") ? relativePath : `./${relativePath}`}`.replace(/\.ts$/, ".js");
|
|
372
|
+
}
|
|
373
|
+
getDefinitionName(definition, names) {
|
|
374
|
+
return this.getNamedReferenceTypeName(definition.identity, names);
|
|
375
|
+
}
|
|
376
|
+
getNamedReferenceTypeName(identity, names) {
|
|
377
|
+
const name = names.get(this.getDefinitionKey(identity.packageId, identity.moduleName, identity.name));
|
|
378
|
+
if (name === undefined) {
|
|
379
|
+
throw new Error(`Cannot emit unresolved named DAML type '${identity.name}'`);
|
|
380
|
+
}
|
|
381
|
+
return name;
|
|
382
|
+
}
|
|
383
|
+
getModuleKey(packageId, moduleName) {
|
|
384
|
+
return `${packageId}\u0000${moduleName}`;
|
|
385
|
+
}
|
|
386
|
+
getDefinitionKey(packageId, moduleName, name) {
|
|
387
|
+
return `${this.getModuleKey(packageId, moduleName)}\u0000${name}`;
|
|
388
|
+
}
|
|
389
|
+
safeTypeName(value) {
|
|
390
|
+
const normalized = value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[^A-Za-z0-9]+/g, " ").trim();
|
|
391
|
+
if (normalized.length === 0) {
|
|
392
|
+
throw new Error("Cannot normalize an empty DAML identifier");
|
|
393
|
+
}
|
|
394
|
+
const name = normalized.split(/\s+/).map((segment) => `${segment[0].toUpperCase()}${segment.slice(1)}`).join("");
|
|
395
|
+
return /^[0-9]/.test(name) ? `_${name}` : name;
|
|
396
|
+
}
|
|
397
|
+
*getRuntimePrimitiveTypes(type) {
|
|
398
|
+
switch (type.kind) {
|
|
399
|
+
case "primitive": {
|
|
400
|
+
const name = this.getPrimitiveTypeName(type.builtinType);
|
|
401
|
+
if (name.startsWith("Daml")) {
|
|
402
|
+
yield name;
|
|
403
|
+
}
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
case "contractId": return;
|
|
407
|
+
case "optional":
|
|
408
|
+
case "list":
|
|
409
|
+
yield* this.getRuntimePrimitiveTypes(type.element);
|
|
410
|
+
return;
|
|
411
|
+
case "textMap":
|
|
412
|
+
yield* this.getRuntimePrimitiveTypes(type.value);
|
|
413
|
+
return;
|
|
414
|
+
case "genMap":
|
|
415
|
+
yield* this.getRuntimePrimitiveTypes(type.key);
|
|
416
|
+
yield* this.getRuntimePrimitiveTypes(type.value);
|
|
417
|
+
return;
|
|
418
|
+
case "record":
|
|
419
|
+
for (const field of type.fields) {
|
|
420
|
+
yield* this.getRuntimePrimitiveTypes(field.type);
|
|
421
|
+
}
|
|
422
|
+
return;
|
|
423
|
+
case "variant":
|
|
424
|
+
for (const constructor of type.constructors) {
|
|
425
|
+
yield* this.getRuntimePrimitiveTypes(constructor.payload);
|
|
426
|
+
}
|
|
427
|
+
return;
|
|
428
|
+
case "enum":
|
|
429
|
+
case "namedReference":
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
shortHash(value) {
|
|
434
|
+
let hash = 0x811c9dc5;
|
|
435
|
+
for (const character of value) {
|
|
436
|
+
hash ^= character.charCodeAt(0);
|
|
437
|
+
hash = Math.imul(hash, 0x01000193);
|
|
438
|
+
}
|
|
439
|
+
return (hash >>> 0).toString(36).padStart(6, "0").slice(-6);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { DamlInterfaceAnalysisResult } from "../analysis/daml-interface-analyzer.js";
|
|
2
2
|
import { GeneratedDamlInterfaceProject } from "../emission-model/generated-daml-interface-project.js";
|
|
3
|
+
import { NamedTypeEmitter } from "./named-type-emitter.js";
|
|
3
4
|
import { RegistryEmitter } from "./registry-emitter.js";
|
|
4
5
|
import { SupportFileEmitter } from "./support-file-emitter.js";
|
|
5
6
|
import { TemplateBindingEmitter } from "./template-binding-emitter.js";
|
|
7
|
+
import { TypeScriptNameResolver } from "./type-script-name-resolver.js";
|
|
6
8
|
export declare class ProjectEmitter {
|
|
9
|
+
private readonly nameResolver;
|
|
7
10
|
private readonly templateBindingEmitter;
|
|
8
11
|
private readonly supportFileEmitter;
|
|
9
12
|
private readonly registryEmitter;
|
|
10
|
-
|
|
13
|
+
private readonly namedTypeEmitter;
|
|
14
|
+
constructor(nameResolver?: TypeScriptNameResolver, templateBindingEmitter?: TemplateBindingEmitter, supportFileEmitter?: SupportFileEmitter, registryEmitter?: RegistryEmitter, namedTypeEmitter?: NamedTypeEmitter);
|
|
11
15
|
/** Emits the complete in-memory DAML interface project from analyzed templates. */
|
|
12
16
|
emitProject(analysis: DamlInterfaceAnalysisResult): GeneratedDamlInterfaceProject;
|
|
13
17
|
}
|
|
@@ -1,36 +1,53 @@
|
|
|
1
1
|
import { GeneratedDamlInterfaceProject } from "../emission-model/generated-daml-interface-project.js";
|
|
2
|
+
import { NamedTypeEmitter } from "./named-type-emitter.js";
|
|
2
3
|
import { RegistryEmitter } from "./registry-emitter.js";
|
|
3
4
|
import { SupportFileEmitter } from "./support-file-emitter.js";
|
|
4
5
|
import { TemplateBindingEmitter } from "./template-binding-emitter.js";
|
|
6
|
+
import { TypeScriptNameResolver } from "./type-script-name-resolver.js";
|
|
5
7
|
export class ProjectEmitter {
|
|
8
|
+
nameResolver;
|
|
6
9
|
templateBindingEmitter;
|
|
7
10
|
supportFileEmitter;
|
|
8
11
|
registryEmitter;
|
|
9
|
-
|
|
12
|
+
namedTypeEmitter;
|
|
13
|
+
constructor(nameResolver = new TypeScriptNameResolver(), templateBindingEmitter = new TemplateBindingEmitter(nameResolver), supportFileEmitter = new SupportFileEmitter(), registryEmitter = new RegistryEmitter(), namedTypeEmitter = new NamedTypeEmitter(nameResolver)) {
|
|
14
|
+
this.nameResolver = nameResolver;
|
|
10
15
|
this.templateBindingEmitter = templateBindingEmitter;
|
|
11
16
|
this.supportFileEmitter = supportFileEmitter;
|
|
12
17
|
this.registryEmitter = registryEmitter;
|
|
18
|
+
this.namedTypeEmitter = namedTypeEmitter;
|
|
19
|
+
void this.nameResolver;
|
|
13
20
|
void this.templateBindingEmitter;
|
|
21
|
+
void this.namedTypeEmitter;
|
|
14
22
|
void this.supportFileEmitter;
|
|
15
23
|
void this.registryEmitter;
|
|
16
24
|
}
|
|
17
25
|
/** Emits the complete in-memory DAML interface project from analyzed templates. */
|
|
18
26
|
emitProject(analysis) {
|
|
19
|
-
|
|
20
|
-
const
|
|
27
|
+
this.namedTypeEmitter.prepareProjectOrThrow(analysis.templates, analysis.typeDefinitions);
|
|
28
|
+
const templateBindingFiles = analysis.templates.map((template) => this.templateBindingEmitter.emitTemplateBindingFile(template));
|
|
29
|
+
const namedTypeFiles = this.namedTypeEmitter.emitPreparedNamedTypeFiles(analysis.typeDefinitions, templateBindingFiles);
|
|
30
|
+
const templateFiles = analysis.templates.map((template) => this.templateBindingEmitter.emitTemplateFile(template, namedTypeFiles));
|
|
31
|
+
const supportFiles = [
|
|
32
|
+
...this.supportFileEmitter.emitSupportFiles(analysis, namedTypeFiles),
|
|
33
|
+
...this.supportFileEmitter.emitNamespaceFiles(new GeneratedDamlInterfaceProject({ templateFiles, namedTypeFiles })),
|
|
34
|
+
];
|
|
21
35
|
const baseProject = new GeneratedDamlInterfaceProject({
|
|
22
36
|
templateFiles,
|
|
37
|
+
namedTypeFiles,
|
|
23
38
|
supportFiles,
|
|
24
39
|
});
|
|
25
40
|
const registryFile = this.registryEmitter.emitRegistry(baseProject);
|
|
26
41
|
const projectWithRegistry = new GeneratedDamlInterfaceProject({
|
|
27
42
|
templateFiles,
|
|
43
|
+
namedTypeFiles,
|
|
28
44
|
supportFiles,
|
|
29
45
|
registryFile,
|
|
30
46
|
});
|
|
31
47
|
const indexFile = this.supportFileEmitter.emitIndexFile(projectWithRegistry);
|
|
32
48
|
return new GeneratedDamlInterfaceProject({
|
|
33
49
|
templateFiles,
|
|
50
|
+
namedTypeFiles,
|
|
34
51
|
supportFiles,
|
|
35
52
|
registryFile,
|
|
36
53
|
indexFile,
|
|
@@ -3,4 +3,5 @@ import { GeneratedRegistryFile } from "../emission-model/generated-registry-file
|
|
|
3
3
|
export declare class RegistryEmitter {
|
|
4
4
|
/** Emits a registry that dispatches created and exercised events by template id. */
|
|
5
5
|
emitRegistry(project: GeneratedDamlInterfaceProject): GeneratedRegistryFile;
|
|
6
|
+
private emitCases;
|
|
6
7
|
}
|
|
@@ -8,27 +8,31 @@ export class RegistryEmitter {
|
|
|
8
8
|
.replace(/\.ts$/, ".js");
|
|
9
9
|
return `import { ${file.binding.className} } from "${modulePath}";`;
|
|
10
10
|
});
|
|
11
|
-
const createdCases =
|
|
12
|
-
const exercisedCases =
|
|
11
|
+
const createdCases = this.emitCases(project, "fromCreatedEvent");
|
|
12
|
+
const exercisedCases = this.emitCases(project, "fromExercisedEvent");
|
|
13
13
|
return new GeneratedRegistryFile({
|
|
14
14
|
path: "generated/registry.ts",
|
|
15
15
|
contents: [
|
|
16
|
+
'import { DamlMaterializationError, normalizeDamlCreatedEventSource, normalizeDamlExercisedEventSource } from "@distrohelena/canton-typescript-sdk/daml-interface";',
|
|
17
|
+
'import type { DamlCreatedEventSource, DamlExercisedEventSource } from "@distrohelena/canton-typescript-sdk/daml-interface";',
|
|
16
18
|
...importLines,
|
|
17
19
|
"",
|
|
18
20
|
"export class GeneratedRegistry {",
|
|
19
|
-
" public static
|
|
20
|
-
"
|
|
21
|
+
" public static fromCreatedEvent(event: DamlCreatedEventSource): unknown {",
|
|
22
|
+
" const normalized = normalizeDamlCreatedEventSource(event);",
|
|
23
|
+
" switch (`${normalized.metadata.templateId.packageId}:${normalized.metadata.templateId.moduleName}:${normalized.metadata.templateId.entityName}`) {",
|
|
21
24
|
...createdCases,
|
|
22
25
|
" default:",
|
|
23
|
-
"
|
|
26
|
+
" throw new DamlMaterializationError(\"template ID\", \"no generated template binding matches the created event\");",
|
|
24
27
|
" }",
|
|
25
28
|
" }",
|
|
26
29
|
"",
|
|
27
|
-
" public static
|
|
28
|
-
"
|
|
30
|
+
" public static fromExercisedEvent(event: DamlExercisedEventSource): unknown {",
|
|
31
|
+
" const normalized = normalizeDamlExercisedEventSource(event);",
|
|
32
|
+
" switch (`${normalized.metadata.templateId.packageId}:${normalized.metadata.templateId.moduleName}:${normalized.metadata.templateId.entityName}`) {",
|
|
29
33
|
...exercisedCases,
|
|
30
34
|
" default:",
|
|
31
|
-
"
|
|
35
|
+
" throw new DamlMaterializationError(\"template ID\", \"no generated template binding matches the exercised event\");",
|
|
32
36
|
" }",
|
|
33
37
|
" }",
|
|
34
38
|
"}",
|
|
@@ -36,4 +40,7 @@ export class RegistryEmitter {
|
|
|
36
40
|
].join("\n"),
|
|
37
41
|
});
|
|
38
42
|
}
|
|
43
|
+
emitCases(project, methodName) {
|
|
44
|
+
return project.templateFiles.map((file) => ` case "${file.binding.templateIdLiteral}":\n return ${file.binding.className}.${methodName}(event);`);
|
|
45
|
+
}
|
|
39
46
|
}
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
import { DamlInterfaceAnalysisResult } from "../analysis/daml-interface-analyzer.js";
|
|
1
2
|
import { GeneratedDamlInterfaceProject } from "../emission-model/generated-daml-interface-project.js";
|
|
3
|
+
import { GeneratedNamedTypeFile } from "../emission-model/generated-named-type-file.js";
|
|
2
4
|
import { GeneratedSupportFile } from "../emission-model/generated-support-file.js";
|
|
3
5
|
export declare class SupportFileEmitter {
|
|
4
6
|
/** Emits shared support files for the generated DAML interface project. */
|
|
5
|
-
emitSupportFiles(): readonly GeneratedSupportFile[];
|
|
7
|
+
emitSupportFiles(analysis: DamlInterfaceAnalysisResult, namedTypeFiles?: readonly GeneratedNamedTypeFile[]): readonly GeneratedSupportFile[];
|
|
8
|
+
/** Emits one barrel module for each generated DAML package/module namespace. */
|
|
9
|
+
emitNamespaceFiles(project: GeneratedDamlInterfaceProject): readonly GeneratedSupportFile[];
|
|
6
10
|
/** Emits the generated project index file. */
|
|
7
11
|
emitIndexFile(project: GeneratedDamlInterfaceProject): GeneratedSupportFile;
|
|
12
|
+
private getNamespaceGroups;
|
|
13
|
+
private getFileNameWithoutExtension;
|
|
14
|
+
private assertDistinctModuleExportedSymbols;
|
|
15
|
+
private getExportedSymbols;
|
|
16
|
+
private describeTemplate;
|
|
17
|
+
private emitDescriptorRegistry;
|
|
18
|
+
private emitDescriptor;
|
|
19
|
+
private emitDefinitionDescriptor;
|
|
20
|
+
private getFieldPropertyName;
|
|
21
|
+
private getFieldKey;
|
|
22
|
+
private getIdentityKey;
|
|
8
23
|
}
|