@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
|
@@ -1,119 +1,420 @@
|
|
|
1
|
+
import { DamlLfBuiltinType } from "../../daml-lf/model/daml-lf-builtin-type.js";
|
|
1
2
|
import { GeneratedChoiceBinding } from "../emission-model/generated-choice-binding.js";
|
|
2
|
-
import { GeneratedTemplateBinding } from "../emission-model/generated-template-binding.js";
|
|
3
|
-
import { GeneratedTemplateBindingField, } from "../emission-model/generated-template-binding.js";
|
|
3
|
+
import { GeneratedTemplateBinding, GeneratedTemplateBindingField, } from "../emission-model/generated-template-binding.js";
|
|
4
4
|
import { GeneratedTemplateBindingFile } from "../emission-model/generated-template-binding-file.js";
|
|
5
5
|
import { TypeScriptNameResolver } from "./type-script-name-resolver.js";
|
|
6
|
+
/** Emits typed contract and exercise-event bindings for analyzed DAML templates. */
|
|
6
7
|
export class TemplateBindingEmitter {
|
|
7
8
|
nameResolver;
|
|
8
9
|
constructor(nameResolver = new TypeScriptNameResolver()) {
|
|
9
10
|
this.nameResolver = nameResolver;
|
|
10
11
|
void this.nameResolver;
|
|
11
12
|
}
|
|
13
|
+
/** Prepares stable collision-safe names before emitting a complete project. */
|
|
14
|
+
prepareTemplatesOrThrow(templates) {
|
|
15
|
+
this.nameResolver.prepareTemplatesOrThrow(templates);
|
|
16
|
+
}
|
|
12
17
|
/** Emits a generated TypeScript file for one analyzed DAML template. */
|
|
13
|
-
emitTemplateFile(template) {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
18
|
+
emitTemplateFile(template, namedTypeFiles = []) {
|
|
19
|
+
const namedReferences = this.resolveNamedReferences(template, namedTypeFiles);
|
|
20
|
+
const binding = this.createBinding(template, namedReferences);
|
|
21
|
+
return new GeneratedTemplateBindingFile({
|
|
22
|
+
path: binding.path,
|
|
23
|
+
contents: this.emitContents(binding, namedReferences),
|
|
24
|
+
binding,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** Emits binding metadata without source, for resolving named declaration exports first. */
|
|
28
|
+
emitTemplateBindingFile(template) {
|
|
29
|
+
const namedReferences = this.resolveNamedReferences(template, []);
|
|
30
|
+
const binding = this.createBinding(template, namedReferences);
|
|
16
31
|
return new GeneratedTemplateBindingFile({
|
|
17
32
|
path: binding.path,
|
|
18
|
-
contents,
|
|
33
|
+
contents: "",
|
|
19
34
|
binding,
|
|
20
35
|
});
|
|
21
36
|
}
|
|
22
|
-
createBinding(template) {
|
|
37
|
+
createBinding(template, namedReferences) {
|
|
23
38
|
return new GeneratedTemplateBinding({
|
|
24
|
-
|
|
39
|
+
templateIdentityKey: this.nameResolver.getTemplateIdentityKey(template),
|
|
40
|
+
namespaceAlias: this.nameResolver.getNamespaceAlias(template),
|
|
41
|
+
className: this.nameResolver.getTemplateClassName(template),
|
|
25
42
|
templateIdLiteral: this.nameResolver.getTemplateIdLiteral(template),
|
|
26
43
|
path: this.nameResolver.getTemplateFilePath(template),
|
|
27
44
|
createFieldsTypeName: this.nameResolver.getCreateFieldsTypeName(template),
|
|
28
45
|
createdEventTypeName: this.nameResolver.getCreatedEventTypeName(template),
|
|
29
46
|
createFields: template.createFields.map((field) => new GeneratedTemplateBindingField({
|
|
30
47
|
name: field.name,
|
|
31
|
-
propertyName:
|
|
32
|
-
|
|
48
|
+
propertyName: this.nameResolver.getFieldPropertyName(template, field),
|
|
49
|
+
constructorParameterName: this.nameResolver.getFieldConstructorParameterName(template, field),
|
|
50
|
+
type: this.normalizeType(field.type),
|
|
51
|
+
typeName: this.getTypeName(this.normalizeType(field.type), namedReferences),
|
|
33
52
|
})),
|
|
34
53
|
choices: template.choices.map((choice) => new GeneratedChoiceBinding({
|
|
54
|
+
choiceIdentityKey: this.nameResolver.getChoiceIdentityKey(template, choice),
|
|
35
55
|
name: choice.name,
|
|
36
|
-
methodName:
|
|
56
|
+
methodName: this.nameResolver.getChoiceMethodName(template, choice),
|
|
37
57
|
choiceTypeName: this.nameResolver.getChoiceTypeName(template, choice),
|
|
38
58
|
exercisedEventTypeName: this.nameResolver.getExercisedEventTypeName(template, choice),
|
|
39
|
-
parameterName:
|
|
40
|
-
|
|
41
|
-
|
|
59
|
+
parameterName: this.nameResolver.getChoiceParameterName(template, choice),
|
|
60
|
+
parameterType: this.normalizeType(choice.parameterType),
|
|
61
|
+
parameterTypeName: this.getTypeName(this.normalizeType(choice.parameterType), namedReferences),
|
|
62
|
+
returnType: this.normalizeType(choice.returnType),
|
|
63
|
+
returnTypeName: this.getTypeName(this.normalizeType(choice.returnType), namedReferences),
|
|
42
64
|
})),
|
|
43
65
|
});
|
|
44
66
|
}
|
|
45
|
-
emitContents(binding) {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
].join("\n"))
|
|
55
|
-
.join("\n\n");
|
|
56
|
-
const exercisedEvents = binding.choices
|
|
57
|
-
.map((choice) => [
|
|
58
|
-
`export interface ${choice.exercisedEventTypeName} {`,
|
|
59
|
-
` choiceName: "${choice.name}";`,
|
|
60
|
-
` result: ${choice.returnTypeName};`,
|
|
61
|
-
"}",
|
|
62
|
-
].join("\n"))
|
|
63
|
-
.join("\n\n");
|
|
64
|
-
const choiceMethods = binding.choices
|
|
65
|
-
.map((choice) => [
|
|
66
|
-
` public static ${choice.methodName}(`,
|
|
67
|
-
" contractId: string,",
|
|
68
|
-
` choice: ${choice.choiceTypeName},`,
|
|
69
|
-
" ): unknown {",
|
|
70
|
-
" return {",
|
|
71
|
-
" contractId,",
|
|
72
|
-
` choiceName: "${choice.name}",`,
|
|
73
|
-
" choice,",
|
|
74
|
-
" };",
|
|
75
|
-
" }",
|
|
76
|
-
].join("\n"))
|
|
77
|
-
.join("\n\n");
|
|
78
|
-
const exercisedReturnType = binding.choices.length === 1
|
|
79
|
-
? binding.choices[0].exercisedEventTypeName
|
|
80
|
-
: binding.choices
|
|
81
|
-
.map((choice) => choice.exercisedEventTypeName)
|
|
82
|
-
.join(" | ");
|
|
67
|
+
emitContents(binding, namedReferences) {
|
|
68
|
+
const imports = this.emitImports(binding, namedReferences);
|
|
69
|
+
const fields = binding.createFields.map((field) => ` readonly ${field.propertyName}: ${field.typeName};`);
|
|
70
|
+
const constructorParameters = binding.createFields.map((field) => `${field.constructorParameterName}: ${field.typeName}`);
|
|
71
|
+
const constructorAssignments = binding.createFields.map((field) => ` this.${field.propertyName} = ${field.constructorParameterName};`);
|
|
72
|
+
const orderedArguments = binding.createFields.map((field) => ` fields.${field.propertyName},`);
|
|
73
|
+
const exercisedReturnType = binding.choices.length === 0
|
|
74
|
+
? "never"
|
|
75
|
+
: binding.choices.map((choice) => choice.exercisedEventTypeName).join(" | ");
|
|
83
76
|
return [
|
|
77
|
+
...imports,
|
|
78
|
+
"",
|
|
84
79
|
`export interface ${binding.createFieldsTypeName} {`,
|
|
85
|
-
|
|
80
|
+
...fields,
|
|
86
81
|
"}",
|
|
87
82
|
"",
|
|
88
|
-
|
|
83
|
+
this.emitTemplateClass(binding, constructorParameters, constructorAssignments, orderedArguments, exercisedReturnType),
|
|
84
|
+
...(binding.choices.length === 0 ? [] : ["", ...binding.choices.flatMap((choice) => [
|
|
85
|
+
this.emitChoiceEventClass(binding, choice),
|
|
86
|
+
"",
|
|
87
|
+
])]),
|
|
88
|
+
].join("\n");
|
|
89
|
+
}
|
|
90
|
+
emitImports(binding, namedReferences) {
|
|
91
|
+
const namedImports = new Map();
|
|
92
|
+
for (const reference of namedReferences.values()) {
|
|
93
|
+
const imported = namedImports.get(reference.path) ?? new Map();
|
|
94
|
+
imported.set(reference.exportedName, reference.alias);
|
|
95
|
+
namedImports.set(reference.path, imported);
|
|
96
|
+
}
|
|
97
|
+
return [
|
|
98
|
+
'import { DamlMaterializationError, DamlTemplate, decodeDamlValue, materializeDamlValue, normalizeDamlCreatedEventSource, normalizeDamlExercisedEventSource } from "@distrohelena/canton-typescript-sdk/daml-interface";',
|
|
99
|
+
'import type { DamlCreatedEventSource, DamlDate, DamlExercisedEventMetadata, DamlExercisedEventSource, DamlNormalizedExercisedEvent, DamlNumeric, DamlParty, DamlTimestamp, DamlTypeDescriptor, DamlUnit } from "@distrohelena/canton-typescript-sdk/daml-interface";',
|
|
100
|
+
`import { generatedDamlTypeDescriptorRegistry } from ${JSON.stringify(this.relativeFilePath(binding.path, "generated/support/descriptors.ts"))};`,
|
|
101
|
+
...[...namedImports.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([path, imported]) => `import type { ${[...imported.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([name, alias]) => `${name} as ${alias}`).join(", ")} } from ${JSON.stringify(path)};`),
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
emitTemplateClass(binding, constructorParameters, constructorAssignments, orderedArguments, exercisedReturnType) {
|
|
105
|
+
return [
|
|
106
|
+
`export class ${binding.className} extends DamlTemplate implements ${binding.createFieldsTypeName} {`,
|
|
107
|
+
` public static readonly templateId = ${JSON.stringify(binding.templateIdLiteral)};`,
|
|
108
|
+
` private static readonly descriptor: DamlTypeDescriptor = ${this.emitTemplateDescriptor(binding)};`,
|
|
89
109
|
"",
|
|
90
|
-
`
|
|
91
|
-
|
|
92
|
-
`
|
|
93
|
-
"
|
|
110
|
+
...binding.createFields.map((field) => ` public readonly ${field.propertyName}: ${field.typeName};`),
|
|
111
|
+
...(binding.createFields.length === 0 ? [] : [""]),
|
|
112
|
+
` public constructor(contractId: string${constructorParameters.length === 0 ? "" : `, ${constructorParameters.join(", ")}`}) {`,
|
|
113
|
+
" super(contractId);",
|
|
114
|
+
...constructorAssignments,
|
|
115
|
+
" }",
|
|
116
|
+
"",
|
|
117
|
+
` public static fromCreatedEvent(event: DamlCreatedEventSource): ${binding.className} {`,
|
|
118
|
+
" const normalized = normalizeDamlCreatedEventSource(event);",
|
|
119
|
+
` ${binding.className}.assertTemplateIdentity(normalized.metadata.templateId);`,
|
|
120
|
+
` const fields = materializeDamlValue<${binding.createFieldsTypeName}>(decodeDamlValue(normalized.payload, ${binding.className}.descriptor, generatedDamlTypeDescriptorRegistry, "create arguments"));`,
|
|
121
|
+
` return new ${binding.className}(`,
|
|
122
|
+
" normalized.contractId,",
|
|
123
|
+
...orderedArguments,
|
|
124
|
+
" );",
|
|
125
|
+
" }",
|
|
126
|
+
"",
|
|
127
|
+
` public static fromExercisedEvent(event: DamlExercisedEventSource): ${exercisedReturnType} {`,
|
|
128
|
+
" const normalized = normalizeDamlExercisedEventSource(event);",
|
|
129
|
+
` ${binding.className}.assertTemplateIdentity(normalized.metadata.templateId);`,
|
|
130
|
+
" switch (normalized.choice) {",
|
|
131
|
+
...binding.choices.map((choice) => ` case ${JSON.stringify(choice.name)}:\n return ${choice.exercisedEventTypeName}.fromNormalizedEvent(normalized);`),
|
|
132
|
+
" default:",
|
|
133
|
+
` throw new DamlMaterializationError("choice", \`Unexpected choice '\${normalized.choice}' for template '${binding.templateIdLiteral}'\`);`,
|
|
134
|
+
" }",
|
|
135
|
+
" }",
|
|
94
136
|
"",
|
|
95
|
-
|
|
137
|
+
" private static assertTemplateIdentity(identity: { readonly packageId: string; readonly moduleName: string; readonly entityName: string }): void {",
|
|
138
|
+
` if (identity.packageId !== ${JSON.stringify(this.packageId(binding))} || identity.moduleName !== ${JSON.stringify(this.moduleName(binding))} || identity.entityName !== ${JSON.stringify(this.entityName(binding))}) {`,
|
|
139
|
+
` throw new DamlMaterializationError("template ID", \`Expected template '${binding.templateIdLiteral}' but received '\${identity.packageId}:\${identity.moduleName}:\${identity.entityName}'\`);`,
|
|
140
|
+
" }",
|
|
141
|
+
" }",
|
|
142
|
+
"}",
|
|
143
|
+
].join("\n");
|
|
144
|
+
}
|
|
145
|
+
emitChoiceEventClass(binding, choice) {
|
|
146
|
+
return [
|
|
147
|
+
`export class ${choice.exercisedEventTypeName} {`,
|
|
148
|
+
` private static readonly argumentDescriptor: DamlTypeDescriptor = ${this.emitDescriptor(choice.parameterType)};`,
|
|
149
|
+
` private static readonly resultDescriptor: DamlTypeDescriptor = ${this.emitDescriptor(choice.returnType)};`,
|
|
96
150
|
"",
|
|
97
|
-
`
|
|
98
|
-
|
|
151
|
+
` public readonly choiceName = ${JSON.stringify(choice.name)} as const;`,
|
|
152
|
+
" public readonly contractId: string;",
|
|
153
|
+
` public readonly argument: ${choice.parameterTypeName};`,
|
|
154
|
+
` public readonly result: ${choice.returnTypeName};`,
|
|
155
|
+
" public readonly consuming: boolean;",
|
|
156
|
+
" public readonly metadata: DamlExercisedEventMetadata;",
|
|
99
157
|
"",
|
|
100
|
-
|
|
101
|
-
"
|
|
102
|
-
|
|
103
|
-
"
|
|
104
|
-
"
|
|
158
|
+
" public constructor(contractId: string, argument: " + choice.parameterTypeName + ", result: " + choice.returnTypeName + ", consuming: boolean, metadata: DamlExercisedEventMetadata) {",
|
|
159
|
+
" this.contractId = contractId;",
|
|
160
|
+
" this.argument = argument;",
|
|
161
|
+
" this.result = result;",
|
|
162
|
+
" this.consuming = consuming;",
|
|
163
|
+
" this.metadata = metadata;",
|
|
105
164
|
" }",
|
|
106
165
|
"",
|
|
107
|
-
|
|
166
|
+
` public static fromExercisedEvent(event: DamlExercisedEventSource): ${choice.exercisedEventTypeName} {`,
|
|
167
|
+
" const normalized = normalizeDamlExercisedEventSource(event);",
|
|
168
|
+
` ${choice.exercisedEventTypeName}.assertTemplateIdentity(normalized.metadata.templateId);`,
|
|
169
|
+
` return ${choice.exercisedEventTypeName}.fromNormalizedEvent(normalized);`,
|
|
170
|
+
" }",
|
|
108
171
|
"",
|
|
109
|
-
` public static
|
|
110
|
-
`
|
|
172
|
+
` public static fromNormalizedEvent(event: DamlNormalizedExercisedEvent): ${choice.exercisedEventTypeName} {`,
|
|
173
|
+
` ${choice.exercisedEventTypeName}.assertTemplateIdentity(event.metadata.templateId);`,
|
|
174
|
+
` if (event.choice !== ${JSON.stringify(choice.name)}) {`,
|
|
175
|
+
` throw new DamlMaterializationError("choice", \`Expected choice '${choice.name}' but received '\${event.choice}'\`);`,
|
|
176
|
+
" }",
|
|
177
|
+
` const argument = materializeDamlValue<${choice.parameterTypeName}>(decodeDamlValue(event.argument, ${choice.exercisedEventTypeName}.argumentDescriptor, generatedDamlTypeDescriptorRegistry, "choice argument"));`,
|
|
178
|
+
` const result = materializeDamlValue<${choice.returnTypeName}>(decodeDamlValue(event.result, ${choice.exercisedEventTypeName}.resultDescriptor, generatedDamlTypeDescriptorRegistry, "exercise result"));`,
|
|
179
|
+
` return new ${choice.exercisedEventTypeName}(event.contractId, argument, result, event.consuming, event.metadata);`,
|
|
111
180
|
" }",
|
|
112
181
|
"",
|
|
113
|
-
|
|
114
|
-
`
|
|
182
|
+
" private static assertTemplateIdentity(identity: { readonly packageId: string; readonly moduleName: string; readonly entityName: string }): void {",
|
|
183
|
+
` if (identity.packageId !== ${JSON.stringify(this.packageId(binding))} || identity.moduleName !== ${JSON.stringify(this.moduleName(binding))} || identity.entityName !== ${JSON.stringify(this.entityName(binding))}) {`,
|
|
184
|
+
` throw new DamlMaterializationError("template ID", \`Expected template '${binding.templateIdLiteral}' but received '\${identity.packageId}:\${identity.moduleName}:\${identity.entityName}'\`);`,
|
|
185
|
+
" }",
|
|
115
186
|
" }",
|
|
116
187
|
"}",
|
|
117
|
-
].
|
|
188
|
+
].join("\n");
|
|
189
|
+
}
|
|
190
|
+
emitTemplateDescriptor(binding) {
|
|
191
|
+
return `{ kind: "record", fields: [${binding.createFields.map((field) => `{ damlLabel: ${JSON.stringify(field.name)}, propertyName: ${JSON.stringify(field.propertyName)}, type: ${this.emitDescriptor(field.type)} }`).join(", ")}] }`;
|
|
192
|
+
}
|
|
193
|
+
emitDescriptor(type) {
|
|
194
|
+
switch (type.kind) {
|
|
195
|
+
case "primitive":
|
|
196
|
+
return `{ kind: "primitive", primitive: ${JSON.stringify(type.builtinType)}${type.numericScale === undefined ? "" : `, numericScale: ${type.numericScale}`} }`;
|
|
197
|
+
case "contractId":
|
|
198
|
+
return '{ kind: "contractId" }';
|
|
199
|
+
case "optional":
|
|
200
|
+
return `{ kind: "optional", element: ${this.emitDescriptor(type.element)} }`;
|
|
201
|
+
case "list":
|
|
202
|
+
return `{ kind: "list", element: ${this.emitDescriptor(type.element)} }`;
|
|
203
|
+
case "textMap":
|
|
204
|
+
return `{ kind: "textMap", value: ${this.emitDescriptor(type.value)} }`;
|
|
205
|
+
case "genMap":
|
|
206
|
+
return `{ kind: "genMap", key: ${this.emitDescriptor(type.key)}, value: ${this.emitDescriptor(type.value)} }`;
|
|
207
|
+
case "record":
|
|
208
|
+
return `{ kind: "record", fields: [${type.fields.map((field) => `{ damlLabel: ${JSON.stringify(field.damlLabel)}, propertyName: ${JSON.stringify(field.propertyName)}, type: ${this.emitDescriptor(field.type)} }`).join(", ")}] }`;
|
|
209
|
+
case "variant":
|
|
210
|
+
return `{ kind: "variant", constructors: [${type.constructors.map((constructor) => `{ constructor: ${JSON.stringify(constructor.constructor)}, payload: ${this.emitDescriptor(constructor.payload)} }`).join(", ")}] }`;
|
|
211
|
+
case "enum":
|
|
212
|
+
return `{ kind: "enum", constructors: [${type.constructors.map((constructor) => JSON.stringify(constructor)).join(", ")}] }`;
|
|
213
|
+
case "namedReference":
|
|
214
|
+
return `{ kind: "namedReference", identity: { packageId: ${JSON.stringify(type.identity.packageId)}, moduleName: ${JSON.stringify(type.identity.moduleName)}, entityName: ${JSON.stringify(type.identity.name)} } }`;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
getTypeName(type, namedReferences) {
|
|
218
|
+
switch (type.kind) {
|
|
219
|
+
case "primitive":
|
|
220
|
+
return this.getPrimitiveTypeName(type.builtinType);
|
|
221
|
+
case "contractId":
|
|
222
|
+
return "string";
|
|
223
|
+
case "optional":
|
|
224
|
+
return `${this.getTypeName(type.element, namedReferences)} | undefined`;
|
|
225
|
+
case "list":
|
|
226
|
+
return `readonly ${this.getTypeName(type.element, namedReferences)}[]`;
|
|
227
|
+
case "textMap":
|
|
228
|
+
return `ReadonlyMap<string, ${this.getTypeName(type.value, namedReferences)}>`;
|
|
229
|
+
case "genMap":
|
|
230
|
+
return `ReadonlyMap<${this.getTypeName(type.key, namedReferences)}, ${this.getTypeName(type.value, namedReferences)}>`;
|
|
231
|
+
case "record":
|
|
232
|
+
return `{ ${type.fields.map((field) => `readonly ${field.propertyName}: ${this.getTypeName(field.type, namedReferences)};`).join(" ")} }`;
|
|
233
|
+
case "variant":
|
|
234
|
+
return type.constructors.map((constructor) => `{ readonly tag: ${JSON.stringify(constructor.constructor)}; readonly value: ${this.getTypeName(constructor.payload, namedReferences)}; }`).join(" | ");
|
|
235
|
+
case "enum":
|
|
236
|
+
return type.constructors.map((constructor) => JSON.stringify(constructor)).join(" | ");
|
|
237
|
+
case "namedReference":
|
|
238
|
+
return this.getNamedReference(type.identity, namedReferences).alias;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
getPrimitiveTypeName(type) {
|
|
242
|
+
switch (type) {
|
|
243
|
+
case DamlLfBuiltinType.unit: return "DamlUnit";
|
|
244
|
+
case DamlLfBuiltinType.bool: return "boolean";
|
|
245
|
+
case DamlLfBuiltinType.int64: return "bigint";
|
|
246
|
+
case DamlLfBuiltinType.date: return "DamlDate";
|
|
247
|
+
case DamlLfBuiltinType.timestamp: return "DamlTimestamp";
|
|
248
|
+
case DamlLfBuiltinType.numeric: return "DamlNumeric";
|
|
249
|
+
case DamlLfBuiltinType.party: return "DamlParty";
|
|
250
|
+
case DamlLfBuiltinType.text: return "string";
|
|
251
|
+
default: throw new Error(`Cannot emit unsupported primitive DAML type '${type}'`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
normalizeType(type) {
|
|
255
|
+
if ("kind" in type) {
|
|
256
|
+
return type;
|
|
257
|
+
}
|
|
258
|
+
else if (type.builtinType === DamlLfBuiltinType.contractId) {
|
|
259
|
+
if (type.typeArguments.length !== 1) {
|
|
260
|
+
throw new Error("DAML ContractId requires exactly one type argument");
|
|
261
|
+
}
|
|
262
|
+
return { kind: "contractId" };
|
|
263
|
+
}
|
|
264
|
+
else if (type.typeConReference !== undefined) {
|
|
265
|
+
return { kind: "namedReference", identity: type.typeConReference };
|
|
266
|
+
}
|
|
267
|
+
const arguments_ = type.typeArguments.map((argument) => this.normalizeType(argument));
|
|
268
|
+
switch (type.builtinType) {
|
|
269
|
+
case DamlLfBuiltinType.optional:
|
|
270
|
+
return { kind: "optional", element: arguments_[0] ?? { kind: "primitive", builtinType: DamlLfBuiltinType.text } };
|
|
271
|
+
case DamlLfBuiltinType.list:
|
|
272
|
+
return { kind: "list", element: arguments_[0] ?? { kind: "primitive", builtinType: DamlLfBuiltinType.text } };
|
|
273
|
+
case DamlLfBuiltinType.textMap:
|
|
274
|
+
return { kind: "textMap", value: arguments_[0] ?? { kind: "primitive", builtinType: DamlLfBuiltinType.text } };
|
|
275
|
+
case DamlLfBuiltinType.genMap:
|
|
276
|
+
return { kind: "genMap", key: arguments_[0] ?? { kind: "primitive", builtinType: DamlLfBuiltinType.text }, value: arguments_[1] ?? { kind: "primitive", builtinType: DamlLfBuiltinType.text } };
|
|
277
|
+
case DamlLfBuiltinType.unit:
|
|
278
|
+
case DamlLfBuiltinType.bool:
|
|
279
|
+
case DamlLfBuiltinType.int64:
|
|
280
|
+
case DamlLfBuiltinType.date:
|
|
281
|
+
case DamlLfBuiltinType.timestamp:
|
|
282
|
+
case DamlLfBuiltinType.numeric:
|
|
283
|
+
case DamlLfBuiltinType.party:
|
|
284
|
+
case DamlLfBuiltinType.text:
|
|
285
|
+
return { kind: "primitive", builtinType: type.builtinType, numericScale: type.numericScale };
|
|
286
|
+
case DamlLfBuiltinType.unknown:
|
|
287
|
+
throw new Error("Cannot emit an unknown DAML type");
|
|
288
|
+
default:
|
|
289
|
+
throw new Error("Cannot emit unsupported DAML type");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
resolveNamedReferences(template, namedTypeFiles) {
|
|
293
|
+
const identities = new Map();
|
|
294
|
+
for (const type of [
|
|
295
|
+
...template.createFields.map((field) => this.normalizeType(field.type)),
|
|
296
|
+
...template.choices.flatMap((choice) => [
|
|
297
|
+
this.normalizeType(choice.parameterType),
|
|
298
|
+
this.normalizeType(choice.returnType),
|
|
299
|
+
]),
|
|
300
|
+
]) {
|
|
301
|
+
for (const reference of this.walkNamedReferences(type)) {
|
|
302
|
+
identities.set(this.getNamedReferenceKey(reference.identity), reference);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
const aliases = new Map();
|
|
306
|
+
const usedAliases = new Set();
|
|
307
|
+
for (const [key, reference] of [...identities.entries()].sort(([left], [right]) => left.localeCompare(right))) {
|
|
308
|
+
const file = namedTypeFiles.find((candidate) => candidate.packageId === reference.identity.packageId
|
|
309
|
+
&& candidate.moduleName === reference.identity.moduleName);
|
|
310
|
+
const exportedName = file?.exportedTypeNamesByIdentity.get(key);
|
|
311
|
+
if (file === undefined || exportedName === undefined) {
|
|
312
|
+
if (namedTypeFiles.length !== 0) {
|
|
313
|
+
throw new Error(`Cannot emit unresolved named DAML type '${reference.identity.name}'`);
|
|
314
|
+
}
|
|
315
|
+
aliases.set(key, reference.identity.name);
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
const baseAlias = this.toTypeName(`${reference.identity.packageId} ${reference.identity.moduleName} ${exportedName}`);
|
|
319
|
+
let alias = baseAlias;
|
|
320
|
+
let escalation = 2;
|
|
321
|
+
while (usedAliases.has(alias)) {
|
|
322
|
+
alias = `${baseAlias}_${this.shortHash(key)}_${escalation}`;
|
|
323
|
+
escalation += 1;
|
|
324
|
+
}
|
|
325
|
+
usedAliases.add(alias);
|
|
326
|
+
aliases.set(key, alias);
|
|
327
|
+
}
|
|
328
|
+
return new Map([...identities.entries()].map(([key, reference]) => {
|
|
329
|
+
const file = namedTypeFiles.find((candidate) => candidate.packageId === reference.identity.packageId
|
|
330
|
+
&& candidate.moduleName === reference.identity.moduleName);
|
|
331
|
+
const exportedName = file?.exportedTypeNamesByIdentity.get(key);
|
|
332
|
+
const alias = aliases.get(key);
|
|
333
|
+
if (file === undefined || exportedName === undefined) {
|
|
334
|
+
return [key, {
|
|
335
|
+
path: "",
|
|
336
|
+
exportedName: reference.identity.name,
|
|
337
|
+
alias: alias ?? reference.identity.name,
|
|
338
|
+
}];
|
|
339
|
+
}
|
|
340
|
+
return [key, {
|
|
341
|
+
path: this.relativeFilePath(this.nameResolver.getTemplateFilePath(template), file.path),
|
|
342
|
+
exportedName,
|
|
343
|
+
alias: alias,
|
|
344
|
+
}];
|
|
345
|
+
}));
|
|
346
|
+
}
|
|
347
|
+
*walkNamedReferences(type) {
|
|
348
|
+
switch (type.kind) {
|
|
349
|
+
case "namedReference":
|
|
350
|
+
yield type;
|
|
351
|
+
return;
|
|
352
|
+
case "contractId": return;
|
|
353
|
+
case "optional":
|
|
354
|
+
case "list":
|
|
355
|
+
yield* this.walkNamedReferences(type.element);
|
|
356
|
+
return;
|
|
357
|
+
case "textMap":
|
|
358
|
+
yield* this.walkNamedReferences(type.value);
|
|
359
|
+
return;
|
|
360
|
+
case "genMap":
|
|
361
|
+
yield* this.walkNamedReferences(type.key);
|
|
362
|
+
yield* this.walkNamedReferences(type.value);
|
|
363
|
+
return;
|
|
364
|
+
case "record":
|
|
365
|
+
for (const field of type.fields) {
|
|
366
|
+
yield* this.walkNamedReferences(field.type);
|
|
367
|
+
}
|
|
368
|
+
return;
|
|
369
|
+
case "variant":
|
|
370
|
+
for (const constructor of type.constructors) {
|
|
371
|
+
yield* this.walkNamedReferences(constructor.payload);
|
|
372
|
+
}
|
|
373
|
+
return;
|
|
374
|
+
case "primitive":
|
|
375
|
+
case "enum": return;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
getNamedReference(identity, namedReferences) {
|
|
379
|
+
const reference = namedReferences.get(this.getNamedReferenceKey(identity));
|
|
380
|
+
if (reference === undefined) {
|
|
381
|
+
throw new Error(`Cannot resolve named DAML type '${identity.name}'`);
|
|
382
|
+
}
|
|
383
|
+
return reference;
|
|
384
|
+
}
|
|
385
|
+
getNamedReferenceKey(identity) {
|
|
386
|
+
return `${identity.packageId}\u0000${identity.moduleName}\u0000${identity.name}`;
|
|
387
|
+
}
|
|
388
|
+
toTypeName(value) {
|
|
389
|
+
const normalized = value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[^A-Za-z0-9]+/g, " ").trim();
|
|
390
|
+
const name = normalized.split(/\s+/).map((part) => `${part[0]?.toUpperCase()}${part.slice(1)}`).join("");
|
|
391
|
+
return /^[0-9]/.test(name) ? `_${name}` : name;
|
|
392
|
+
}
|
|
393
|
+
shortHash(value) {
|
|
394
|
+
let hash = 0x811c9dc5;
|
|
395
|
+
for (const character of value) {
|
|
396
|
+
hash ^= character.charCodeAt(0);
|
|
397
|
+
hash = Math.imul(hash, 0x01000193);
|
|
398
|
+
}
|
|
399
|
+
return (hash >>> 0).toString(36).padStart(6, "0").slice(-6);
|
|
400
|
+
}
|
|
401
|
+
packageId(binding) {
|
|
402
|
+
return binding.templateIdLiteral.split(":")[0];
|
|
403
|
+
}
|
|
404
|
+
moduleName(binding) {
|
|
405
|
+
return binding.templateIdLiteral.split(":")[1];
|
|
406
|
+
}
|
|
407
|
+
entityName(binding) {
|
|
408
|
+
return binding.templateIdLiteral.split(":")[2];
|
|
409
|
+
}
|
|
410
|
+
relativeFilePath(fromPath, toPath) {
|
|
411
|
+
const from = fromPath.split("/").slice(0, -1);
|
|
412
|
+
const to = toPath.split("/");
|
|
413
|
+
while (from[0] === to[0] && from.length > 0) {
|
|
414
|
+
from.shift();
|
|
415
|
+
to.shift();
|
|
416
|
+
}
|
|
417
|
+
const relative = from.map(() => "..").concat(to).join("/") || ".";
|
|
418
|
+
return `${relative.startsWith(".") ? relative : `./${relative}`}`.replace(/\.ts$/, ".js");
|
|
118
419
|
}
|
|
119
420
|
}
|
|
@@ -1,21 +1,68 @@
|
|
|
1
|
-
import { DamlLfType } from "../../daml-lf/model/daml-lf-type.js";
|
|
2
1
|
import { AnalyzedChoice } from "../analysis/analyzed-choice.js";
|
|
3
|
-
import {
|
|
2
|
+
import { AnalyzedDamlType } from "../analysis/analyzed-daml-type.js";
|
|
3
|
+
import { AnalyzedDamlTypeDefinition } from "../analysis/analyzed-daml-type-definition.js";
|
|
4
|
+
import { AnalyzedTemplate, AnalyzedTemplateField } from "../analysis/analyzed-template.js";
|
|
4
5
|
export declare class TypeScriptNameResolver {
|
|
6
|
+
private readonly templatesByIdentity;
|
|
7
|
+
private resolvedTemplates;
|
|
8
|
+
private resolvedModules;
|
|
9
|
+
constructor(templates?: readonly AnalyzedTemplate[]);
|
|
10
|
+
/** Prepares a project-wide name table and rejects irreconcilable output collisions. */
|
|
11
|
+
prepareTemplatesOrThrow(templates: readonly AnalyzedTemplate[]): void;
|
|
12
|
+
/** Prepares shared package/module paths for template and named DAML type output. */
|
|
13
|
+
prepareProjectOrThrow(templates: readonly AnalyzedTemplate[], typeDefinitions: readonly AnalyzedDamlTypeDefinition[]): void;
|
|
14
|
+
/** Resolves the full package/module/entity identity key for a template. */
|
|
15
|
+
getTemplateIdentityKey(template: AnalyzedTemplate): string;
|
|
16
|
+
/** Resolves the generated namespace alias for a template package/module. */
|
|
17
|
+
getNamespaceAlias(template: AnalyzedTemplate): string;
|
|
5
18
|
/** Resolves the generated file path for a template binding. */
|
|
6
19
|
getTemplateFilePath(template: AnalyzedTemplate): string;
|
|
20
|
+
/** Resolves the generated class name for a template binding. */
|
|
21
|
+
getTemplateClassName(template: AnalyzedTemplate): string;
|
|
22
|
+
/** Resolves the output directory shared by a named DAML type package/module. */
|
|
23
|
+
getNamedTypeModuleDirectoryPath(packageId: string, moduleName: string): string;
|
|
24
|
+
/** Resolves the generated namespace alias shared by templates and named DAML types. */
|
|
25
|
+
getNamedTypeModuleNamespaceAlias(packageId: string, moduleName: string): string;
|
|
7
26
|
/** Resolves the generated create-fields type name for a template. */
|
|
8
27
|
getCreateFieldsTypeName(template: AnalyzedTemplate): string;
|
|
9
28
|
/** Resolves the generated created-event type name for a template. */
|
|
10
29
|
getCreatedEventTypeName(template: AnalyzedTemplate): string;
|
|
30
|
+
/** Resolves the generated property name for an original DAML template field. */
|
|
31
|
+
getFieldPropertyName(template: AnalyzedTemplate, field: AnalyzedTemplateField): string;
|
|
32
|
+
/** Resolves the generated constructor parameter for an original DAML template field. */
|
|
33
|
+
getFieldConstructorParameterName(template: AnalyzedTemplate, field: AnalyzedTemplateField): string;
|
|
34
|
+
/** Resolves the generated exercise method name for a DAML choice. */
|
|
35
|
+
getChoiceMethodName(template: AnalyzedTemplate, choice: AnalyzedChoice): string;
|
|
11
36
|
/** Resolves the generated choice payload type name for a template choice. */
|
|
12
37
|
getChoiceTypeName(template: AnalyzedTemplate, choice: AnalyzedChoice): string;
|
|
13
38
|
/** Resolves the generated exercised-event type name for a template choice. */
|
|
14
39
|
getExercisedEventTypeName(template: AnalyzedTemplate, choice: AnalyzedChoice): string;
|
|
40
|
+
/** Resolves the generated parameter property name for a DAML choice. */
|
|
41
|
+
getChoiceParameterName(template: AnalyzedTemplate, choice: AnalyzedChoice): string;
|
|
42
|
+
/** Resolves the full identity key for a DAML choice. */
|
|
43
|
+
getChoiceIdentityKey(template: AnalyzedTemplate, choice: AnalyzedChoice): string;
|
|
15
44
|
/** Resolves the TypeScript type name for a supported DAML-LF type. */
|
|
16
|
-
getTypeName(type:
|
|
45
|
+
getTypeName(type: AnalyzedDamlType): string;
|
|
17
46
|
/** Resolves the literal template identifier used by generated helpers. */
|
|
18
47
|
getTemplateIdLiteral(template: AnalyzedTemplate): string;
|
|
48
|
+
private getResolvedTemplate;
|
|
49
|
+
private getResolvedModule;
|
|
50
|
+
private getResolvedField;
|
|
51
|
+
private getResolvedChoice;
|
|
52
|
+
private resolveFieldNames;
|
|
53
|
+
private resolveChoiceNames;
|
|
54
|
+
private resolveNames;
|
|
55
|
+
private assertDistinctTemplateOutput;
|
|
56
|
+
private assertDistinctNamespaceAliases;
|
|
19
57
|
private getModuleDirectory;
|
|
58
|
+
private getTemplateFileBaseName;
|
|
59
|
+
private getPackageModuleIdentityKey;
|
|
60
|
+
private getPackageModuleIdentityKeyFromParts;
|
|
61
|
+
private safeTypeName;
|
|
62
|
+
private safeNamespaceAlias;
|
|
63
|
+
private safeMemberName;
|
|
64
|
+
private toPascalCase;
|
|
20
65
|
private toKebabCase;
|
|
66
|
+
private shortHash;
|
|
67
|
+
private describeTemplate;
|
|
21
68
|
}
|