@milaboratories/pl-middle-layer 1.23.19 → 1.25.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.
@@ -49,7 +49,12 @@ import {
49
49
  } from '../model/project_model_util';
50
50
  import { BlockPackSpecPrepared } from '../model';
51
51
  import { notEmpty } from '@milaboratories/ts-helpers';
52
- import { AuthorMarker, ProjectMeta } from '@milaboratories/pl-model-middle-layer';
52
+ import {
53
+ AuthorMarker,
54
+ BlockSettings,
55
+ InitialBlockSettings,
56
+ ProjectMeta
57
+ } from '@milaboratories/pl-model-middle-layer';
53
58
  import Denque from 'denque';
54
59
  import { exportContext, getPreparedExportTemplateEnvelope } from './context_export';
55
60
  import { loadTemplate } from './template/template_loading';
@@ -64,6 +69,7 @@ interface BlockFieldState {
64
69
  }
65
70
 
66
71
  type BlockFieldStates = Partial<Record<ProjectField['fieldName'], BlockFieldState>>;
72
+ type BlockFieldStateValue = Omit<BlockFieldState, 'modCount'>;
67
73
 
68
74
  interface BlockInfoState {
69
75
  readonly id: string;
@@ -234,7 +240,8 @@ export class ProjectMutator {
234
240
  private readonly ctxExportTplHolder: AnyResourceRef
235
241
  ) {}
236
242
 
237
- private fixProblems() {
243
+ private fixProblemsAndMigrate() {
244
+ // Fixing problems introduced by old code
238
245
  this.blockInfos.forEach((blockInfo) => {
239
246
  if (
240
247
  blockInfo.fields.prodArgs === undefined ||
@@ -243,6 +250,16 @@ export class ProjectMutator {
243
250
  )
244
251
  this.deleteBlockFields(blockInfo.id, 'prodArgs', 'prodOutput', 'prodCtx');
245
252
  });
253
+
254
+ // Migration for addition of block settings field
255
+ let initialBlockSettings: Omit<BlockFieldState, 'modCount'> | undefined;
256
+ this.blockInfos.forEach((blockInfo) => {
257
+ if (blockInfo.fields.blockSettings === undefined) {
258
+ if (initialBlockSettings === undefined)
259
+ initialBlockSettings = this.createJsonFieldValue(InitialBlockSettings);
260
+ this.setBlockFieldObj(blockInfo.id, 'blockSettings', initialBlockSettings);
261
+ }
262
+ });
246
263
  }
247
264
 
248
265
  get wasModified(): boolean {
@@ -297,7 +314,19 @@ export class ProjectMutator {
297
314
  //
298
315
 
299
316
  private getBlockInfo(blockId: string): BlockInfo {
300
- return notEmpty(this.blockInfos.get(blockId));
317
+ const info = this.blockInfos.get(blockId);
318
+ if (info === undefined) throw new Error(`No such block: ${blockId}`);
319
+ return info;
320
+ }
321
+
322
+ private createJsonFieldValueByContent(content: string): BlockFieldStateValue {
323
+ const value = Buffer.from(content);
324
+ const ref = this.tx.createValue(Pl.JsonObject, value);
325
+ return { ref, value, status: 'Ready' };
326
+ }
327
+
328
+ private createJsonFieldValue(obj: unknown): BlockFieldStateValue {
329
+ return this.createJsonFieldValueByContent(JSON.stringify(obj));
301
330
  }
302
331
 
303
332
  private getBlock(blockId: string): Block {
@@ -308,7 +337,7 @@ export class ProjectMutator {
308
337
  private setBlockFieldObj(
309
338
  blockId: string,
310
339
  fieldName: keyof BlockFieldStates,
311
- state: Omit<BlockFieldState, 'modCount'>
340
+ state: BlockFieldStateValue
312
341
  ) {
313
342
  const fid = field(this.rid, projectFieldName(blockId, fieldName));
314
343
 
@@ -447,6 +476,11 @@ export class ProjectMutator {
447
476
  this.updateLastModified();
448
477
  }
449
478
 
479
+ public setBlockSettings(blockId: string, newValue: BlockSettings): void {
480
+ this.setBlockFieldObj(blockId, 'blockSettings', this.createJsonFieldValue(newValue));
481
+ this.updateLastModified();
482
+ }
483
+
450
484
  /** Update block label */
451
485
  // public setBlockLabel(blockId: string, label: string): void {
452
486
  // const newStructure = this.structure;
@@ -586,10 +620,15 @@ export class ProjectMutator {
586
620
  const bp = createBlockPack(this.tx, spec.blockPack);
587
621
  this.setBlockField(blockId, 'blockPack', Pl.wrapInHolder(this.tx, bp), 'NotReady');
588
622
 
623
+ // settings
624
+ this.setBlockFieldObj(
625
+ blockId,
626
+ 'blockSettings',
627
+ this.createJsonFieldValue(InitialBlockSettings)
628
+ );
629
+
589
630
  // args
590
- const binArgs = Buffer.from(spec.args);
591
- const argsRes = this.tx.createValue(Pl.JsonObject, binArgs);
592
- this.setBlockField(blockId, 'currentArgs', argsRes, 'Ready', binArgs);
631
+ this.setBlockFieldObj(blockId, 'currentArgs', this.createJsonFieldValueByContent(spec.args));
593
632
 
594
633
  // uiState
595
634
  if (spec.uiState /* this check is for compatibility with old configs */) {
@@ -1052,7 +1091,7 @@ export class ProjectMutator {
1052
1091
  ctxExportTplHolder
1053
1092
  );
1054
1093
 
1055
- prj.fixProblems();
1094
+ prj.fixProblemsAndMigrate();
1056
1095
 
1057
1096
  return prj;
1058
1097
  }
@@ -3,8 +3,18 @@ import { assertNever } from '@milaboratories/ts-helpers';
3
3
  import type { ExplicitTemplate } from '../../model/template_spec';
4
4
  import type { Hash } from 'node:crypto';
5
5
  import { createHash } from 'node:crypto';
6
- import type { TemplateData, TemplateLibData, TemplateSoftwareData } from '@milaboratories/pl-model-backend';
7
- import { PlTemplateLibV1, PlTemplateSoftwareV1, PlTemplateV1, PlTemplateOverrideV1, parseTemplate } from '@milaboratories/pl-model-backend';
6
+ import type {
7
+ TemplateData,
8
+ TemplateLibData,
9
+ TemplateSoftwareData
10
+ } from '@milaboratories/pl-model-backend';
11
+ import {
12
+ PlTemplateLibV1,
13
+ PlTemplateSoftwareV1,
14
+ PlTemplateV1,
15
+ PlTemplateOverrideV1,
16
+ parseTemplate
17
+ } from '@milaboratories/pl-model-backend';
8
18
 
9
19
  export function loadTemplateFromExplicitDirect(tx: PlTransaction, spec: ExplicitTemplate): AnyRef {
10
20
  const templateInfo: TemplateData = parseTemplate(spec.content);
@@ -20,10 +30,10 @@ export function loadTemplateFromExplicitDirect(tx: PlTransaction, spec: Explicit
20
30
 
21
31
  type Renderer<T> = {
22
32
  hash: Hasher<T>;
23
- render: (resource: T, tx: PlTransaction, creator: Creator<T>) => AnyResourceRef;
33
+ render: (resource: T, tx: PlTransaction, creator: Creator) => AnyResourceRef;
24
34
  };
25
35
  type Hasher<T> = (resource: T, hash: Hash) => void;
26
- type Creator<T> = (resource: T, renderer: Renderer<T>) => AnyResourceRef;
36
+ type Creator = <T>(resource: T, renderer: Renderer<T>) => AnyResourceRef;
27
37
 
28
38
  const LibRenderer: Renderer<TemplateLibData> = {
29
39
  hash(resource, hash) {
@@ -37,9 +47,9 @@ const LibRenderer: Renderer<TemplateLibData> = {
37
47
  render(resource, tx, _creator) {
38
48
  return tx.createValue(
39
49
  PlTemplateLibV1.type,
40
- JSON.stringify(PlTemplateLibV1.fromV2Data(resource).data),
50
+ JSON.stringify(PlTemplateLibV1.fromV2Data(resource).data)
41
51
  );
42
- },
52
+ }
43
53
  };
44
54
 
45
55
  const SoftwareInfoRenderer: Renderer<TemplateSoftwareData> = {
@@ -57,7 +67,22 @@ const SoftwareInfoRenderer: Renderer<TemplateSoftwareData> = {
57
67
  tx.setKValue(ref, PlTemplateSoftwareV1.metaNameKey, JSON.stringify(sw.name));
58
68
  tx.lock(ref);
59
69
  return ref;
70
+ }
71
+ };
72
+
73
+ const HashOverrideRenderer: Renderer<TemplateData> = {
74
+ hash(resource, hash) {
75
+ hash
76
+ .update(PlTemplateOverrideV1.type.name)
77
+ .update(PlTemplateOverrideV1.type.version)
78
+ .update(resource.hashOverride ?? '');
60
79
  },
80
+ render(resource, tx, _creator) {
81
+ return tx.createStruct(
82
+ PlTemplateOverrideV1.type,
83
+ JSON.stringify(PlTemplateOverrideV1.fromV2Data(resource))
84
+ );
85
+ }
61
86
  };
62
87
 
63
88
  const TemplateRenderer: Renderer<TemplateData> = {
@@ -70,8 +95,8 @@ const TemplateRenderer: Renderer<TemplateData> = {
70
95
  .update(resource.version)
71
96
  .update(resource.src);
72
97
 
73
- const srt = <T>(entries: [string, T][]) : [string, T][] => {
74
- entries.sort((a, b) => a[0] === b[0] ? 0 : a[0] < b[0] ? -1 : 1);
98
+ const srt = <T>(entries: [string, T][]): [string, T][] => {
99
+ entries.sort((a, b) => (a[0] === b[0] ? 0 : a[0] < b[0] ? -1 : 1));
75
100
  return entries;
76
101
  };
77
102
 
@@ -93,32 +118,52 @@ const TemplateRenderer: Renderer<TemplateData> = {
93
118
  }
94
119
  },
95
120
  render(resource, tx, _creator) {
96
- return tx.createStruct(
121
+ const tplRef = tx.createStruct(
97
122
  PlTemplateV1.type,
98
- JSON.stringify(PlTemplateV1.fromV2Data(resource).data),
123
+ JSON.stringify(PlTemplateV1.fromV2Data(resource).data)
99
124
  );
100
- },
101
- };
125
+ // Render libraries
126
+ for (const [libId, lib] of Object.entries(resource.libs ?? {})) {
127
+ const fld = PlTemplateV1.libField(tplRef, libId);
128
+ tx.createField(fld, 'Input');
129
+ tx.setField(fld, _creator(lib, LibRenderer));
130
+ }
102
131
 
103
- const HashOverrideRenderer: Renderer<TemplateData> = {
104
- hash(resource, hash) {
105
- hash
106
- .update(PlTemplateOverrideV1.type.name)
107
- .update(PlTemplateOverrideV1.type.version)
108
- .update(resource.hashOverride ?? '');
109
- },
110
- render(resource, tx, _creator) {
111
- return tx.createStruct(
112
- PlTemplateOverrideV1.type,
113
- JSON.stringify(PlTemplateOverrideV1.fromV2Data(resource)),
114
- );
115
- },
116
- };
132
+ // Render software and assets
133
+ for (const [swId, sw] of Object.entries(resource.software ?? {})) {
134
+ const fld = PlTemplateV1.swField(tplRef, swId);
135
+ tx.createField(fld, 'Input');
136
+ tx.setField(fld, _creator(sw, SoftwareInfoRenderer));
137
+ }
138
+ for (const [swId, sw] of Object.entries(resource.assets ?? {})) {
139
+ const fld = PlTemplateV1.swField(tplRef, swId);
140
+ tx.createField(fld, 'Input');
141
+ tx.setField(fld, _creator(sw, SoftwareInfoRenderer));
142
+ }
143
+
144
+ // Render dependency templates
145
+ for (const [depTplId, depTpl] of Object.entries(resource.templates ?? {})) {
146
+ const fld = PlTemplateV1.tplField(tplRef, depTplId);
147
+ tx.createField(fld, 'Input');
148
+ tx.setField(fld, _creator(depTpl, TemplateRenderer));
149
+ }
150
+
151
+ tx.lock(tplRef);
152
+
153
+ if (!resource.hashOverride) return tplRef;
117
154
 
118
- function createTemplateV2Tree(tx: PlTransaction, tplInfo: TemplateData, resourceCache?: Map<string, AnyResourceRef>): AnyRef {
119
- if (!resourceCache) {
120
- resourceCache = new Map<string, AnyResourceRef>();
155
+ // Override template hash with proxy resource, when hash override is configured for template
156
+ const overrideRef = _creator(resource, HashOverrideRenderer);
157
+ const fld = PlTemplateOverrideV1.tplField(overrideRef);
158
+ tx.createField(fld, 'Service');
159
+ tx.setField(fld, tplRef);
160
+ tx.lock(tplRef);
161
+ return overrideRef;
121
162
  }
163
+ };
164
+
165
+ function createTemplateV2Tree(tx: PlTransaction, tplInfo: TemplateData): AnyRef {
166
+ const resourceCache = new Map<string, AnyResourceRef>();
122
167
 
123
168
  const createResource = <T>(resource: T, renderer: Renderer<T>): AnyResourceRef => {
124
169
  const hasher: Hash = createHash('sha256');
@@ -133,45 +178,5 @@ function createTemplateV2Tree(tx: PlTransaction, tplInfo: TemplateData, resource
133
178
  return resourceCache.get(rKey)!;
134
179
  };
135
180
 
136
- const tplRef = createResource(tplInfo, TemplateRenderer);
137
-
138
- // Render libraries
139
- for (const [libId, lib] of Object.entries(tplInfo.libs ?? {})) {
140
- const fld = PlTemplateV1.libField(tplRef, libId);
141
- tx.createField(fld, 'Input');
142
- tx.setField(fld, createResource(lib, LibRenderer));
143
- }
144
-
145
- // Render software and assets
146
- for (const [swId, sw] of Object.entries(tplInfo.software ?? {})) {
147
- const fld = PlTemplateV1.swField(tplRef, swId);
148
- tx.createField(fld, 'Input');
149
- tx.setField(fld, createResource(sw, SoftwareInfoRenderer));
150
- }
151
- for (const [swId, sw] of Object.entries(tplInfo.assets ?? {})) {
152
- const fld = PlTemplateV1.swField(tplRef, swId);
153
- tx.createField(fld, 'Input');
154
- tx.setField(fld, createResource(sw, SoftwareInfoRenderer));
155
- }
156
-
157
- // Render dependency templates
158
- for (const [depTplId, depTpl] of Object.entries(tplInfo.templates ?? {})) {
159
- const fld = PlTemplateV1.tplField(tplRef, depTplId);
160
- tx.createField(fld, 'Input');
161
- tx.setField(fld, createTemplateV2Tree(tx, depTpl, resourceCache));
162
- }
163
-
164
- tx.lock(tplRef);
165
-
166
- if (!tplInfo.hashOverride) {
167
- return tplRef;
168
- }
169
-
170
- // Override template hash with proxy resource, when hash override is configured for template
171
- const overrideRef = createResource(tplInfo, HashOverrideRenderer);
172
- const fld = PlTemplateOverrideV1.tplField(overrideRef);
173
- tx.createField(fld, 'Service');
174
- tx.setField(fld, tplRef);
175
- tx.lock(tplRef);
176
- return overrideRef;
181
+ return createResource(tplInfo, TemplateRenderer);
177
182
  }