@accordproject/template-engine 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ModelManager, ClassDeclaration } from '@accordproject/concerto-core';
2
2
  import { Template } from '@accordproject/cicero-core';
3
+ import { TwoSlashReturn } from '@typescript/twoslash';
3
4
 
4
5
  /*
5
6
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -133,6 +134,7 @@ type InitResponse = {
133
134
  */
134
135
  declare class TemplateArchiveProcessor {
135
136
  template: Template;
137
+ private compiledLogicCache?;
136
138
  /**
137
139
  * Creates a template archive processor
138
140
  * @param {Template} template - the template to be used by the processor
@@ -148,21 +150,31 @@ declare class TemplateArchiveProcessor {
148
150
  */
149
151
  draft(data: any, format: string, options: any, currentTime?: string): Promise<any>;
150
152
  /**
151
- * Trigger the logic of a template
153
+ * Compile the logic of a template
154
+ * @param {boolean} [enableCompiledLogicCache] - whether to cache the compiled logic for future use
155
+ * @returns {Promise<Record<string, TwoSlashReturn>>} the compiled code for each typescript file
156
+ */
157
+ compileLogic(enableCompiledLogicCache?: boolean): Promise<Record<string, TwoSlashReturn>>;
158
+ /**
159
+ * Trigger the logic of a template.
160
+ * @param {object} data - the data for the template
152
161
  * @param {object} request - the request to send to the template logic
153
162
  * @param {object} state - the current state of the template
154
163
  * @param {[string]} currentTime - the current time, defaults to now
155
164
  * @param {[number]} utcOffset - the UTC offset, defaults to zero
156
- * @returns {Promise} the response and any events
165
+ * @param {boolean} [enableCompiledLogicCache] - whether to use the compiled logic cache
166
+ * @returns {Promise<TriggerResponse>} the response and any events
157
167
  */
158
- trigger(data: any, request: any, state?: any, currentTime?: string, utcOffset?: number): Promise<TriggerResponse>;
168
+ trigger(data: any, request: any, state?: any, currentTime?: string, utcOffset?: number, enableCompiledLogicCache?: boolean): Promise<TriggerResponse>;
159
169
  /**
160
- * Init the logic of a template
170
+ * Init the logic of a template.
171
+ * @param {object} data - the data for the template
161
172
  * @param {[string]} currentTime - the current time, defaults to now
162
173
  * @param {[number]} utcOffset - the UTC offset, defaults to zero
174
+ * @param {boolean} [enableCompiledLogicCache] - whether to use the compiled logic cache
163
175
  * @returns {Promise<InitResponse>} the new state
164
176
  */
165
- init(data: any, currentTime?: string, utcOffset?: number): Promise<InitResponse>;
177
+ init(data: any, currentTime?: string, utcOffset?: number, enableCompiledLogicCache?: boolean): Promise<InitResponse>;
166
178
  }
167
179
 
168
180
  declare function ensureDirSync(path: string): void;
package/dist/index.js CHANGED
@@ -529,17 +529,31 @@ class JavaScriptEvaluator {
529
529
  const end = (/* @__PURE__ */ new Date()).getTime();
530
530
  resolve({ result, elapsed: end - start });
531
531
  }).catch((err) => {
532
- console.log(err);
533
- reject({
534
- message: err.message
535
- });
532
+ console.error(err);
533
+ if (err instanceof Error) {
534
+ reject({
535
+ message: err.message,
536
+ stack: err.stack
537
+ });
538
+ } else {
539
+ reject({
540
+ message: String(err)
541
+ });
542
+ }
536
543
  });
537
544
  }
538
545
  } catch (err) {
539
- console.log(err);
540
- reject({
541
- message: err.message
542
- });
546
+ console.error(err);
547
+ if (err instanceof Error) {
548
+ reject({
549
+ message: err.message,
550
+ stack: err.stack
551
+ });
552
+ } else {
553
+ reject({
554
+ message: String(err)
555
+ });
556
+ }
543
557
  }
544
558
  });
545
559
  }
@@ -561,6 +575,7 @@ class JavaScriptEvaluator {
561
575
  };
562
576
  if (this.queue.length >= this.options.maxQueueDepth) {
563
577
  reject({ maxQueueDepthExceeded: true, elapsed: 0 });
578
+ return;
564
579
  }
565
580
  this.queue.push(workItem);
566
581
  this.processQueue(options);
@@ -601,7 +616,7 @@ class JavaScriptEvaluator {
601
616
  }
602
617
  const workerPath = this.getWorkerPath();
603
618
  const worker = child_process.fork(workerPath, { timeout: options.timeout, env: {} });
604
- if (!worker.pid) {
619
+ if (worker.pid === void 0 || worker.pid === null) {
605
620
  throw new Error("Failed to fork child process");
606
621
  }
607
622
  this.workers.push(worker);
@@ -610,7 +625,18 @@ class JavaScriptEvaluator {
610
625
  worker.on("error", (err) => {
611
626
  this.workers = this.workers.filter((w) => w.pid !== worker.pid);
612
627
  const end = (/* @__PURE__ */ new Date()).getTime();
613
- reject({ message: err.message, elapsed: end - start });
628
+ if (err instanceof Error) {
629
+ reject({
630
+ message: err.message,
631
+ stack: err.stack,
632
+ elapsed: end - start
633
+ });
634
+ } else {
635
+ reject({
636
+ message: String(err),
637
+ elapsed: end - start
638
+ });
639
+ }
614
640
  });
615
641
  worker.on("message", (msg) => {
616
642
  result = msg;
@@ -793,13 +819,17 @@ async function generateRecursiveBlocks(modelManager, clauseLibrary, templateMark
793
819
  if (!Array.isArray(arrayData)) {
794
820
  throw new Error(`Values found for path '${path}' in data ${data} is not an array: ${arrayData}.`);
795
821
  } else {
822
+ const firstChild = context.nodes[0];
823
+ const hasListWrapper = firstChild && firstChild.$class === `${markdownCommon.CommonMarkModel.NAMESPACE}.List` && Array.isArray(firstChild.nodes) && firstChild.nodes.length > 0;
824
+ const itemTemplate = hasListWrapper ? firstChild.nodes[0] : firstChild;
796
825
  const nodes = [];
797
826
  for (let n2 = 0; n2 < arrayData.length; n2++) {
798
827
  const arrayItem = arrayData[n2];
799
- const subResult = await generateAgreement(modelManager, clauseLibrary, context.nodes[0].nodes[0], arrayItem, options);
828
+ const subResult = await generateAgreement(modelManager, clauseLibrary, itemTemplate, arrayItem, options);
829
+ const childNodes = hasListWrapper ? subResult.nodes ? subResult.nodes : [] : [subResult];
800
830
  nodes.push({
801
831
  $class: childNodeClass,
802
- nodes: subResult.nodes ? subResult.nodes : []
832
+ nodes: childNodes
803
833
  });
804
834
  }
805
835
  result[thisPath.join("/")] = nodes;
@@ -1143,14 +1173,14 @@ class TemplateArchiveProcessor {
1143
1173
  return result;
1144
1174
  }
1145
1175
  /**
1146
- * Trigger the logic of a template
1147
- * @param {object} request - the request to send to the template logic
1148
- * @param {object} state - the current state of the template
1149
- * @param {[string]} currentTime - the current time, defaults to now
1150
- * @param {[number]} utcOffset - the UTC offset, defaults to zero
1151
- * @returns {Promise} the response and any events
1176
+ * Compile the logic of a template
1177
+ * @param {boolean} [enableCompiledLogicCache] - whether to cache the compiled logic for future use
1178
+ * @returns {Promise<Record<string, TwoSlashReturn>>} the compiled code for each typescript file
1152
1179
  */
1153
- async trigger(data, request, state, currentTime, utcOffset) {
1180
+ async compileLogic(enableCompiledLogicCache = false) {
1181
+ if (enableCompiledLogicCache && this.compiledLogicCache) {
1182
+ return this.compiledLogicCache;
1183
+ }
1154
1184
  const logicManager = this.template.getLogicManager();
1155
1185
  if (logicManager.getLanguage() === "typescript") {
1156
1186
  const compiledCode = {};
@@ -1167,69 +1197,70 @@ class TemplateArchiveProcessor {
1167
1197
  const result = compiler.compile(code);
1168
1198
  compiledCode[tsFile.getIdentifier()] = result;
1169
1199
  }
1170
- const resolvedTime = currentTime ?? (/* @__PURE__ */ new Date()).toISOString();
1171
- const resolvedOffset = utcOffset ?? 0;
1172
- const evaluator = new JavaScriptEvaluator();
1173
- const evalResponse = await evaluator.evalDangerously({
1174
- templateLogic: true,
1175
- verbose: false,
1176
- functionName: "trigger",
1177
- code: compiledCode["logic/logic.ts"].code,
1178
- // TODO DCS - how to find the code to run?
1179
- argumentNames: ["data", "request", "state"],
1180
- arguments: [data, request, state, resolvedTime, resolvedOffset]
1181
- });
1182
- if (evalResponse.result) {
1183
- return evalResponse.result;
1184
- } else {
1185
- throw new Error("Trigger failed with message: " + evalResponse.message);
1200
+ if (enableCompiledLogicCache) {
1201
+ this.compiledLogicCache = compiledCode;
1186
1202
  }
1203
+ return compiledCode;
1187
1204
  } else {
1188
1205
  throw new Error("Only TypeScript is supported at this time");
1189
1206
  }
1190
1207
  }
1191
1208
  /**
1192
- * Init the logic of a template
1209
+ * Trigger the logic of a template.
1210
+ * @param {object} data - the data for the template
1211
+ * @param {object} request - the request to send to the template logic
1212
+ * @param {object} state - the current state of the template
1213
+ * @param {[string]} currentTime - the current time, defaults to now
1214
+ * @param {[number]} utcOffset - the UTC offset, defaults to zero
1215
+ * @param {boolean} [enableCompiledLogicCache] - whether to use the compiled logic cache
1216
+ * @returns {Promise<TriggerResponse>} the response and any events
1217
+ */
1218
+ async trigger(data, request, state, currentTime, utcOffset, enableCompiledLogicCache) {
1219
+ const compiledCode = await this.compileLogic(enableCompiledLogicCache);
1220
+ const resolvedTime = currentTime ?? (/* @__PURE__ */ new Date()).toISOString();
1221
+ const resolvedOffset = utcOffset ?? 0;
1222
+ const evaluator = new JavaScriptEvaluator();
1223
+ const evalResponse = await evaluator.evalDangerously({
1224
+ templateLogic: true,
1225
+ verbose: false,
1226
+ functionName: "trigger",
1227
+ code: compiledCode["logic/logic.ts"].code,
1228
+ // TODO DCS - how to find the code to run?
1229
+ argumentNames: ["data", "request", "state"],
1230
+ arguments: [data, request, state, resolvedTime, resolvedOffset]
1231
+ });
1232
+ if (evalResponse.result) {
1233
+ return evalResponse.result;
1234
+ } else {
1235
+ throw new Error("Trigger failed with message: " + evalResponse.message);
1236
+ }
1237
+ }
1238
+ /**
1239
+ * Init the logic of a template.
1240
+ * @param {object} data - the data for the template
1193
1241
  * @param {[string]} currentTime - the current time, defaults to now
1194
1242
  * @param {[number]} utcOffset - the UTC offset, defaults to zero
1243
+ * @param {boolean} [enableCompiledLogicCache] - whether to use the compiled logic cache
1195
1244
  * @returns {Promise<InitResponse>} the new state
1196
1245
  */
1197
- async init(data, currentTime, utcOffset) {
1198
- const logicManager = this.template.getLogicManager();
1199
- if (logicManager.getLanguage() === "typescript") {
1200
- const compiledCode = {};
1201
- const tsFiles = logicManager.getScriptManager().getScriptsForTarget("typescript");
1202
- for (let n = 0; n < tsFiles.length; n++) {
1203
- const tsFile = tsFiles[n];
1204
- const compiler = new TypeScriptToJavaScriptCompiler(
1205
- this.template.getModelManager(),
1206
- this.template.getTemplateModel().getFullyQualifiedName()
1207
- );
1208
- await compiler.initialize();
1209
- const code = `${Buffer.from(SMART_LEGAL_CONTRACT_BASE64, "base64").toString()}
1210
- ${tsFile.getContents()}`;
1211
- const result = compiler.compile(code);
1212
- compiledCode[tsFile.getIdentifier()] = result;
1213
- }
1214
- const resolvedTime = currentTime ?? (/* @__PURE__ */ new Date()).toISOString();
1215
- const resolvedOffset = utcOffset ?? 0;
1216
- const evaluator = new JavaScriptEvaluator();
1217
- const evalResponse = await evaluator.evalDangerously({
1218
- templateLogic: true,
1219
- verbose: false,
1220
- functionName: "init",
1221
- code: compiledCode["logic/logic.ts"].code,
1222
- // TODO DCS - how to find the code to run?
1223
- argumentNames: ["data"],
1224
- arguments: [data, resolvedTime, resolvedOffset]
1225
- });
1226
- if (evalResponse.result) {
1227
- return evalResponse.result;
1228
- } else {
1229
- throw new Error("Init failed with message: " + evalResponse.message);
1230
- }
1246
+ async init(data, currentTime, utcOffset, enableCompiledLogicCache) {
1247
+ const compiledCode = await this.compileLogic(enableCompiledLogicCache);
1248
+ const resolvedTime = currentTime ?? (/* @__PURE__ */ new Date()).toISOString();
1249
+ const resolvedOffset = utcOffset ?? 0;
1250
+ const evaluator = new JavaScriptEvaluator();
1251
+ const evalResponse = await evaluator.evalDangerously({
1252
+ templateLogic: true,
1253
+ verbose: false,
1254
+ functionName: "init",
1255
+ code: compiledCode["logic/logic.ts"].code,
1256
+ // TODO DCS - how to find the code to run?
1257
+ argumentNames: ["data"],
1258
+ arguments: [data, resolvedTime, resolvedOffset]
1259
+ });
1260
+ if (evalResponse.result) {
1261
+ return evalResponse.result;
1231
1262
  } else {
1232
- throw new Error("Only TypeScript is supported at this time");
1263
+ throw new Error("Init failed with message: " + evalResponse.message);
1233
1264
  }
1234
1265
  }
1235
1266
  }