@platforma-sdk/tengo-builder 1.14.11

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.
Files changed (73) hide show
  1. package/README.md +52 -0
  2. package/bin/run.js +7 -0
  3. package/dist/commands/build.d.ts +13 -0
  4. package/dist/commands/build.d.ts.map +1 -0
  5. package/dist/commands/check.d.ts +11 -0
  6. package/dist/commands/check.d.ts.map +1 -0
  7. package/dist/commands/dump/all.d.ts +7 -0
  8. package/dist/commands/dump/all.d.ts.map +1 -0
  9. package/dist/commands/dump/libs.d.ts +10 -0
  10. package/dist/commands/dump/libs.d.ts.map +1 -0
  11. package/dist/commands/dump/software.d.ts +7 -0
  12. package/dist/commands/dump/software.d.ts.map +1 -0
  13. package/dist/commands/dump/templates.d.ts +7 -0
  14. package/dist/commands/dump/templates.d.ts.map +1 -0
  15. package/dist/commands/dump/tests.d.ts +7 -0
  16. package/dist/commands/dump/tests.d.ts.map +1 -0
  17. package/dist/commands/index.d.ts +9 -0
  18. package/dist/commands/index.d.ts.map +1 -0
  19. package/dist/commands/test.d.ts +11 -0
  20. package/dist/commands/test.d.ts.map +1 -0
  21. package/dist/compiler/artifactset.d.ts +22 -0
  22. package/dist/compiler/artifactset.d.ts.map +1 -0
  23. package/dist/compiler/compiler.d.ts +34 -0
  24. package/dist/compiler/compiler.d.ts.map +1 -0
  25. package/dist/compiler/main.d.ts +17 -0
  26. package/dist/compiler/main.d.ts.map +1 -0
  27. package/dist/compiler/package.d.ts +37 -0
  28. package/dist/compiler/package.d.ts.map +1 -0
  29. package/dist/compiler/source.d.ts +27 -0
  30. package/dist/compiler/source.d.ts.map +1 -0
  31. package/dist/compiler/template.d.ts +49 -0
  32. package/dist/compiler/template.d.ts.map +1 -0
  33. package/dist/compiler/test.artifacts.d.ts +32 -0
  34. package/dist/compiler/test.artifacts.d.ts.map +1 -0
  35. package/dist/compiler/util.d.ts +5 -0
  36. package/dist/compiler/util.d.ts.map +1 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +38 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/index.mjs +851 -0
  42. package/dist/index.mjs.map +1 -0
  43. package/dist/shared/basecmd.d.ts +9 -0
  44. package/dist/shared/basecmd.d.ts.map +1 -0
  45. package/dist/shared/dump.d.ts +7 -0
  46. package/dist/shared/dump.d.ts.map +1 -0
  47. package/dist/shared/proc.d.ts +5 -0
  48. package/dist/shared/proc.d.ts.map +1 -0
  49. package/package.json +44 -0
  50. package/src/commands/build.ts +175 -0
  51. package/src/commands/check.ts +45 -0
  52. package/src/commands/dump/all.ts +17 -0
  53. package/src/commands/dump/libs.ts +24 -0
  54. package/src/commands/dump/software.ts +17 -0
  55. package/src/commands/dump/templates.ts +18 -0
  56. package/src/commands/dump/tests.ts +17 -0
  57. package/src/commands/index.ts +10 -0
  58. package/src/commands/test.ts +41 -0
  59. package/src/compiler/artifactset.ts +76 -0
  60. package/src/compiler/compiler.test.ts +48 -0
  61. package/src/compiler/compiler.ts +300 -0
  62. package/src/compiler/main.ts +363 -0
  63. package/src/compiler/package.ts +96 -0
  64. package/src/compiler/source.test.ts +28 -0
  65. package/src/compiler/source.ts +319 -0
  66. package/src/compiler/template.test.ts +54 -0
  67. package/src/compiler/template.ts +90 -0
  68. package/src/compiler/test.artifacts.ts +195 -0
  69. package/src/compiler/util.ts +38 -0
  70. package/src/index.ts +1 -0
  71. package/src/shared/basecmd.ts +28 -0
  72. package/src/shared/dump.ts +164 -0
  73. package/src/shared/proc.ts +29 -0
@@ -0,0 +1,363 @@
1
+ #!/usr/bin/env node
2
+
3
+ import * as path from 'node:path';
4
+ import * as fs from 'node:fs';
5
+ import { findNodeModules, pathType } from './util';
6
+ import { TemplatesAndLibs, TengoTemplateCompiler } from './compiler';
7
+ import {
8
+ artifactNameToString,
9
+ CompileMode,
10
+ FullArtifactName,
11
+ fullNameToString,
12
+ typedArtifactNameToString
13
+ } from './package';
14
+ import { ArtifactSource, parseSourceFile } from './source';
15
+ import { Template } from './template';
16
+ import winston from 'winston';
17
+
18
+ interface PackageJson {
19
+ name: string;
20
+ version: string;
21
+ type: string;
22
+ }
23
+
24
+ const compiledTplSuffix = '.plj.gz';
25
+ const compiledLibSuffix = '.lib.tengo';
26
+ const compiledSoftwareSuffix = '.sw.json';
27
+
28
+ // We need to keep track of dependencies for correct tgo-test CLI utility configuraiton.
29
+ // It is much simpler to do this here, than duplicate all tle logic regarding dependencies
30
+ // in go code.
31
+ const srcTestSuffix = '.test.tengo';
32
+
33
+ const srcTplSuffix = '.tpl.tengo';
34
+ const srcLibSuffix = '.lib.tengo';
35
+ const srcSoftwareSuffix = '.sw.json';
36
+ const compilableSuffixes = [srcLibSuffix, srcTplSuffix, srcSoftwareSuffix];
37
+
38
+ export function createLogger(level: string = 'debug'): winston.Logger {
39
+ return winston.createLogger({
40
+ level: level,
41
+ format: winston.format.printf(({ level, message }) => {
42
+ return `${level.padStart(6, ' ')}: ${message}`;
43
+ }),
44
+ transports: [
45
+ new winston.transports.Console({
46
+ stderrLevels: ['error', 'warn', 'info', 'debug'],
47
+ handleExceptions: true
48
+ })
49
+ ]
50
+ });
51
+ }
52
+
53
+ export function getPackageInfo(): PackageJson {
54
+ const packageInfo: PackageJson = JSON.parse(fs.readFileSync('package.json').toString());
55
+ return packageInfo;
56
+ }
57
+
58
+ function resolveLibsDst(mode: CompileMode, root: string) {
59
+ return path.resolve(root, mode, 'tengo', 'lib');
60
+ }
61
+
62
+ function resolveTemplatesDst(mode: CompileMode, root: string) {
63
+ return path.resolve(root, mode, 'tengo', 'tpl');
64
+ }
65
+
66
+ function resolveSoftwareDst(mode: CompileMode, root: string) {
67
+ return path.resolve(root, mode, 'tengo', 'software');
68
+ }
69
+
70
+ function loadDependencies(
71
+ logger: winston.Logger,
72
+ compiler: TengoTemplateCompiler,
73
+ packageInfo: PackageJson,
74
+ searchIn: string,
75
+ isLink: boolean = false
76
+ ): void {
77
+ const packageJsonPath = path.resolve(searchIn, 'package.json');
78
+
79
+ if (pathType(packageJsonPath) !== 'file') {
80
+ // We're not in package root. Recursively iterate over all folders looking for packages.
81
+
82
+ for (const f of fs.readdirSync(searchIn)) {
83
+ const isLink = pathType(path.join(searchIn, f)) === 'link';
84
+ const file = path.resolve(searchIn, f);
85
+ const type = pathType(file);
86
+ if (type === 'dir') {
87
+ loadDependencies(logger, compiler, packageInfo, file, isLink);
88
+ }
89
+ }
90
+
91
+ return;
92
+ }
93
+
94
+ // we are in package folder
95
+ const libDistFolder = resolveLibsDst('dist', searchIn);
96
+ const tplDistFolder = resolveTemplatesDst('dist', searchIn);
97
+ const softwareDistFolder = resolveSoftwareDst('dist', searchIn);
98
+
99
+ const libDistExists = pathType(libDistFolder) === 'dir';
100
+ const tplDistExists = pathType(tplDistFolder) === 'dir';
101
+ const softwareDistExists = pathType(softwareDistFolder) === 'dir';
102
+
103
+ if (!libDistExists && !tplDistExists && !softwareDistExists)
104
+ // if neither of tengo-specific folders detected, skipping package
105
+ return;
106
+
107
+ // we are in tengo dependency folder
108
+ const packageJson: PackageJson = JSON.parse(fs.readFileSync(packageJsonPath).toString());
109
+
110
+ // in a workspace we will find ourselves in node_modules, ignoring
111
+ if (packageJson.name === packageInfo.name) return;
112
+
113
+ if (pathType(path.resolve(searchIn, 'node_modules')) === 'dir' && isLink)
114
+ throw new Error(
115
+ `nested node_modules is a sign of library dependencies version incompatibility in ${searchIn}`
116
+ );
117
+
118
+ if (libDistExists) {
119
+ loadLibsFromDir(logger, packageJson, 'dist', libDistFolder, compiler);
120
+ }
121
+
122
+ if (tplDistExists) {
123
+ loadTemplatesFromDir(logger, packageJson, 'dist', tplDistFolder, compiler);
124
+ }
125
+
126
+ if (softwareDistExists) {
127
+ loadSoftwareFromDir(logger, packageJson, 'dist', softwareDistFolder, compiler);
128
+ }
129
+ }
130
+
131
+ function loadLibsFromDir(
132
+ logger: winston.Logger,
133
+ packageJson: PackageJson,
134
+ mode: CompileMode,
135
+ folder: string,
136
+ compiler: TengoTemplateCompiler
137
+ ) {
138
+ for (const f of fs.readdirSync(folder)) {
139
+ const file = path.resolve(folder, f);
140
+ if (!f.endsWith(compiledLibSuffix)) throw new Error(`unexpected file in 'lib' folder: ${file}`);
141
+ const fullName: FullArtifactName = {
142
+ type: 'library',
143
+ pkg: packageJson.name,
144
+ id: f.slice(0, f.length - compiledLibSuffix.length),
145
+ version: packageJson.version
146
+ };
147
+ const src = parseSourceFile(mode, file, fullName, true);
148
+ compiler.addLib(src);
149
+ logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);
150
+ if (src.dependencies.length > 0) {
151
+ logger.debug('Dependencies:');
152
+ for (const dep of src.dependencies) logger.debug(` - ${typedArtifactNameToString(dep)}`);
153
+ }
154
+ }
155
+ }
156
+
157
+ function loadTemplatesFromDir(
158
+ logger: winston.Logger,
159
+ packageJson: PackageJson,
160
+ mode: CompileMode,
161
+ folder: string,
162
+ compiler: TengoTemplateCompiler
163
+ ) {
164
+ // adding templates
165
+ for (const f of fs.readdirSync(folder)) {
166
+ const file = path.resolve(folder, f);
167
+ if (!f.endsWith(compiledTplSuffix)) throw new Error(`unexpected file in 'tpl' folder: ${file}`);
168
+ const fullName: FullArtifactName = {
169
+ type: 'template',
170
+ pkg: packageJson.name,
171
+ id: f.slice(0, f.length - compiledTplSuffix.length),
172
+ version: packageJson.version
173
+ };
174
+ const tpl = new Template(mode, fullName, { content: fs.readFileSync(file) });
175
+ compiler.addTemplate(tpl);
176
+ logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);
177
+ }
178
+ }
179
+
180
+ function loadSoftwareFromDir(
181
+ logger: winston.Logger,
182
+ packageJson: PackageJson,
183
+ mode: CompileMode,
184
+ folder: string,
185
+ compiler: TengoTemplateCompiler
186
+ ) {
187
+ // adding software
188
+ for (const f of fs.readdirSync(folder)) {
189
+ const file = path.resolve(folder, f);
190
+ if (!f.endsWith(compiledSoftwareSuffix))
191
+ throw new Error(`unexpected file in 'software' folder: ${file}`);
192
+ const fullName: FullArtifactName = {
193
+ type: 'software',
194
+ pkg: packageJson.name,
195
+ id: f.slice(0, f.length - compiledSoftwareSuffix.length),
196
+ version: packageJson.version
197
+ };
198
+
199
+ const software = new ArtifactSource(mode, fullName, fs.readFileSync(file).toString(), file, []);
200
+ compiler.addSoftware(software);
201
+ logger.debug(`Adding dependency ${fullNameToString(fullName)} from ${file}`);
202
+ }
203
+ }
204
+
205
+ export function parseSources(
206
+ logger: winston.Logger,
207
+ packageInfo: PackageJson,
208
+ mode: CompileMode,
209
+ root: string,
210
+ subdir: string
211
+ ): ArtifactSource[] {
212
+ const sources: ArtifactSource[] = [];
213
+
214
+ for (const f of fs.readdirSync(path.join(root, subdir))) {
215
+ const inRootPath = path.join(subdir, f); // path to item inside given <root>
216
+ const fullPath = path.join(root, inRootPath); // full path to item from CWD (or abs path, if <root> is abs path)
217
+
218
+ if (pathType(fullPath) === 'dir') {
219
+ const nested = parseSources(logger, packageInfo, mode, root, inRootPath);
220
+ sources.push(...nested);
221
+ continue;
222
+ }
223
+
224
+ const artifactName =
225
+ f === 'index.lib.tengo' ? `${path.basename(subdir)}.lib.tengo` : inRootPath;
226
+
227
+ const fullName = fullNameFromFileName(packageInfo, artifactName.replaceAll(path.sep, '.'));
228
+ if (!fullName) {
229
+ continue; // skip unknown file types
230
+ }
231
+
232
+ // if (subdir != '') {
233
+ // // prettier-ignore
234
+ // throw new Error(`Templates and libraries should reside only inside '${root}' dir.
235
+ // You are free to have any file and dirs structure inside '${root}' keeping other files where you want,
236
+ // but regarding ${compilableSuffixes.join(', ')}, the flat file structure is mandatory.`);
237
+ // }
238
+
239
+ const file = path.resolve(root, inRootPath);
240
+ logger.debug(`Parsing ${fullNameToString(fullName)} from ${file}`);
241
+ const newSrc = parseSourceFile(mode, file, fullName, true);
242
+ if (newSrc.dependencies.length > 0) {
243
+ logger.debug('Detected dependencies:');
244
+ for (const dep of newSrc.dependencies) logger.debug(` - ${typedArtifactNameToString(dep)}`);
245
+ }
246
+
247
+ sources.push(newSrc);
248
+ }
249
+
250
+ return sources;
251
+ }
252
+
253
+ export function newCompiler(
254
+ logger: winston.Logger,
255
+ packageInfo: PackageJson,
256
+ mode: CompileMode
257
+ ): TengoTemplateCompiler {
258
+ const compiler = new TengoTemplateCompiler(mode);
259
+
260
+ // collect all data (templates, libs and software) from dependency tree
261
+ loadDependencies(logger, compiler, packageInfo, findNodeModules());
262
+
263
+ return compiler;
264
+ }
265
+
266
+ function fullNameFromFileName(
267
+ packageJson: PackageJson,
268
+ artifactName: string
269
+ ): FullArtifactName | null {
270
+ const pkgAndVersion = { pkg: packageJson.name, version: packageJson.version };
271
+ if (artifactName.endsWith(srcLibSuffix)) {
272
+ return {
273
+ ...pkgAndVersion,
274
+ id: artifactName.substring(0, artifactName.length - srcLibSuffix.length),
275
+ type: 'library'
276
+ };
277
+ }
278
+
279
+ if (artifactName.endsWith(srcTplSuffix)) {
280
+ return {
281
+ ...pkgAndVersion,
282
+ id: artifactName.substring(0, artifactName.length - srcTplSuffix.length),
283
+ type: 'template'
284
+ };
285
+ }
286
+
287
+ if (artifactName.endsWith(srcSoftwareSuffix)) {
288
+ return {
289
+ ...pkgAndVersion,
290
+ id: artifactName.substring(0, artifactName.length - srcSoftwareSuffix.length),
291
+ type: 'software'
292
+ };
293
+ }
294
+
295
+ if (artifactName.endsWith(srcTestSuffix)) {
296
+ return {
297
+ ...pkgAndVersion,
298
+ id: artifactName.substring(0, artifactName.length - srcTestSuffix.length),
299
+ type: 'test'
300
+ };
301
+ }
302
+
303
+ return null;
304
+ }
305
+
306
+ export function compile(logger: winston.Logger, mode: CompileMode): TemplatesAndLibs {
307
+ const packageInfo = getPackageInfo();
308
+ const compiler = newCompiler(logger, packageInfo, mode);
309
+ const sources = parseSources(logger, packageInfo, mode, 'src', '');
310
+
311
+ // checking that we have something to do
312
+ if (sources.length === 0) {
313
+ const lookFor: string[] = [];
314
+ for (const suffix of compilableSuffixes) {
315
+ lookFor.push(`*${suffix}`);
316
+ }
317
+
318
+ logger.error(`Nothing to compile. Looked for ${lookFor.join(', ')}`);
319
+ process.exit(1);
320
+ }
321
+
322
+ // compilation
323
+ logger.info(`Compiling '${mode}'...`);
324
+ const compiled = compiler.compileAndAdd(sources);
325
+ logger.debug(`Done.`);
326
+
327
+ return compiled;
328
+ }
329
+
330
+ export function savePacks(logger: winston.Logger, compiled: TemplatesAndLibs, mode: CompileMode) {
331
+ // writing libs
332
+ if (compiled.libs.length > 0) {
333
+ const libOutput = resolveLibsDst(mode, '.');
334
+ fs.mkdirSync(libOutput, { recursive: true });
335
+ for (const lib of compiled.libs) {
336
+ const file = path.resolve(libOutput, lib.fullName.id + compiledLibSuffix);
337
+ logger.info(` - writing ${file}`);
338
+ fs.writeFileSync(file, lib.src);
339
+ }
340
+ }
341
+
342
+ // writing templates
343
+ if (compiled.templates.length > 0) {
344
+ const tplOutput = resolveTemplatesDst(mode, '.');
345
+ fs.mkdirSync(tplOutput, { recursive: true });
346
+ for (const tpl of compiled.templates) {
347
+ const file = path.resolve(tplOutput, tpl.fullName.id + compiledTplSuffix);
348
+ logger.info(` - writing ${file}`);
349
+ fs.writeFileSync(file, tpl.content);
350
+ }
351
+ }
352
+
353
+ // writing software
354
+ if (compiled.software.length > 0) {
355
+ const swOutput = resolveSoftwareDst(mode, '.');
356
+ fs.mkdirSync(swOutput, { recursive: true });
357
+ for (const sw of compiled.software) {
358
+ const file = path.resolve(swOutput, sw.fullName.id + compiledSoftwareSuffix);
359
+ logger.info(` - writing ${file}`);
360
+ fs.writeFileSync(file, sw.src);
361
+ }
362
+ }
363
+ }
@@ -0,0 +1,96 @@
1
+ import { gunzipSync, gzipSync } from 'node:zlib';
2
+ import canonicalize from 'canonicalize';
3
+
4
+ /*
5
+ Package "@milaboratory/current-tengo-package".
6
+
7
+ Structure:
8
+
9
+ src/
10
+ local-template.pl.tengo <- this one will be compiled and put into ./dist/tengo/tpl/local-template.pl.pkg
11
+ local-library.tengo <- this one will be normalized and put into ./dist/tengo/lib/local-library.tengo
12
+ main.tpl.tengo <- this one will be compiled into ./dist/tengo/tpl/main.pl.pkg and published by external tool
13
+
14
+ Code of "main.tpl.tengo":
15
+
16
+ plapi := import("plapi")
17
+
18
+ plapi.getTemplateId("@milaboratory/some-tengo-template") // -> getTemplateId("@milaboratory/some-tengo-template:main")
19
+ import("@milaboratory/some-tengo-library") // -> import("@milaboratory/some-tengo-library:main")
20
+
21
+ */
22
+
23
+ export type CompileMode = 'dist'
24
+
25
+ export type ArtifactType = 'library' | 'template' | 'test' | 'software'
26
+
27
+ /** Artifact Name including package version */
28
+ export interface FullArtifactName {
29
+ /** Dependency type */
30
+ type: ArtifactType;
31
+
32
+ /** Fully qualified package */
33
+ pkg: string;
34
+
35
+ /** Id of the artifact inside the package */
36
+ id: string;
37
+
38
+ /** Package version */
39
+ version: string;
40
+ }
41
+
42
+ export type FullArtifactNameWithoutType = Omit<FullArtifactName, 'type'>;
43
+
44
+ export type TypedArtifactName = Pick<FullArtifactName, 'type' | 'pkg' | 'id'>;
45
+
46
+ export type PackageName = Pick<FullArtifactName, 'pkg' | 'version'>;
47
+
48
+ export type ArtifactName = Pick<FullArtifactName, 'pkg' | 'id'>;
49
+
50
+ export function artifactKey(name: TypedArtifactName): string {
51
+ return `${name.type}||${name.pkg}||${name.id}`;
52
+ }
53
+
54
+ export function fullNameToString(name: FullArtifactName): string {
55
+ return `${name.type}:${name.pkg}:${name.id}:${name.version}`;
56
+ }
57
+
58
+ /** used for exceptions */
59
+ export function typedArtifactNameToString(name: TypedArtifactName): string {
60
+ return `${name.type}:${name.pkg}:${name.id}`;
61
+ }
62
+
63
+ export function typedArtifactNamesEquals(name1: TypedArtifactName, name2: TypedArtifactName): boolean {
64
+ return name1.type == name2.type && name1.pkg == name2.pkg && name1.id == name2.id;
65
+ }
66
+
67
+
68
+ /** used to format artefact name while generating output files */
69
+ export function artifactNameToString(name: ArtifactName): string {
70
+ return `${name.pkg}:${name.id}`;
71
+ }
72
+
73
+ /** used to format artefact name and version while generating output files */
74
+ export function formatArtefactNameAndVersion(name: FullArtifactName): { name: string, version: string } {
75
+ return { name: artifactNameToString(name), version: name.version };
76
+ }
77
+
78
+ /** used to format artefact name and version while generating output files */
79
+ export function parseArtefactNameAndVersion(nameAndVersion: {
80
+ name: string,
81
+ version: string
82
+ }): FullArtifactNameWithoutType {
83
+ const match = nameAndVersion.name.match(/^(?<pkg>[^:]*):(?<id>[^:]*)$/);
84
+ if (!match)
85
+ throw new Error(`malformed artifact name: ${nameAndVersion.name}`);
86
+ return { pkg: match.groups!['pkg'], id: match.groups!['id'], version: nameAndVersion.version };
87
+ }
88
+
89
+
90
+ export function fullNameWithoutTypeToString(name: FullArtifactNameWithoutType): string {
91
+ return `${name.pkg}:${name.id}:${name.version}`;
92
+ }
93
+
94
+ export function fullNameWithoutType(name: FullArtifactName): FullArtifactNameWithoutType {
95
+ return { pkg: name.pkg, id: name.id, version: name.version };
96
+ }
@@ -0,0 +1,28 @@
1
+ import { parseSource } from './source';
2
+ import { testLocalLib1Src, testLocalLib1Name, testLocalLib2Src, testLocalLib1SrcNormalized } from './test.artifacts';
3
+
4
+ test('test lib 1 parsing', () => {
5
+ const libSrc = parseSource('dist', testLocalLib1Src, testLocalLib1Name, true);
6
+ expect(libSrc.src).toEqual(testLocalLib1SrcNormalized)
7
+ expect(libSrc.dependencies).toEqual([
8
+ { type: 'library', pkg: 'package1', id: 'other-lib-2' },
9
+ { type: 'software', pkg: 'current-package', id: 'software-1' },
10
+ { type: 'template', pkg: 'current-package', id: 'local-template-2' },
11
+ { type: 'template', pkg: 'package1', id: 'template-3' }
12
+ ]);
13
+
14
+ expect(
15
+ parseSource('dist', testLocalLib1Src, testLocalLib1Name, false).src
16
+ ).toEqual(testLocalLib1Src)
17
+ });
18
+
19
+ test('test lib 2 parsing', () => {
20
+ const libSrc = parseSource('dist', testLocalLib2Src, testLocalLib1Name, true);
21
+ expect(libSrc.dependencies).toEqual([
22
+ { type: 'library', pkg: 'package1', id: 'someid' },
23
+ { type: 'library', pkg: '@milaboratory/tengo-sdk', id: 'll' },
24
+ { type: 'template', pkg: 'package2', id: 'template-1' },
25
+ { type: 'software', pkg: 'package2', id: 'software-1' },
26
+ { type: 'template', pkg: 'current-package', id: 'local-template-2' },
27
+ ]);
28
+ });