@platforma-sdk/tengo-builder 2.0.2 → 2.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.
@@ -1,5 +1,6 @@
1
1
  import type { ArtifactSource } from './source';
2
- import { Template } from './template';
2
+ import type { TemplateWithSource } from './template';
3
+ import { newTemplateWithSource } from './template';
3
4
  import type {
4
5
  TypedArtifactName, FullArtifactName,
5
6
  CompileMode,
@@ -14,29 +15,33 @@ import {
14
15
  import { ArtifactStore } from './artifactset';
15
16
  import { assertNever } from './util';
16
17
  import { applyLibraryCompilerOptions, applyTemplateCompilerOptions } from './compileroptions';
17
- import type { TemplateData } from '@milaboratories/pl-model-backend';
18
+ import type { CompiledTemplateV3 } from '@milaboratories/pl-model-backend';
18
19
 
20
+ /** A compilation result. */
19
21
  export interface TemplatesAndLibs {
20
- templates: Template[];
22
+ templates: TemplateWithSource[];
21
23
  libs: ArtifactSource[];
22
24
  software: ArtifactSource[];
23
25
  assets: ArtifactSource[];
24
26
  }
25
27
 
26
28
  export class TengoTemplateCompiler {
27
- constructor(
28
- private readonly compileMode: CompileMode,
29
- ) { }
30
-
31
29
  private readonly libs = new ArtifactStore<ArtifactSource>((src) => src.fullName);
32
30
  private readonly software = new ArtifactStore<ArtifactSource>((src) => src.fullName);
33
31
  private readonly assets = new ArtifactStore<ArtifactSource>((src) => src.fullName);
34
- private readonly templates = new ArtifactStore<Template>((tpl) => tpl.fullName);
32
+ private readonly templates = new ArtifactStore<TemplateWithSource>((tpl) => tpl.fullName);
33
+
34
+ constructor(
35
+ private readonly compileMode: CompileMode,
36
+ ) { }
35
37
 
36
- private populateTemplateDataFromDependencies(fullName: FullArtifactName,
37
- data: TemplateData,
38
+ /** Recursively add dependencies to the template. */
39
+ private populateTemplateDataFromDependencies(
40
+ fullName: FullArtifactName,
41
+ data: CompiledTemplateV3,
38
42
  deps: TypedArtifactName[],
39
- trace: string[]) {
43
+ trace: string[],
44
+ ) {
40
45
  for (const dep of deps) {
41
46
  switch (dep.type) {
42
47
  case 'library': {
@@ -44,17 +49,19 @@ export class TengoTemplateCompiler {
44
49
 
45
50
  const recursionStart = trace.indexOf(artifactNameToString(dep));
46
51
  if (recursionStart >= 0) {
47
- const errorMessage = `library import recursion detected: ${trace.slice(recursionStart).join(' -> ')} -> ${artifactNameToString(dep)}`;
52
+ const errorMessage = `library import recursion detected: `
53
+ + `${trace.slice(recursionStart).join(' -> ')} -> ${artifactNameToString(dep)}`;
48
54
  throw new Error(errorMessage);
49
55
  }
50
56
 
51
57
  const tplLib = {
52
58
  ...formatArtefactNameAndVersion(lib.fullName),
53
- src: lib.src,
59
+ sourceHash: lib.sourceHash,
54
60
  };
55
61
 
56
62
  applyLibraryCompilerOptions(lib.compilerOptions, tplLib);
57
- data.libs[artifactNameToString(dep)] = tplLib;
63
+ data.template.libs[artifactNameToString(dep)] = tplLib;
64
+ data.hashToSource[tplLib.sourceHash] = lib.src;
58
65
 
59
66
  // populate with transient library dependencies
60
67
  this.populateTemplateDataFromDependencies(fullName, data, lib.dependencies, [...trace, artifactNameToString(dep)]);
@@ -63,10 +70,11 @@ export class TengoTemplateCompiler {
63
70
  }
64
71
  case 'software': {
65
72
  const software = this.getSoftwareOrError(dep);
66
- data.software[artifactNameToString(dep)] = {
73
+ data.template.software[artifactNameToString(dep)] = {
67
74
  ...formatArtefactNameAndVersion(software.fullName),
68
- src: software.src,
75
+ sourceHash: software.sourceHash,
69
76
  };
77
+ data.hashToSource[software.sourceHash] = software.src;
70
78
 
71
79
  break;
72
80
  }
@@ -74,11 +82,11 @@ export class TengoTemplateCompiler {
74
82
  const asset = this.getAssetOrError(dep);
75
83
  // Yes, we temporarily put assets into 'software' section of template, so controller can
76
84
  // handle it the right way without updates
77
- data.software[artifactNameToString(dep)] = {
85
+ data.template.software[artifactNameToString(dep)] = {
78
86
  ...formatArtefactNameAndVersion(asset.fullName),
79
- src: asset.src,
87
+ sourceHash: asset.sourceHash,
80
88
  };
81
-
89
+ data.hashToSource[asset.sourceHash] = asset.src;
82
90
  break;
83
91
  }
84
92
  case 'template': {
@@ -87,12 +95,20 @@ export class TengoTemplateCompiler {
87
95
  continue;
88
96
 
89
97
  const tpl = this.getTemplateOrError(dep);
90
- data.templates[artifactNameToString(dep)] = tpl.data;
98
+ data.template.templates[artifactNameToString(dep)] = tpl.data.template;
99
+ data.hashToSource[tpl.data.template.sourceHash] = tpl.source;
100
+
101
+ // add all the sources of transitivedependencies to the resulted hashToSource
102
+ for (const [hash, src] of Object.entries(tpl.data.hashToSource)) {
103
+ data.hashToSource[hash] = src;
104
+ }
105
+
91
106
  break;
92
107
  }
93
108
  case 'test':
94
109
  throw new Error(
95
- `dependencies tree error: tests should never be part of template: ${typedArtifactNameToString(dep)} is dependency of ${artifactNameToString(fullName)}`,
110
+ `dependencies tree error: tests should never be part of template: `
111
+ + `${typedArtifactNameToString(dep)} is dependency of ${artifactNameToString(fullName)}`,
96
112
  );
97
113
  default:
98
114
  assertNever(dep.type);
@@ -101,29 +117,32 @@ export class TengoTemplateCompiler {
101
117
  }
102
118
 
103
119
  /** This method assumes that all dependencies are already added to the compiler's context */
104
- private compileAndAddTemplate(tplSrc: ArtifactSource): Template {
120
+ private compileAndAddTemplate(tplSrc: ArtifactSource): CompiledTemplateV3 {
105
121
  if (tplSrc.fullName.type !== 'template')
106
122
  throw new Error('unexpected source type');
107
123
 
108
124
  // creating template with unpopulated dependencies
109
- const tplData: TemplateData = {
110
- type: 'pl.tengo-template.v2',
111
- ...formatArtefactNameAndVersion(tplSrc.fullName),
112
- templates: {},
113
- libs: {},
114
- software: {},
115
- assets: {},
116
- src: tplSrc.src,
125
+ const tplData: CompiledTemplateV3 = {
126
+ type: 'pl.tengo-template.v3',
127
+ hashToSource: {
128
+ [tplSrc.sourceHash]: tplSrc.src,
129
+ },
130
+ template: {
131
+ ...formatArtefactNameAndVersion(tplSrc.fullName),
132
+ templates: {},
133
+ libs: {},
134
+ software: {},
135
+ assets: {},
136
+ sourceHash: tplSrc.sourceHash,
137
+ },
117
138
  };
118
139
 
119
- applyTemplateCompilerOptions(tplSrc.compilerOptions, tplData);
140
+ applyTemplateCompilerOptions(tplSrc.compilerOptions, tplData.template);
120
141
 
121
142
  // collecting dependencies in output format
122
143
  this.populateTemplateDataFromDependencies(tplSrc.fullName, tplData, tplSrc.dependencies, []);
123
144
 
124
- const tpl = new Template(tplSrc.compileMode, tplSrc.fullName, { data: tplData });
125
- this.addTemplate(tpl);
126
- return tpl;
145
+ return tplData;
127
146
  }
128
147
 
129
148
  addLib(lib: ArtifactSource) {
@@ -151,6 +170,18 @@ export class TengoTemplateCompiler {
151
170
  return lib;
152
171
  }
153
172
 
173
+ checkLibs() {
174
+ this.libs.forEach(this.compileMode, (lib) => {
175
+ for (const dep of lib.dependencies) {
176
+ if (dep.type === 'test')
177
+ throw new Error(`test should never be dependency of production code: ${typedArtifactNameToString(dep)} test is dependency of ${fullNameToString(lib.fullName)}`);
178
+
179
+ if (!this.getArtefact(dep))
180
+ throw new Error(`unresolved dependency ${typedArtifactNameToString(dep)} for ${fullNameToString(lib.fullName)}`);
181
+ }
182
+ });
183
+ }
184
+
154
185
  addSoftware(software: ArtifactSource) {
155
186
  const swFromMap = this.software.add(software.compileMode, software, false);
156
187
  if (swFromMap && !fullNameEquals(software.fullName, swFromMap.fullName))
@@ -203,7 +234,7 @@ export class TengoTemplateCompiler {
203
234
  return asset;
204
235
  }
205
236
 
206
- addTemplate(tpl: Template) {
237
+ addTemplate(tpl: TemplateWithSource) {
207
238
  const tplFromMap = this.templates.add(tpl.compileMode, tpl, false);
208
239
  if (tplFromMap && !fullNameEquals(tpl.fullName, tplFromMap.fullName))
209
240
  throw new Error(
@@ -211,24 +242,24 @@ export class TengoTemplateCompiler {
211
242
  );
212
243
  }
213
244
 
214
- allTemplates(): Template[] {
245
+ allTemplates(): TemplateWithSource[] {
215
246
  return this.templates.array(this.compileMode);
216
247
  }
217
248
 
218
- getTemplate(name: TypedArtifactName): Template | undefined {
249
+ getTemplate(name: TypedArtifactName): TemplateWithSource | undefined {
219
250
  if (name.type !== 'template')
220
251
  throw new Error(`illegal artifact type: got ${name.type} instead of 'template`);
221
252
  return this.templates.get(this.compileMode, name);
222
253
  }
223
254
 
224
- getTemplateOrError(name: TypedArtifactName): Template {
255
+ getTemplateOrError(name: TypedArtifactName): TemplateWithSource {
225
256
  const tpl = this.getTemplate(name);
226
257
  if (!tpl)
227
258
  throw new Error(`template not found: ${artifactNameToString(name)}`);
228
259
  return tpl;
229
260
  }
230
261
 
231
- getArtefact(name: TypedArtifactName): ArtifactSource | Template | undefined {
262
+ getArtefact(name: TypedArtifactName): ArtifactSource | TemplateWithSource | undefined {
232
263
  switch (name.type) {
233
264
  case 'template':
234
265
  return this.getTemplate(name);
@@ -247,35 +278,29 @@ export class TengoTemplateCompiler {
247
278
  }
248
279
  }
249
280
 
250
- checkLibs() {
251
- this.libs.forEach(this.compileMode, (lib) => {
252
- for (const dep of lib.dependencies) {
253
- if (dep.type === 'test')
254
- throw new Error(`test should never be dependency of production code: ${typedArtifactNameToString(dep)} test is dependency of ${fullNameToString(lib.fullName)}`);
255
-
256
- if (!this.getArtefact(dep))
257
- throw new Error(`unresolved dependency ${typedArtifactNameToString(dep)} for ${fullNameToString(lib.fullName)}`);
258
- }
259
- });
260
- }
261
-
262
281
  compileAndAdd(sources: ArtifactSource[]): TemplatesAndLibs {
263
- const ret: TemplatesAndLibs = { templates: [], libs: [], software: [], assets: [] };
282
+ const result: TemplatesAndLibs = {
283
+ templates: [],
284
+ libs: [],
285
+ software: [],
286
+ assets: [],
287
+ };
288
+
264
289
  let current: ArtifactSource[] = [];
265
290
 
266
291
  for (const src of sources) {
267
292
  if (src.fullName.type === 'library') {
268
293
  // add libraries 'as-is' to be able to resolve them as dependencies
269
294
  this.addLib(src);
270
- ret.libs.push(src);
295
+ result.libs.push(src);
271
296
  } else if (src.fullName.type === 'software') {
272
297
  // add software 'as-is' to be able to resolve them as dependencies
273
298
  this.addSoftware(src);
274
- ret.software.push(src);
299
+ result.software.push(src);
275
300
  } else if (src.fullName.type === 'asset') {
276
301
  // add assets 'as-is' to be able to resolve them as dependencies
277
302
  this.addAsset(src);
278
- ret.assets.push(src);
303
+ result.assets.push(src);
279
304
  } else {
280
305
  current.push(src);
281
306
  }
@@ -312,23 +337,25 @@ export class TengoTemplateCompiler {
312
337
  case 'library':
313
338
  // libraries are added as is
314
339
  this.addLib(src);
315
- ret.libs.push(src);
340
+ result.libs.push(src);
316
341
  break;
317
342
  case 'software':
318
343
  // software dependencies are added as is
319
344
  this.addSoftware(src);
320
- ret.software.push(src);
345
+ result.software.push(src);
321
346
  break;
322
347
  case 'asset':
323
348
  // software dependencies are added as is
324
349
  this.addAsset(src);
325
- ret.assets.push(src);
350
+ result.assets.push(src);
326
351
  break;
327
352
  case 'template':
328
353
  // templates are compiled and then added
329
354
  try {
330
355
  const tpl = this.compileAndAddTemplate(src);
331
- ret.templates.push(tpl);
356
+ const tplWithSrc = newTemplateWithSource(src.compileMode, src.fullName, tpl, src.src);
357
+ this.addTemplate(tplWithSrc);
358
+ result.templates.push(tplWithSrc);
332
359
  } catch (error: unknown) {
333
360
  const err = error as Error;
334
361
  let errorMessage = `Unsatisfied dependencies in ${fullNameToString(src.fullName)}:\n`;
@@ -359,6 +386,6 @@ export class TengoTemplateCompiler {
359
386
  current = unprocessed.map(({ src: ArtifactSource }) => ArtifactSource);
360
387
  }
361
388
 
362
- return ret;
389
+ return result;
363
390
  }
364
391
  }
@@ -1,8 +1,8 @@
1
- import type { TemplateData, TemplateLibData } from '@milaboratories/pl-model-backend';
1
+ import type { TemplateDataV3, TemplateLibDataV3 } from '@milaboratories/pl-model-backend';
2
2
  import type { CompilerOption } from './package';
3
3
  import * as util from './util';
4
4
 
5
- export function applyTemplateCompilerOptions(opts: CompilerOption[], tpl: TemplateData) {
5
+ export function applyTemplateCompilerOptions(opts: CompilerOption[], tpl: TemplateDataV3) {
6
6
  for (const opt of opts) {
7
7
  switch (opt.name) {
8
8
  case 'hash_override': {
@@ -13,7 +13,7 @@ export function applyTemplateCompilerOptions(opts: CompilerOption[], tpl: Templa
13
13
  }
14
14
  }
15
15
 
16
- export function applyLibraryCompilerOptions(opts: CompilerOption[], lib: TemplateLibData) {
16
+ export function applyLibraryCompilerOptions(opts: CompilerOption[], lib: TemplateLibDataV3) {
17
17
  for (const opt of opts) {
18
18
  switch (opt.name) {
19
19
  case 'hash_override': {
@@ -0,0 +1,45 @@
1
+ import { fullNameFromFileName } from './main';
2
+ import { expect, describe, test } from 'vitest';
3
+
4
+ describe('fullNameFromFileName', () => {
5
+ const defaultPackageId = {
6
+ name: 'test-package',
7
+ version: '1.0.0'
8
+ };
9
+
10
+ test.each([
11
+ {
12
+ filename: 'myLib.lib.tengo',
13
+ expectedType: 'library',
14
+ expectedId: 'myLib'
15
+ },
16
+ {
17
+ filename: 'myTemplate.tpl.tengo',
18
+ expectedType: 'template',
19
+ expectedId: 'myTemplate'
20
+ },
21
+ {
22
+ filename: 'mySoftware.sw.json',
23
+ expectedType: 'software',
24
+ expectedId: 'mySoftware'
25
+ },
26
+ {
27
+ filename: 'myAsset.as.json',
28
+ expectedType: 'asset',
29
+ expectedId: 'myAsset'
30
+ },
31
+ {
32
+ filename: 'myTest.test.tengo',
33
+ expectedType: 'test',
34
+ expectedId: 'myTest'
35
+ }
36
+ ])('should correctly parse %s as %s with id %s', ({ filename, expectedType, expectedId }) => {
37
+ const result = fullNameFromFileName(defaultPackageId, filename);
38
+ expect(result).toEqual({
39
+ pkg: defaultPackageId.name,
40
+ version: defaultPackageId.version,
41
+ id: expectedId,
42
+ type: expectedType
43
+ });
44
+ });
45
+ });
@@ -5,6 +5,7 @@ import * as fs from 'node:fs';
5
5
  import { pathType } from './util';
6
6
  import type { TemplatesAndLibs } from './compiler';
7
7
  import { TengoTemplateCompiler } from './compiler';
8
+ import { getSha256 } from './source';
8
9
  import type {
9
10
  CompileMode,
10
11
  FullArtifactName } from './package';
@@ -13,9 +14,10 @@ import {
13
14
  typedArtifactNameToString,
14
15
  } from './package';
15
16
  import { ArtifactSource, parseSourceFile } from './source';
16
- import { Template } from './template';
17
+ import { newTemplateFromContent, templateToSource } from './template';
17
18
  import type winston from 'winston';
18
19
  import { tryResolve, tryResolveOrError } from '@milaboratories/resolve-helper';
20
+ import { serializeTemplate } from '@milaboratories/pl-model-backend';
19
21
 
20
22
  interface PackageId {
21
23
  /** Package name from package.json */
@@ -59,16 +61,17 @@ const srcSoftwareSuffix = '.sw.json';
59
61
  const srcAssetSuffix = '.as.json';
60
62
  const compilableSuffixes = [srcLibSuffix, srcTplSuffix, srcSoftwareSuffix, srcAssetSuffix];
61
63
 
62
- function resolvePackageJsonPath(root: string, packageName?: string): string | undefined {
63
- if (!path.isAbsolute(root))
64
+ /**
65
+ * Resolves path to package.json file of the given dependency package.
66
+ */
67
+ function resolvePackageJsonPackage(root: string, depPackageName: string): string | undefined {
68
+ if (!path.isAbsolute(root)) {
64
69
  throw new Error(`Root path must be absolute: ${root}`);
65
- if (!packageName) {
66
- const p = path.join(root, 'package.json');
67
- if (pathType(p) === 'file')
68
- return p;
69
- throw new Error(`Can't resolve package.json in ${root}`);
70
70
  }
71
- let resolved = tryResolve(root, packageName);
71
+
72
+ // First approach: resolving package's main entry point and try to find package.json
73
+ // in dir tree upwards.
74
+ let resolved = tryResolve(root, depPackageName);
72
75
  if (resolved) {
73
76
  let depth = 0;
74
77
  do {
@@ -79,36 +82,48 @@ function resolvePackageJsonPath(root: string, packageName?: string): string | un
79
82
  resolved = path.dirname(resolved);
80
83
  } while (depth < 7 && path.basename(resolved) !== 'node_modules');
81
84
  }
82
- const resolved2 = tryResolveOrError(root, `${packageName}/package.json`);
85
+
86
+ // Second approach: trying to find package.json in the package dir.
87
+ const resolved2 = tryResolveOrError(root, `${depPackageName}/package.json`);
83
88
  if (resolved2.result === undefined) {
84
89
  if (resolved2.err === 'ERR_PACKAGE_PATH_NOT_EXPORTED')
85
90
  // tolerating not-exported package.json for dev dependencies
86
91
  return undefined;
87
- throw new Error(`Can't resolve package.json for package ${packageName ?? '.'} relative to ${root}`);
92
+ throw new Error(`Can't resolve package.json for package ${depPackageName ?? '.'} relative to ${root}`);
88
93
  }
89
94
  return resolved2.result;
90
95
  }
91
96
 
97
+ export function resolvePackageJsonRoot(root: string): string {
98
+ if (!path.isAbsolute(root)) {
99
+ throw new Error(`Root path must be absolute: ${root}`);
100
+ }
101
+
102
+ const p = path.join(root, 'package.json');
103
+ if (pathType(p) === 'file')
104
+ return p;
105
+ throw new Error(`Can't resolve package.json in ${root}`);
106
+ }
107
+
92
108
  type PackageInfoContext = 'root' | 'dependency' | 'devDependency';
93
109
 
94
110
  /**
95
111
  * Get package info from package.json and all dependencies.
96
- * @param root - Root directory of the package.
97
- * @param cion
98
- * @returns Package info.
99
112
  */
100
- export function getPackageInfo(root: string, logger: winston.Logger, context: PackageInfoContext = 'root'): PackageInfo {
101
- const packageJsonPath = resolvePackageJsonPath(root);
102
- if (!packageJsonPath)
103
- throw new Error(`Can't resolve package.json for root package ${root}`);
104
- const { name, version, type, dependencies, devDependencies }: PackageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString()) as PackageJson;
113
+ export function getPackageInfo(
114
+ root: string,
115
+ logger: winston.Logger,
116
+ context: PackageInfoContext = 'root',
117
+ ): PackageInfo {
118
+ const packageJsonPath = resolvePackageJsonRoot(root);
119
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString()) as PackageJson;
105
120
 
106
121
  // resolving dependencies
107
122
  const depInfos: PackageInfo[] = [];
108
123
 
109
- if (dependencies && context !== 'devDependency') {
110
- for (const dep of Object.keys(dependencies)) {
111
- const depPackageJson = resolvePackageJsonPath(root, dep);
124
+ if (packageJson.dependencies && context !== 'devDependency') {
125
+ for (const dep of Object.keys(packageJson.dependencies)) {
126
+ const depPackageJson = resolvePackageJsonPackage(root, dep);
112
127
  if (depPackageJson === undefined)
113
128
  throw new Error(`Can't resolve package.json for dependency ${dep} of ${root}`);
114
129
  const depRoot = path.dirname(depPackageJson);
@@ -116,9 +131,9 @@ export function getPackageInfo(root: string, logger: winston.Logger, context: Pa
116
131
  }
117
132
  }
118
133
 
119
- if (devDependencies && context === 'root') {
120
- for (const dep of Object.keys(devDependencies)) {
121
- const depPackageJson = resolvePackageJsonPath(root, dep);
134
+ if (packageJson.devDependencies && context === 'root') {
135
+ for (const dep of Object.keys(packageJson.devDependencies)) {
136
+ const depPackageJson = resolvePackageJsonPackage(root, dep);
122
137
  if (depPackageJson === undefined) {
123
138
  logger.warn(`Can't resolve package.json for dev dependency ${dep} of ${root}`);
124
139
  // tolerating not-exported package.json for dev dependencies
@@ -129,9 +144,14 @@ export function getPackageInfo(root: string, logger: winston.Logger, context: Pa
129
144
  }
130
145
  }
131
146
 
132
- const packageInfo: PackageInfo = { name, version, type, dependencies: depInfos, root, context };
133
-
134
- return packageInfo;
147
+ return {
148
+ name: packageJson.name,
149
+ version: packageJson.version,
150
+ type: packageJson.type,
151
+ dependencies: depInfos,
152
+ root,
153
+ context,
154
+ };
135
155
  }
136
156
 
137
157
  function resolveLibsDst(mode: CompileMode, root: string) {
@@ -239,8 +259,8 @@ function loadTemplatesFromDir(
239
259
  id: f.slice(0, f.length - compiledTplSuffix.length),
240
260
  version: packageId.version,
241
261
  };
242
- const tpl = new Template(mode, fullName, { content: fs.readFileSync(file) });
243
- compiler.addTemplate(tpl);
262
+ const tpl = newTemplateFromContent(mode, fullName, fs.readFileSync(file));
263
+ compiler.addTemplate(templateToSource(tpl));
244
264
  logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);
245
265
  }
246
266
  }
@@ -263,7 +283,17 @@ function loadSoftwareFromDir(
263
283
  version: packageId.version,
264
284
  };
265
285
 
266
- const software = new ArtifactSource(mode, fullName, fs.readFileSync(file).toString(), file, [], []);
286
+ const source = fs.readFileSync(file).toString();
287
+
288
+ const software = new ArtifactSource(
289
+ mode,
290
+ fullName,
291
+ getSha256(source),
292
+ source,
293
+ file,
294
+ [],
295
+ [],
296
+ );
267
297
 
268
298
  logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);
269
299
  compiler.addSoftware(software);
@@ -288,7 +318,17 @@ function loadAssetsFromDir(
288
318
  version: packageId.version,
289
319
  };
290
320
 
291
- const asset = new ArtifactSource(mode, fullName, fs.readFileSync(file).toString(), file, [], []);
321
+ const source = fs.readFileSync(file).toString();
322
+
323
+ const asset = new ArtifactSource(
324
+ mode,
325
+ fullName,
326
+ getSha256(source),
327
+ source,
328
+ file,
329
+ [],
330
+ [],
331
+ );
292
332
 
293
333
  logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);
294
334
  compiler.addAsset(asset);
@@ -314,6 +354,7 @@ export function parseSources(
314
354
  continue;
315
355
  }
316
356
 
357
+ // Handling index.lib.tengo files: rename them to <package-name>.lib.tengo
317
358
  const artifactName = f === 'index.lib.tengo' ? `${path.dirname(inRootPath)}.lib.tengo` : inRootPath;
318
359
 
319
360
  const fullName = fullNameFromFileName(packageId, artifactName.replaceAll(path.sep, '.'));
@@ -356,7 +397,7 @@ export function newCompiler(
356
397
  return compiler;
357
398
  }
358
399
 
359
- function fullNameFromFileName(
400
+ export function fullNameFromFileName(
360
401
  packageId: PackageId,
361
402
  artifactName: string,
362
403
  ): FullArtifactName | null {
@@ -404,8 +445,7 @@ function fullNameFromFileName(
404
445
  return null;
405
446
  }
406
447
 
407
- export function compile(logger: winston.Logger, mode: CompileMode): TemplatesAndLibs {
408
- const packageInfo = getPackageInfo(process.cwd(), logger);
448
+ export function compile(logger: winston.Logger, packageInfo: PackageInfo, mode: CompileMode): TemplatesAndLibs {
409
449
  const compiler = newCompiler(logger, packageInfo, mode);
410
450
  const sources = parseSources(logger, packageInfo, mode, 'src', '');
411
451
 
@@ -447,7 +487,7 @@ export function savePacks(logger: winston.Logger, compiled: TemplatesAndLibs, mo
447
487
  for (const tpl of compiled.templates) {
448
488
  const file = path.resolve(tplOutput, tpl.fullName.id + compiledTplSuffix);
449
489
  logger.info(` - writing ${file}`);
450
- fs.writeFileSync(file, tpl.content);
490
+ fs.writeFileSync(file, serializeTemplate(tpl.data));
451
491
  }
452
492
  }
453
493