@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,319 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { TypedArtifactName, FullArtifactName, ArtifactType, CompileMode } from './package';
3
+ import { ArtifactMap, createArtifactNameSet } from './artifactset';
4
+
5
+ // matches any valid name in tengo. Don't forget to use '\b' when needed to limit the boundaries!
6
+ const namePattern = '[_a-zA-Z][_a-zA-Z0-9]*';
7
+
8
+ const functionCallRE = (moduleName: string, fnName: string) => {
9
+ return new RegExp(
10
+ `\\b${moduleName}\\.(?<fnCall>(?<fnName>` +
11
+ fnName +
12
+ `)\\s*\\(\\s*"(?<templateName>[^"]+)"\\s*\\))`
13
+ );
14
+ };
15
+
16
+ const newGetTemplateIdRE = (moduleName: string) => {
17
+ return functionCallRE(moduleName, 'getTemplateId');
18
+ };
19
+ const newGetSoftwareInfoRE = (moduleName: string) => {
20
+ return functionCallRE(moduleName, 'getSoftwareInfo');
21
+ };
22
+
23
+ const newImportTemplateRE = (moduleName: string) => {
24
+ return functionCallRE(moduleName, 'importTemplate');
25
+ };
26
+ const newImportSoftwareRE = (moduleName: string) => {
27
+ return functionCallRE(moduleName, 'importSoftware');
28
+ };
29
+
30
+ const singlelineCommentRE = /^\s*(\/\/)|(\/\*.*\*\/)/;
31
+ const multilineCommentStartRE = /^\s*\/\*/;
32
+ const multilineCommentEndRE = /\*\//;
33
+ const importRE = /\s*:=\s*import\s*\(\s*"(?<moduleName>[^"]+)"\s*\)/;
34
+ const importNameRE = new RegExp(
35
+ `\\b(?<importName>${namePattern}(\\.${namePattern})*)${importRE.source}`
36
+ );
37
+ const dependencyRE = /(?<pkgName>[^"]+)?:(?<depID>[^"]+)/; // use it to parse <moduleName> from importPattern or <templateName> акщь getTemplateID
38
+
39
+ export class ArtifactSource {
40
+ constructor(
41
+ /** The mode this artifact was built (dev or dist) */
42
+ public readonly compileMode: CompileMode,
43
+ /** Full artifact id, including package version */
44
+ public readonly fullName: FullArtifactName,
45
+ /** Normalized source code */
46
+ public readonly src: string,
47
+ /** Path to source file where artifact came from */
48
+ public readonly srcName: string,
49
+ /** List of dependencies */
50
+ public readonly dependencies: TypedArtifactName[]
51
+ ) {}
52
+ }
53
+
54
+ export function parseSourceFile(
55
+ mode: CompileMode,
56
+ srcFile: string,
57
+ fullSourceName: FullArtifactName,
58
+ normalize: boolean
59
+ ): ArtifactSource {
60
+ const src = readFileSync(srcFile).toString();
61
+ const { deps, normalized } = parseSourceData(src, fullSourceName, normalize);
62
+
63
+ return new ArtifactSource(mode, fullSourceName, normalized, srcFile, deps.array);
64
+ }
65
+
66
+ export function parseSource(
67
+ mode: CompileMode,
68
+ src: string,
69
+ fullSourceName: FullArtifactName,
70
+ normalize: boolean
71
+ ): ArtifactSource {
72
+ const { deps, normalized } = parseSourceData(src, fullSourceName, normalize);
73
+
74
+ return new ArtifactSource(mode, fullSourceName, normalized, '', deps.array);
75
+ }
76
+
77
+ function parseSourceData(
78
+ src: string,
79
+ fullSourceName: FullArtifactName,
80
+ globalizeImports: boolean
81
+ ): {
82
+ normalized: string;
83
+ deps: ArtifactMap<TypedArtifactName>;
84
+ } {
85
+ const dependencySet = createArtifactNameSet();
86
+
87
+ // iterating over lines
88
+ const lines = src.split('\n');
89
+
90
+ // processedLines keep all the original lines from <src>.
91
+ // If <globalizeImport>==true, the parser modifies 'import' and 'getTemplateId' lines
92
+ // with Platforma Tengo lib and template usages, resolving local names (":<item>") to
93
+ // global ("@milaboratory/pkg:<item>")
94
+ const processedLines: string[] = [];
95
+ let parserContext: sourceParserContext = {
96
+ isInCommentBlock: false,
97
+ tplDepREs: new Map<string, [ArtifactType, RegExp][]>()
98
+ };
99
+
100
+ let lineNo = 0;
101
+ for (const line of lines) {
102
+ lineNo++;
103
+
104
+ try {
105
+ const result = parseSingleSourceLine(
106
+ line,
107
+ parserContext,
108
+ fullSourceName.pkg,
109
+ globalizeImports
110
+ );
111
+ processedLines.push(result.line);
112
+ parserContext = result.context;
113
+
114
+ if (result.artifact) {
115
+ dependencySet.add(result.artifact);
116
+ }
117
+ } catch (error: any) {
118
+ throw new Error(`[line ${lineNo}]: ${error.message}\n\t${line}`);
119
+ }
120
+ }
121
+
122
+ return {
123
+ normalized: processedLines.join('\n'),
124
+ deps: dependencySet
125
+ };
126
+ }
127
+
128
+ interface sourceParserContext {
129
+ isInCommentBlock: boolean;
130
+ tplDepREs: Map<string, [ArtifactType, RegExp][]>;
131
+ }
132
+
133
+ function parseSingleSourceLine(
134
+ line: string,
135
+ context: sourceParserContext,
136
+ localPackageName: string,
137
+ globalizeImports: boolean
138
+ ): {
139
+ line: string;
140
+ context: sourceParserContext;
141
+ artifact: TypedArtifactName | undefined;
142
+ } {
143
+ if (context.isInCommentBlock) {
144
+ if (multilineCommentEndRE.exec(line)) {
145
+ context.isInCommentBlock = false;
146
+ }
147
+ return { line, context, artifact: undefined };
148
+ }
149
+
150
+ if (singlelineCommentRE.exec(line)) {
151
+ return { line, context, artifact: undefined };
152
+ }
153
+
154
+ if (multilineCommentStartRE.exec(line)) {
155
+ context.isInCommentBlock = true;
156
+ return { line, context, artifact: undefined };
157
+ }
158
+
159
+ const importInstruction = importRE.exec(line);
160
+
161
+ if (importInstruction) {
162
+ const iInfo = parseImport(line);
163
+
164
+ if (iInfo.module === 'plapi') {
165
+ if (!context.tplDepREs.has(iInfo.module)) {
166
+ context.tplDepREs.set(iInfo.module, [
167
+ ['template', newGetTemplateIdRE(iInfo.alias)],
168
+ ['software', newGetSoftwareInfoRE(iInfo.alias)]
169
+ ]);
170
+ }
171
+ return { line, context, artifact: undefined };
172
+ }
173
+
174
+ if (
175
+ iInfo.module === '@milaboratory/tengo-sdk:ll' ||
176
+ iInfo.module === '@platforma-sdk/workflow-tengo:ll' ||
177
+ ((localPackageName === '@milaboratory/tengo-sdk' ||
178
+ localPackageName === '@platforma-sdk/workflow-tengo') &&
179
+ iInfo.module === ':ll')
180
+ ) {
181
+ if (!context.tplDepREs.has(iInfo.module)) {
182
+ context.tplDepREs.set(iInfo.module, [
183
+ ['template', newImportTemplateRE(iInfo.alias)],
184
+ ['software', newImportSoftwareRE(iInfo.alias)]
185
+ ]);
186
+ }
187
+ }
188
+
189
+ if (
190
+ iInfo.module === '@milaboratory/tengo-sdk:assets' ||
191
+ iInfo.module === '@platforma-sdk/workflow-tengo:assets' ||
192
+ ((localPackageName === '@milaboratory/tengo-sdk' ||
193
+ localPackageName === '@platforma-sdk/workflow-tengo') &&
194
+ iInfo.module === ':assets')
195
+ ) {
196
+ if (!context.tplDepREs.has(iInfo.module)) {
197
+ context.tplDepREs.set(iInfo.module, [
198
+ ['template', newImportTemplateRE(iInfo.alias)],
199
+ ['software', newImportSoftwareRE(iInfo.alias)]
200
+ ]);
201
+ }
202
+ }
203
+
204
+ const artifact = parseArtifactName(iInfo.module, 'library', localPackageName);
205
+ if (!artifact) {
206
+ // not a Platforma Tengo library import
207
+ return { line, context, artifact: undefined };
208
+ }
209
+
210
+ if (globalizeImports) {
211
+ line = line.replace(importInstruction[0], ` := import("${artifact.pkg}:${artifact.id}")`);
212
+ }
213
+
214
+ return { line, context, artifact };
215
+ }
216
+
217
+ if (context.tplDepREs.size > 0) {
218
+ for (const [key, artifactRE] of context.tplDepREs) {
219
+ for (const [artifactType, re] of artifactRE) {
220
+ const match = re.exec(line);
221
+ if (!match || !match.groups) {
222
+ continue;
223
+ }
224
+
225
+ const { fnCall, templateName, fnName } = match.groups;
226
+
227
+ if (!fnCall || !templateName || !fnName) {
228
+ throw Error(`failed to parse template import statement`);
229
+ }
230
+
231
+ const artifact = parseArtifactName(templateName, artifactType, localPackageName);
232
+ if (!artifact) {
233
+ throw Error(`failed to parse artifact name in ${fnName} import statement`);
234
+ }
235
+
236
+ if (globalizeImports) {
237
+ line = line.replace(fnCall, `${fnName}("${artifact.pkg}:${artifact.id}")`);
238
+ }
239
+
240
+ return { line, context, artifact };
241
+ }
242
+ }
243
+ }
244
+
245
+ return { line, context, artifact: undefined };
246
+ }
247
+
248
+ interface ImportInfo {
249
+ module: string; // the module name without wrapping quotes: import("<module>")
250
+ alias: string; // the name of variable that keeps imported module: <alias> := import("<module>")
251
+ }
252
+
253
+ function parseImport(line: string): ImportInfo {
254
+ const match = importNameRE.exec(line);
255
+
256
+ if (!match || !match.groups) {
257
+ throw Error(`failed to parse 'import' statement`);
258
+ }
259
+
260
+ const { importName, moduleName } = match.groups;
261
+ if (!importName || !moduleName) {
262
+ throw Error(`failed to parse 'import' statement`);
263
+ }
264
+
265
+ return {
266
+ module: moduleName,
267
+ alias: importName
268
+ };
269
+ }
270
+
271
+ function parseArtifactName(
272
+ moduleName: string,
273
+ aType: ArtifactType,
274
+ localPackageName: string
275
+ ): TypedArtifactName | undefined {
276
+ const depInfo = dependencyRE.exec(moduleName);
277
+ if (!depInfo) {
278
+ return;
279
+ }
280
+
281
+ if (!depInfo.groups) {
282
+ throw Error(
283
+ `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`
284
+ );
285
+ }
286
+
287
+ const { pkgName, depID } = depInfo.groups;
288
+ if (!depID) {
289
+ throw Error(
290
+ `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`
291
+ );
292
+ }
293
+
294
+ return { type: aType, pkg: pkgName ?? localPackageName, id: depID };
295
+ }
296
+
297
+ function parseTemplateUse(match: RegExpExecArray, localPackageName: string): TypedArtifactName {
298
+ const { templateName } = match.groups!;
299
+
300
+ if (!templateName) {
301
+ throw Error(`failed to parse 'getTemplateId' statement`);
302
+ }
303
+
304
+ const depInfo = dependencyRE.exec(templateName);
305
+ if (!depInfo || !depInfo.groups) {
306
+ throw Error(
307
+ `failed to parse dependency name inside 'getTemplateId' statement. The dependency name should have format '<package>:<templateName>'`
308
+ );
309
+ }
310
+
311
+ const { pkgName, depID } = depInfo.groups;
312
+ if (!pkgName || !depID) {
313
+ throw Error(
314
+ `failed to parse dependency name inside 'getTemplateId' statement. The dependency name should have format '<package>:<templateName>'`
315
+ );
316
+ }
317
+
318
+ return { type: 'template', pkg: pkgName ?? localPackageName, id: depID };
319
+ }
@@ -0,0 +1,54 @@
1
+ import { Template } from './template';
2
+ import { formatArtefactNameAndVersion, FullArtifactName } from './package';
3
+
4
+ test('template serialization / deserialization', () => {
5
+ const name: FullArtifactName = {
6
+ type: 'template',
7
+ pkg: '@milaboratory/some-package',
8
+ id: 'the-template',
9
+ version: '1.2.3'
10
+ };
11
+ const template1 = new Template('dist', name,
12
+ {
13
+ data: {
14
+ type: 'pl.tengo-template.v2',
15
+ ...formatArtefactNameAndVersion(name),
16
+ libs: {
17
+ '@milaboratory/some-package:the-library': {
18
+ name: '@milaboratory/some-package:the-library',
19
+ version: '1.2.3',
20
+ src: 'asdasd'
21
+ }
22
+ },
23
+ templates: {
24
+ '@milaboratory/some-package:the-template-1': {
25
+ type: 'pl.tengo-template.v2',
26
+ name: '@milaboratory/some-package:the-template-1',
27
+ version: '1.2.3',
28
+ libs: {
29
+ '@milaboratory/some-package:the-library:1.2.4': {
30
+ name: '@milaboratory/some-package:the-library',
31
+ version: '1.2.4',
32
+ src: 'asdasd'
33
+ }
34
+ },
35
+ templates: {},
36
+ software: {},
37
+ src: 'src 1...'
38
+ }
39
+ },
40
+ software: {},
41
+ src: 'src 2 ...'
42
+ }
43
+ }
44
+ );
45
+
46
+ const template2 = new Template('dist',
47
+ { type: 'template', pkg: '@milaboratory/some-package', id: 'the-template', version: '1.2.3' },
48
+ { content: template1.content }
49
+ );
50
+
51
+ console.log('Size: raw', JSON.stringify(template1.data).length, 'compressed', template1.content.byteLength);
52
+
53
+ expect(template2.data).toStrictEqual(template1.data);
54
+ });
@@ -0,0 +1,90 @@
1
+ import { gunzipSync, gzipSync } from 'node:zlib';
2
+ import canonicalize from 'canonicalize';
3
+ import {
4
+ CompileMode,
5
+ FullArtifactName,
6
+ FullArtifactNameWithoutType,
7
+ fullNameWithoutTypeToString,
8
+ parseArtefactNameAndVersion
9
+ } from './package';
10
+
11
+ export interface TemplateLibData {
12
+ /** i.e. @milaboratory/some-package:lib1 */
13
+ name: string;
14
+ /** i.e. 1.2.3 */
15
+ version: string;
16
+ /** full source code */
17
+ src: string,
18
+ }
19
+
20
+ export interface TemplateSoftwareData {
21
+ /** i.e. @milaboratory/mixcr:main */
22
+ name: string;
23
+ /** i.e. 4.2.3 */
24
+ version: string;
25
+ /** full contents of software dependency description */
26
+ src: string,
27
+ }
28
+
29
+ export interface TemplateData {
30
+ /** Discriminator for future use */
31
+ type: 'pl.tengo-template.v2';
32
+
33
+ /** i.e. @milaboratory/some-package:template */
34
+ name: string;
35
+ /** i.e. 1.2.3 */
36
+ version: string;
37
+
38
+ /** i.e. @milaboratory/some-package:some-lib -> normalized library source code */
39
+ libs: Record<string, TemplateLibData>;
40
+ /** i.e. @milaboratory/some-package:some-lib -> to nested template data */
41
+ templates: Record<string, TemplateData>;
42
+ /** i.e. @milaboratory/mixcr:main -> software metadata */
43
+ software: Record<string, TemplateSoftwareData>;
44
+ /** Template source code */
45
+ src: string;
46
+ }
47
+
48
+ const decoder = new TextDecoder();
49
+ const encoder = new TextEncoder();
50
+
51
+ export class Template {
52
+ public readonly data: TemplateData;
53
+ public readonly content: Uint8Array;
54
+
55
+ constructor(
56
+ public readonly compileMode: CompileMode,
57
+ public readonly fullName: FullArtifactName,
58
+ body: {
59
+ data?: TemplateData,
60
+ content?: Uint8Array
61
+ }
62
+ ) {
63
+ let { data, content } = body;
64
+ if (data === undefined && content === undefined)
65
+ throw new Error('Neither data nor content is provided for template constructor');
66
+ if (data !== undefined && content !== undefined)
67
+ throw new Error('Both data and content are provided for template constructor');
68
+
69
+ if (data === undefined) {
70
+ data = JSON.parse(decoder.decode(gunzipSync(content!))) as TemplateData;
71
+ if (data.type !== 'pl.tengo-template.v2')
72
+ throw new Error('malformed template');
73
+ }
74
+
75
+ if (content === undefined)
76
+ content = gzipSync(encoder.encode(canonicalize(data!)));
77
+
78
+ const nameFromData: FullArtifactNameWithoutType = parseArtefactNameAndVersion(data);
79
+
80
+ if (nameFromData.pkg !== fullName.pkg || nameFromData.id !== fullName.id || nameFromData.version !== fullName.version)
81
+ throw new Error(`Compiled template name don't match it's package and file names: ${fullNameWithoutTypeToString(nameFromData)} != ${fullNameWithoutTypeToString(fullName)}`);
82
+
83
+ this.data = data;
84
+ this.content = content;
85
+ }
86
+
87
+ toJSON() {
88
+ return { compileMode: this.compileMode, fullName: this.fullName, data: this.data }
89
+ }
90
+ }
@@ -0,0 +1,195 @@
1
+ import { FullArtifactName } from './package';
2
+
3
+ export interface TestArtifactSource {
4
+ fullName: FullArtifactName;
5
+ src: string;
6
+ }
7
+
8
+ /*
9
+
10
+ tpl:current-package:local-template-1
11
+ - tpl:current-package:local-template-1 == self
12
+ - lib:current-package:local-library-1
13
+ - lib:package1:other-lib-1
14
+
15
+ lib:current-package:local-library-1
16
+ - tpl:package1:template-3
17
+ - tpl:current-package:local-template-2
18
+ - lib:package1:other-lib-2
19
+
20
+ tpl:current-package:local-template-2
21
+ - lib:package1:other-lib-1
22
+
23
+ tpl:package1:template-3
24
+ - package1:other-lib-1
25
+
26
+ lib:package1:other-lib-1
27
+
28
+ lib:package1:other-lib-2
29
+ - lib:package1:other-lib-1
30
+ - tpl:package1:template-3
31
+
32
+ */
33
+
34
+ export const testLocalLib1Name: FullArtifactName = {
35
+ type: 'library',
36
+ pkg: 'current-package',
37
+ id: 'local-library-1',
38
+ version: '1.2.3'
39
+ };
40
+ export const testLocalLib1Src = `
41
+ otherLib := import("package1:other-lib-2" )
42
+ plapiCustomName := import("plapi" )
43
+
44
+ notplapiCustomName.getTemplateId( "some other:parameter")
45
+
46
+ plapiCustomName.getTemplateIdAnother("sss:kkk" )
47
+ plapiCustomName.getSoftwareInfo(":software-1")
48
+
49
+ export {
50
+ "some": "value",
51
+ "template2": plapiCustomName.getTemplateId(":local-template-2" ),
52
+ "template3": plapiCustomName.getTemplateId ( "package1:template-3")
53
+ }
54
+ `;
55
+ export const testLocalLib1SrcNormalized = `
56
+ otherLib := import("package1:other-lib-2")
57
+ plapiCustomName := import("plapi" )
58
+
59
+ notplapiCustomName.getTemplateId( "some other:parameter")
60
+
61
+ plapiCustomName.getTemplateIdAnother("sss:kkk" )
62
+ plapiCustomName.getSoftwareInfo("current-package:software-1")
63
+
64
+ export {
65
+ "some": "value",
66
+ "template2": plapiCustomName.getTemplateId("current-package:local-template-2"),
67
+ "template3": plapiCustomName.getTemplateId("package1:template-3")
68
+ }
69
+ `;
70
+ export const testLocalLib2Src = `
71
+ otherLib := import("package1:someid")
72
+ ll := import("@milaboratory/tengo-sdk:ll")
73
+
74
+ /* multiline comments should be ignored
75
+ a := import(":non-existent-library")
76
+ */
77
+
78
+ tplID := ll.importTemplate("package2:template-1")
79
+ softwareID := ll.importSoftware("package2:software-1")
80
+
81
+ export {
82
+ "some": "value",
83
+ "template1": ll.importTemplate("current-package:local-template-2"),
84
+ "template2": tplID,
85
+ }
86
+ `;
87
+
88
+ export const testLocalTpl1Name: FullArtifactName = {
89
+ type: 'template',
90
+ pkg: 'current-package',
91
+ id: 'local-template-1',
92
+ version: '1.2.3'
93
+ };
94
+ export const testLocalTpl1Src = `
95
+ lib1 := import( ":local-library-1")
96
+ lib2 := import("package1:other-lib-1")
97
+ plapi := import("plapi")
98
+
99
+ tpl2 := plapi.getTemplateId("current-package:local-template-1" )
100
+ `;
101
+
102
+ export const testLocalTpl2Name: FullArtifactName = {
103
+ type: 'template',
104
+ pkg: 'current-package',
105
+ id: 'local-template-2',
106
+ version: '1.2.3'
107
+ };
108
+ export const testLocalTpl2Src = `
109
+ lib := import("package1:other-lib-1")
110
+ `;
111
+ export const testLocalTpl2SrcNormalized = `
112
+ lib := import("package1:other-lib-1")
113
+ `;
114
+
115
+ export const testLocalLib1: TestArtifactSource = {
116
+ fullName: testLocalLib1Name,
117
+ src: testLocalLib1Src,
118
+ };
119
+
120
+ export const testLocalTpl1: TestArtifactSource = {
121
+ fullName: testLocalTpl1Name,
122
+ src: testLocalTpl1Src,
123
+ };
124
+
125
+ export const testLocalTpl2: TestArtifactSource = {
126
+ fullName: testLocalTpl2Name,
127
+ src: testLocalTpl2Src,
128
+ };
129
+
130
+ export const testLocalPackage = [testLocalTpl1, testLocalLib1, testLocalTpl2];
131
+
132
+ export const testPackage1Lib1Name: FullArtifactName = {
133
+ type: 'library',
134
+ pkg: 'package1',
135
+ id: 'other-lib-1',
136
+ version: '1.2.3'
137
+ };
138
+ export const testPackage1Lib1Src = `
139
+ export {
140
+ "some": "value1"
141
+ }
142
+ `;
143
+
144
+ export const testPackage1Soft1Name: FullArtifactName = {
145
+ type: 'software',
146
+ pkg: 'current-package',
147
+ id: 'software-1',
148
+ version: '1.2.3'
149
+ };
150
+ export const testPackage1Soft1Src = `
151
+ some software contents. Template builder should pass it 'as-is'
152
+ `;
153
+
154
+ export const testPackage1Lib2Name: FullArtifactName = {
155
+ type: 'library',
156
+ pkg: 'package1',
157
+ id: 'other-lib-2',
158
+ version: '1.2.3'
159
+ };
160
+ export const testPackage1Lib2Src = `
161
+ lib := import("package1:other-lib-1")
162
+ export {
163
+ "some": "value123",
164
+ "theTpl": getTemplateId("package1:template-3")
165
+ }
166
+ `;
167
+
168
+ export const testPackage1Tpl3Name: FullArtifactName = {
169
+ type: 'template',
170
+ pkg: 'package1',
171
+ id: 'template-3',
172
+ version: '1.2.3'
173
+ };
174
+ export const testPackage1Tpl3Src = `
175
+ lib := import("package1:other-lib-1")
176
+ `;
177
+
178
+ export const testPackage1Tpl3CompiledBase64 = 'H4sIAAAAAAAAE22PQQqDMBREr/KZVQsxELsL9CZ/E+VjQ2MiJpUWyd2LglCo2xlm3syK4LsMu2Jy/dMNYmwqD5mb4LvGbHp0o8Ce2wp57mHBUd5TmgutHImIGDmNwrDEWFx4iWFwrByhsMicfYqwMLrVN9Sq/hhFxim4Is3tBxF8R3fy4wa68OkgxnVnHPntWFUon2mvD7pIHFJz2HppzwZ9AanB7OAUAQAA';
179
+
180
+ export const testPackage1Lib1: TestArtifactSource = {
181
+ fullName: testPackage1Lib1Name,
182
+ src: testPackage1Lib1Src,
183
+ };
184
+
185
+ export const testPackage1Lib2: TestArtifactSource = {
186
+ fullName: testPackage1Lib2Name,
187
+ src: testPackage1Lib2Src,
188
+ };
189
+
190
+ export const testPackage1Tpl3: TestArtifactSource = {
191
+ fullName: testPackage1Tpl3Name,
192
+ src: testPackage1Tpl3Src,
193
+ };
194
+
195
+ export const testPackage1 = [testPackage1Lib1, testPackage1Lib2, testPackage1Tpl3];
@@ -0,0 +1,38 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+
4
+ export function assertNever(x: never): never {
5
+ throw new Error('Unexpected object: ' + x);
6
+ }
7
+
8
+ export function findNodeModules(): string {
9
+ let currentDir = process.cwd();
10
+
11
+ while (currentDir) {
12
+ const possibleNodeModulesPath = path.join(currentDir, 'node_modules');
13
+
14
+ if (fs.existsSync(possibleNodeModulesPath)) return possibleNodeModulesPath;
15
+
16
+ const parentDir = path.resolve(currentDir, '..');
17
+ if (parentDir === currentDir) break; // reached the root directory
18
+
19
+ currentDir = parentDir;
20
+ }
21
+
22
+ throw new Error('Unable to find node_modules directory.');
23
+ }
24
+
25
+ export type PathType = 'absent' | 'file' | 'dir' | 'link' | 'unknown';
26
+
27
+ export function pathType(path: string): PathType {
28
+ try {
29
+ const s = fs.statSync(path);
30
+ if (s.isDirectory()) return 'dir';
31
+ if (s.isFile()) return 'file';
32
+ if (s.isSymbolicLink()) return 'link';
33
+ return 'unknown';
34
+ } catch (err: any) {
35
+ if (err.code == 'ENOENT') return 'absent';
36
+ else throw err;
37
+ }
38
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { COMMANDS } from './commands';