@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.
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/compiler/artifactset.d.ts +4 -0
- package/dist/compiler/artifactset.d.ts.map +1 -1
- package/dist/compiler/compiler.d.ts +11 -9
- package/dist/compiler/compiler.d.ts.map +1 -1
- package/dist/compiler/compileroptions.d.ts +3 -3
- package/dist/compiler/compileroptions.d.ts.map +1 -1
- package/dist/compiler/main.d.ts +4 -5
- package/dist/compiler/main.d.ts.map +1 -1
- package/dist/compiler/source.d.ts +24 -4
- package/dist/compiler/source.d.ts.map +1 -1
- package/dist/compiler/template.d.ts +17 -13
- package/dist/compiler/template.d.ts.map +1 -1
- package/dist/compiler/test.artifacts.d.ts +2 -0
- package/dist/compiler/test.artifacts.d.ts.map +1 -1
- package/dist/index.js +29 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +473 -410
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -10
- package/src/commands/build.ts +31 -27
- package/src/compiler/artifactset.ts +4 -0
- package/src/compiler/compiler.test.ts +276 -17
- package/src/compiler/compiler.ts +87 -60
- package/src/compiler/compileroptions.ts +3 -3
- package/src/compiler/main.test.ts +45 -0
- package/src/compiler/main.ts +76 -36
- package/src/compiler/source.test.ts +324 -1
- package/src/compiler/source.ts +47 -42
- package/src/compiler/template.test.ts +22 -14
- package/src/compiler/template.ts +85 -38
- package/src/compiler/test.artifacts.ts +10 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseSource } from './source';
|
|
1
|
+
import { newGetSoftwareInfoRE, newGetTemplateIdRE, parseSource } from './source';
|
|
2
2
|
import { createLogger } from './util';
|
|
3
3
|
import {
|
|
4
4
|
testLocalLib1Name,
|
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
testLocalTpl3Src,
|
|
10
10
|
testLocalTpl3Name
|
|
11
11
|
} from './test.artifacts';
|
|
12
|
+
import { parseSingleSourceLine } from './source';
|
|
13
|
+
import { expect, describe, test } from 'vitest';
|
|
14
|
+
import { ConsoleLoggerAdapter } from '@milaboratories/ts-helpers';
|
|
12
15
|
|
|
13
16
|
test('test lib 1 parsing', () => {
|
|
14
17
|
const logger = createLogger('error');
|
|
@@ -47,3 +50,323 @@ test('test tpl 3 parsing', () => {
|
|
|
47
50
|
const tplSrc = parseSource(logger, 'dist', testLocalTpl3Src, testLocalTpl3Name, true);
|
|
48
51
|
expect(tplSrc.compilerOptions[0].name).toEqual('hash_override');
|
|
49
52
|
});
|
|
53
|
+
|
|
54
|
+
describe('parseSingleSourceLine', () => {
|
|
55
|
+
test.each([
|
|
56
|
+
{
|
|
57
|
+
name: 'empty line',
|
|
58
|
+
line: ' ',
|
|
59
|
+
context: {
|
|
60
|
+
isInCommentBlock: false,
|
|
61
|
+
canDetectOptions: true,
|
|
62
|
+
lineNo: 1,
|
|
63
|
+
tplDepREs: new Map()
|
|
64
|
+
},
|
|
65
|
+
localPackageName: 'test-package',
|
|
66
|
+
expected: {
|
|
67
|
+
line: ' ',
|
|
68
|
+
artifact: undefined,
|
|
69
|
+
option: undefined,
|
|
70
|
+
context: {
|
|
71
|
+
isInCommentBlock: false,
|
|
72
|
+
canDetectOptions: true,
|
|
73
|
+
lineNo: 1,
|
|
74
|
+
tplDepREs: new Map()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'single-line comment',
|
|
80
|
+
line: '// This is a comment',
|
|
81
|
+
context: {
|
|
82
|
+
isInCommentBlock: false,
|
|
83
|
+
canDetectOptions: true,
|
|
84
|
+
lineNo: 1,
|
|
85
|
+
tplDepREs: new Map()
|
|
86
|
+
},
|
|
87
|
+
localPackageName: 'test-package',
|
|
88
|
+
expected: {
|
|
89
|
+
line: '',
|
|
90
|
+
artifact: undefined,
|
|
91
|
+
option: undefined,
|
|
92
|
+
context: {
|
|
93
|
+
isInCommentBlock: false,
|
|
94
|
+
canDetectOptions: true,
|
|
95
|
+
lineNo: 1,
|
|
96
|
+
tplDepREs: new Map()
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'start of multi-line comment',
|
|
102
|
+
line: '/* Start comment',
|
|
103
|
+
context: {
|
|
104
|
+
isInCommentBlock: false,
|
|
105
|
+
canDetectOptions: true,
|
|
106
|
+
lineNo: 1,
|
|
107
|
+
tplDepREs: new Map()
|
|
108
|
+
},
|
|
109
|
+
localPackageName: 'test-package',
|
|
110
|
+
expected: {
|
|
111
|
+
line: '',
|
|
112
|
+
artifact: undefined,
|
|
113
|
+
option: undefined,
|
|
114
|
+
context: {
|
|
115
|
+
isInCommentBlock: true,
|
|
116
|
+
canDetectOptions: true,
|
|
117
|
+
lineNo: 1,
|
|
118
|
+
tplDepREs: new Map()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'line inside comment block',
|
|
124
|
+
line: 'This is inside a comment block',
|
|
125
|
+
context: {
|
|
126
|
+
isInCommentBlock: true,
|
|
127
|
+
canDetectOptions: true,
|
|
128
|
+
lineNo: 1,
|
|
129
|
+
tplDepREs: new Map()
|
|
130
|
+
},
|
|
131
|
+
localPackageName: 'test-package',
|
|
132
|
+
expected: {
|
|
133
|
+
line: '',
|
|
134
|
+
artifact: undefined,
|
|
135
|
+
option: undefined,
|
|
136
|
+
context: {
|
|
137
|
+
isInCommentBlock: true,
|
|
138
|
+
canDetectOptions: true,
|
|
139
|
+
lineNo: 1,
|
|
140
|
+
tplDepREs: new Map()
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: 'end of multi-line comment',
|
|
146
|
+
line: 'End of comment */',
|
|
147
|
+
context: {
|
|
148
|
+
isInCommentBlock: true,
|
|
149
|
+
canDetectOptions: true,
|
|
150
|
+
lineNo: 1,
|
|
151
|
+
tplDepREs: new Map()
|
|
152
|
+
},
|
|
153
|
+
localPackageName: 'test-package',
|
|
154
|
+
expected: {
|
|
155
|
+
line: '',
|
|
156
|
+
artifact: undefined,
|
|
157
|
+
option: undefined,
|
|
158
|
+
context: {
|
|
159
|
+
isInCommentBlock: false,
|
|
160
|
+
canDetectOptions: true,
|
|
161
|
+
lineNo: 1,
|
|
162
|
+
tplDepREs: new Map()
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'compiler option',
|
|
168
|
+
line: '//tengo:nocheck',
|
|
169
|
+
context: {
|
|
170
|
+
isInCommentBlock: false,
|
|
171
|
+
canDetectOptions: true,
|
|
172
|
+
lineNo: 1,
|
|
173
|
+
tplDepREs: new Map()
|
|
174
|
+
},
|
|
175
|
+
localPackageName: 'test-package',
|
|
176
|
+
expected: {
|
|
177
|
+
line: '//tengo:nocheck',
|
|
178
|
+
artifact: undefined,
|
|
179
|
+
option: { name: 'nocheck', args: [] },
|
|
180
|
+
context: {
|
|
181
|
+
isInCommentBlock: false,
|
|
182
|
+
canDetectOptions: true,
|
|
183
|
+
lineNo: 1,
|
|
184
|
+
tplDepREs: new Map()
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: 'regular code disables canDetectOptions',
|
|
190
|
+
line: 'const x = 5',
|
|
191
|
+
context: {
|
|
192
|
+
isInCommentBlock: false,
|
|
193
|
+
canDetectOptions: true,
|
|
194
|
+
lineNo: 1,
|
|
195
|
+
tplDepREs: new Map()
|
|
196
|
+
},
|
|
197
|
+
localPackageName: 'test-package',
|
|
198
|
+
expected: {
|
|
199
|
+
line: 'const x = 5',
|
|
200
|
+
artifact: undefined,
|
|
201
|
+
option: undefined,
|
|
202
|
+
context: {
|
|
203
|
+
isInCommentBlock: false,
|
|
204
|
+
canDetectOptions: false,
|
|
205
|
+
lineNo: 1,
|
|
206
|
+
tplDepREs: new Map()
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: 'malformed compiler option warning',
|
|
212
|
+
line: '// tengo:nocheck',
|
|
213
|
+
context: {
|
|
214
|
+
isInCommentBlock: false,
|
|
215
|
+
canDetectOptions: true,
|
|
216
|
+
lineNo: 1,
|
|
217
|
+
tplDepREs: new Map()
|
|
218
|
+
},
|
|
219
|
+
localPackageName: 'test-package',
|
|
220
|
+
expected: {
|
|
221
|
+
line: '// tengo:nocheck',
|
|
222
|
+
artifact: undefined,
|
|
223
|
+
option: undefined,
|
|
224
|
+
context: {
|
|
225
|
+
isInCommentBlock: false,
|
|
226
|
+
canDetectOptions: true,
|
|
227
|
+
lineNo: 1,
|
|
228
|
+
tplDepREs: new Map()
|
|
229
|
+
},
|
|
230
|
+
warning: true
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: 'regular import',
|
|
235
|
+
line: 'fmt := import("fmt")',
|
|
236
|
+
context: {
|
|
237
|
+
isInCommentBlock: false,
|
|
238
|
+
canDetectOptions: true,
|
|
239
|
+
lineNo: 1,
|
|
240
|
+
tplDepREs: new Map()
|
|
241
|
+
},
|
|
242
|
+
localPackageName: 'test-package',
|
|
243
|
+
expected: {
|
|
244
|
+
line: 'fmt := import("fmt")',
|
|
245
|
+
artifact: undefined,
|
|
246
|
+
option: undefined,
|
|
247
|
+
context: {
|
|
248
|
+
isInCommentBlock: false,
|
|
249
|
+
canDetectOptions: false,
|
|
250
|
+
lineNo: 1,
|
|
251
|
+
tplDepREs: new Map()
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: 'library import',
|
|
257
|
+
line: 'myLib := import("test-package:myLib")',
|
|
258
|
+
context: {
|
|
259
|
+
isInCommentBlock: false,
|
|
260
|
+
canDetectOptions: true,
|
|
261
|
+
lineNo: 1,
|
|
262
|
+
tplDepREs: new Map()
|
|
263
|
+
},
|
|
264
|
+
localPackageName: 'test-package',
|
|
265
|
+
expected: {
|
|
266
|
+
line: 'myLib := import("test-package:myLib")',
|
|
267
|
+
artifact: { pkg: 'test-package', id: 'myLib', type: 'library' },
|
|
268
|
+
option: undefined,
|
|
269
|
+
context: {
|
|
270
|
+
isInCommentBlock: false,
|
|
271
|
+
canDetectOptions: false,
|
|
272
|
+
lineNo: 1,
|
|
273
|
+
tplDepREs: new Map()
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: 'library import with globalize',
|
|
279
|
+
line: 'myLib := import("test-package:myLib")',
|
|
280
|
+
context: {
|
|
281
|
+
isInCommentBlock: false,
|
|
282
|
+
canDetectOptions: true,
|
|
283
|
+
lineNo: 1,
|
|
284
|
+
tplDepREs: new Map()
|
|
285
|
+
},
|
|
286
|
+
localPackageName: 'test-package',
|
|
287
|
+
globalizeImports: true,
|
|
288
|
+
expected: {
|
|
289
|
+
line: 'myLib := import("test-package:myLib")',
|
|
290
|
+
artifact: { pkg: 'test-package', id: 'myLib', type: 'library' },
|
|
291
|
+
option: undefined,
|
|
292
|
+
context: {
|
|
293
|
+
isInCommentBlock: false,
|
|
294
|
+
canDetectOptions: false,
|
|
295
|
+
lineNo: 1,
|
|
296
|
+
tplDepREs: new Map()
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
name: 'plapi import sets up template detection',
|
|
302
|
+
line: 'plapi := import("plapi")',
|
|
303
|
+
context: {
|
|
304
|
+
isInCommentBlock: false,
|
|
305
|
+
canDetectOptions: true,
|
|
306
|
+
lineNo: 1,
|
|
307
|
+
tplDepREs: new Map()
|
|
308
|
+
},
|
|
309
|
+
localPackageName: 'test-package',
|
|
310
|
+
expected: {
|
|
311
|
+
line: 'plapi := import("plapi")',
|
|
312
|
+
artifact: undefined,
|
|
313
|
+
option: undefined,
|
|
314
|
+
context: {
|
|
315
|
+
isInCommentBlock: false,
|
|
316
|
+
canDetectOptions: false,
|
|
317
|
+
lineNo: 1,
|
|
318
|
+
tplDepREs: (() => {
|
|
319
|
+
const r = new Map();
|
|
320
|
+
r.set('template', newGetTemplateIdRE('plapi'));
|
|
321
|
+
r.set('software', newGetSoftwareInfoRE('plapi'));
|
|
322
|
+
return r;
|
|
323
|
+
})(),
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: 'tengo-sdk:ll import sets up template detection',
|
|
329
|
+
line: 'll := import("@milaboratory/tengo-sdk:ll")',
|
|
330
|
+
context: {
|
|
331
|
+
isInCommentBlock: false,
|
|
332
|
+
canDetectOptions: true,
|
|
333
|
+
lineNo: 1,
|
|
334
|
+
tplDepREs: new Map()
|
|
335
|
+
},
|
|
336
|
+
localPackageName: 'test-package',
|
|
337
|
+
expected: {
|
|
338
|
+
line: 'll := import("@milaboratory/tengo-sdk:ll")',
|
|
339
|
+
artifact: {
|
|
340
|
+
id: 'll',
|
|
341
|
+
pkg: '@milaboratory/tengo-sdk',
|
|
342
|
+
type: 'library',
|
|
343
|
+
},
|
|
344
|
+
option: undefined,
|
|
345
|
+
context: {
|
|
346
|
+
isInCommentBlock: false,
|
|
347
|
+
canDetectOptions: false,
|
|
348
|
+
lineNo: 1,
|
|
349
|
+
tplDepREs: (() => {
|
|
350
|
+
const r = new Map();
|
|
351
|
+
r.set('template', newGetTemplateIdRE('ll'));
|
|
352
|
+
r.set('software', newGetSoftwareInfoRE('ll'));
|
|
353
|
+
return r;
|
|
354
|
+
})()
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
])('$name', ({ line, context, localPackageName, globalizeImports, expected }) => {
|
|
359
|
+
const result = parseSingleSourceLine(
|
|
360
|
+
new ConsoleLoggerAdapter(),
|
|
361
|
+
line,
|
|
362
|
+
context,
|
|
363
|
+
localPackageName,
|
|
364
|
+
globalizeImports,
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
expect(result.line).toBe(expected.line);
|
|
368
|
+
expect(result.artifact).toEqual(expected.artifact);
|
|
369
|
+
expect(result.option).toEqual(expected.option);
|
|
370
|
+
expect(result.context).toMatchObject(context);
|
|
371
|
+
});
|
|
372
|
+
});
|
package/src/compiler/source.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
|
-
import type winston from 'winston';
|
|
3
2
|
import {
|
|
4
3
|
type TypedArtifactName,
|
|
5
4
|
type FullArtifactName,
|
|
@@ -10,6 +9,8 @@ import {
|
|
|
10
9
|
} from './package';
|
|
11
10
|
import type { ArtifactMap } from './artifactset';
|
|
12
11
|
import { createArtifactNameSet } from './artifactset';
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
13
|
+
import type { MiLogger } from '@milaboratories/ts-helpers';
|
|
13
14
|
|
|
14
15
|
// matches any valid name in tengo. Don't forget to use '\b' when needed to limit the boundaries!
|
|
15
16
|
const namePattern = '[_a-zA-Z][_a-zA-Z0-9]*';
|
|
@@ -22,10 +23,10 @@ const functionCallRE = (moduleName: string, fnName: string) => {
|
|
|
22
23
|
);
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
const newGetTemplateIdRE = (moduleName: string) => {
|
|
26
|
+
export const newGetTemplateIdRE = (moduleName: string) => {
|
|
26
27
|
return functionCallRE(moduleName, 'getTemplateId');
|
|
27
28
|
};
|
|
28
|
-
const newGetSoftwareInfoRE = (moduleName: string) => {
|
|
29
|
+
export const newGetSoftwareInfoRE = (moduleName: string) => {
|
|
29
30
|
return functionCallRE(moduleName, 'getSoftwareInfo');
|
|
30
31
|
};
|
|
31
32
|
|
|
@@ -46,6 +47,9 @@ const inlineCommentRE = /\/\*.*?\*\//g; // .*? = non-greedy search
|
|
|
46
47
|
const singlelineCommentRE = /^\s*(\/\/)/;
|
|
47
48
|
const multilineCommentStartRE = /^\s*\/\*/;
|
|
48
49
|
const multilineCommentEndRE = /\*\//;
|
|
50
|
+
|
|
51
|
+
// import could only be an assignment in a statement,
|
|
52
|
+
// other ways could break a compilation.
|
|
49
53
|
const importRE = /\s*:=\s*import\s*\(\s*"(?<moduleName>[^"]+)"\s*\)/;
|
|
50
54
|
const importNameRE = new RegExp(
|
|
51
55
|
`\\b(?<importName>${namePattern}(\\.${namePattern})*)${importRE.source}`,
|
|
@@ -82,6 +86,8 @@ export class ArtifactSource {
|
|
|
82
86
|
public readonly compileMode: CompileMode,
|
|
83
87
|
/** Full artifact id, including package version */
|
|
84
88
|
public readonly fullName: FullArtifactName,
|
|
89
|
+
/** Hash of the source code */
|
|
90
|
+
public readonly sourceHash: string,
|
|
85
91
|
/** Normalized source code */
|
|
86
92
|
public readonly src: string,
|
|
87
93
|
/** Path to source file where artifact came from */
|
|
@@ -94,7 +100,7 @@ export class ArtifactSource {
|
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
export function parseSourceFile(
|
|
97
|
-
logger:
|
|
103
|
+
logger: MiLogger,
|
|
98
104
|
mode: CompileMode,
|
|
99
105
|
srcFile: string,
|
|
100
106
|
fullSourceName: FullArtifactName,
|
|
@@ -103,11 +109,19 @@ export function parseSourceFile(
|
|
|
103
109
|
const src = readFileSync(srcFile).toString();
|
|
104
110
|
const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);
|
|
105
111
|
|
|
106
|
-
return new ArtifactSource(
|
|
112
|
+
return new ArtifactSource(
|
|
113
|
+
mode,
|
|
114
|
+
fullSourceName,
|
|
115
|
+
getSha256(normalized),
|
|
116
|
+
normalized,
|
|
117
|
+
srcFile,
|
|
118
|
+
deps.array,
|
|
119
|
+
opts,
|
|
120
|
+
);
|
|
107
121
|
}
|
|
108
122
|
|
|
109
123
|
export function parseSource(
|
|
110
|
-
logger:
|
|
124
|
+
logger: MiLogger,
|
|
111
125
|
mode: CompileMode,
|
|
112
126
|
src: string,
|
|
113
127
|
fullSourceName: FullArtifactName,
|
|
@@ -115,11 +129,18 @@ export function parseSource(
|
|
|
115
129
|
): ArtifactSource {
|
|
116
130
|
const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);
|
|
117
131
|
|
|
118
|
-
return new ArtifactSource(mode, fullSourceName, normalized, '', deps.array, opts);
|
|
132
|
+
return new ArtifactSource(mode, fullSourceName, getSha256(normalized), normalized, '', deps.array, opts);
|
|
119
133
|
}
|
|
120
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Reads src
|
|
137
|
+
* returns normalized source code,
|
|
138
|
+
* gets dependencies from imports,
|
|
139
|
+
* maps imports to global names if globalizeImports is true,
|
|
140
|
+
* and collects compiler options like hashOverride.
|
|
141
|
+
*/
|
|
121
142
|
function parseSourceData(
|
|
122
|
-
logger:
|
|
143
|
+
logger: MiLogger,
|
|
123
144
|
src: string,
|
|
124
145
|
fullSourceName: FullArtifactName,
|
|
125
146
|
globalizeImports: boolean,
|
|
@@ -150,21 +171,21 @@ function parseSourceData(
|
|
|
150
171
|
parserContext.lineNo++;
|
|
151
172
|
|
|
152
173
|
try {
|
|
153
|
-
const
|
|
174
|
+
const { line: processedLine, context: newContext, artifact, option } = parseSingleSourceLine(
|
|
154
175
|
logger,
|
|
155
176
|
line,
|
|
156
177
|
parserContext,
|
|
157
178
|
fullSourceName.pkg,
|
|
158
179
|
globalizeImports,
|
|
159
180
|
);
|
|
160
|
-
processedLines.push(
|
|
161
|
-
parserContext =
|
|
181
|
+
processedLines.push(processedLine);
|
|
182
|
+
parserContext = newContext;
|
|
162
183
|
|
|
163
|
-
if (
|
|
164
|
-
dependencySet.add(
|
|
184
|
+
if (artifact) {
|
|
185
|
+
dependencySet.add(artifact);
|
|
165
186
|
}
|
|
166
|
-
if (
|
|
167
|
-
optionList.push(
|
|
187
|
+
if (option) {
|
|
188
|
+
optionList.push(option);
|
|
168
189
|
}
|
|
169
190
|
} catch (error: unknown) {
|
|
170
191
|
const err = error as Error;
|
|
@@ -186,8 +207,8 @@ interface sourceParserContext {
|
|
|
186
207
|
lineNo: number;
|
|
187
208
|
}
|
|
188
209
|
|
|
189
|
-
function parseSingleSourceLine(
|
|
190
|
-
logger:
|
|
210
|
+
export function parseSingleSourceLine(
|
|
211
|
+
logger: MiLogger,
|
|
191
212
|
line: string,
|
|
192
213
|
context: sourceParserContext,
|
|
193
214
|
localPackageName: string,
|
|
@@ -242,6 +263,7 @@ function parseSingleSourceLine(
|
|
|
242
263
|
return { line, context, artifact: undefined, option: undefined };
|
|
243
264
|
}
|
|
244
265
|
|
|
266
|
+
// options could be only at the top of the file.
|
|
245
267
|
context.canDetectOptions = false;
|
|
246
268
|
|
|
247
269
|
const importInstruction = importRE.exec(line);
|
|
@@ -249,6 +271,9 @@ function parseSingleSourceLine(
|
|
|
249
271
|
if (importInstruction) {
|
|
250
272
|
const iInfo = parseImport(line);
|
|
251
273
|
|
|
274
|
+
// If we have plapi, ll or assets, then try to parse
|
|
275
|
+
// getTemplateId, getSoftwareInfo, getSoftware and getAsset calls.
|
|
276
|
+
|
|
252
277
|
if (iInfo.module === 'plapi') {
|
|
253
278
|
if (!context.tplDepREs.has(iInfo.module)) {
|
|
254
279
|
context.tplDepREs.set(iInfo.module, [
|
|
@@ -304,7 +329,7 @@ function parseSingleSourceLine(
|
|
|
304
329
|
}
|
|
305
330
|
|
|
306
331
|
if (context.tplDepREs.size > 0) {
|
|
307
|
-
for (const [
|
|
332
|
+
for (const [_, artifactRE] of context.tplDepREs) {
|
|
308
333
|
for (const [artifactType, re] of artifactRE) {
|
|
309
334
|
const match = re.exec(line);
|
|
310
335
|
if (!match || !match.groups) {
|
|
@@ -352,8 +377,8 @@ function parseImport(line: string): ImportInfo {
|
|
|
352
377
|
}
|
|
353
378
|
|
|
354
379
|
return {
|
|
355
|
-
module: moduleName,
|
|
356
|
-
alias: importName,
|
|
380
|
+
module: moduleName, // the module name without wrapping quotes: import("<module>")
|
|
381
|
+
alias: importName, // the name of variable that keeps imported module: <alias> := import("<module>")
|
|
357
382
|
};
|
|
358
383
|
}
|
|
359
384
|
|
|
@@ -383,26 +408,6 @@ function parseArtifactName(
|
|
|
383
408
|
return { type: aType, pkg: pkgName ?? localPackageName, id: depID };
|
|
384
409
|
}
|
|
385
410
|
|
|
386
|
-
function
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if (!templateName) {
|
|
390
|
-
throw Error(`failed to parse 'getTemplateId' statement`);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const depInfo = dependencyRE.exec(templateName);
|
|
394
|
-
if (!depInfo || !depInfo.groups) {
|
|
395
|
-
throw Error(
|
|
396
|
-
`failed to parse dependency name inside 'getTemplateId' statement. The dependency name should have format '<package>:<templateName>'`,
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
const { pkgName, depID } = depInfo.groups;
|
|
401
|
-
if (!pkgName || !depID) {
|
|
402
|
-
throw Error(
|
|
403
|
-
`failed to parse dependency name inside 'getTemplateId' statement. The dependency name should have format '<package>:<templateName>'`,
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return { type: 'template', pkg: pkgName ?? localPackageName, id: depID };
|
|
411
|
+
export function getSha256(source: string): string {
|
|
412
|
+
return createHash('sha256').update(source).digest('hex');
|
|
408
413
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Template } from './template';
|
|
1
|
+
import { newTemplateFromContent, newTemplateFromData, Template } from './template';
|
|
2
2
|
import { formatArtefactNameAndVersion, FullArtifactName } from './package';
|
|
3
|
+
import { test, expect } from 'vitest';
|
|
3
4
|
|
|
4
5
|
test('template serialization / deserialization', () => {
|
|
5
6
|
const name: FullArtifactName = {
|
|
@@ -8,46 +9,53 @@ test('template serialization / deserialization', () => {
|
|
|
8
9
|
id: 'the-template',
|
|
9
10
|
version: '1.2.3'
|
|
10
11
|
};
|
|
11
|
-
const template1 =
|
|
12
|
+
const template1 = newTemplateFromData(
|
|
13
|
+
'dist',
|
|
14
|
+
name,
|
|
12
15
|
{
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
type: 'pl.tengo-template.v3',
|
|
17
|
+
hashToSource: {
|
|
18
|
+
"asdasd": "src1...",
|
|
19
|
+
"asdasd2": "src2...",
|
|
20
|
+
"asdasd3": "src3...",
|
|
21
|
+
},
|
|
22
|
+
template: {
|
|
23
|
+
sourceHash: "asdasd3",
|
|
15
24
|
...formatArtefactNameAndVersion(name),
|
|
16
25
|
libs: {
|
|
17
|
-
'
|
|
26
|
+
'asdasd': {
|
|
18
27
|
name: '@milaboratory/some-package:the-library',
|
|
19
28
|
version: '1.2.3',
|
|
20
|
-
|
|
29
|
+
sourceHash: 'asdasd'
|
|
21
30
|
}
|
|
22
31
|
},
|
|
23
32
|
templates: {
|
|
24
|
-
'
|
|
25
|
-
type: 'pl.tengo-template.v2',
|
|
33
|
+
'asdasd2': {
|
|
26
34
|
name: '@milaboratory/some-package:the-template-1',
|
|
27
35
|
version: '1.2.3',
|
|
28
36
|
libs: {
|
|
29
37
|
'@milaboratory/some-package:the-library:1.2.4': {
|
|
30
38
|
name: '@milaboratory/some-package:the-library',
|
|
31
39
|
version: '1.2.4',
|
|
32
|
-
|
|
40
|
+
sourceHash: 'asdasd2'
|
|
33
41
|
}
|
|
34
42
|
},
|
|
35
43
|
templates: {},
|
|
36
44
|
software: {},
|
|
37
45
|
assets: {},
|
|
38
|
-
|
|
46
|
+
sourceHash: 'src 1...'
|
|
39
47
|
}
|
|
40
48
|
},
|
|
41
49
|
software: {},
|
|
42
50
|
assets: {},
|
|
43
|
-
|
|
44
|
-
}
|
|
51
|
+
},
|
|
45
52
|
}
|
|
46
53
|
);
|
|
47
54
|
|
|
48
|
-
const template2 =
|
|
55
|
+
const template2 = newTemplateFromContent(
|
|
56
|
+
'dist',
|
|
49
57
|
{ type: 'template', pkg: '@milaboratory/some-package', id: 'the-template', version: '1.2.3' },
|
|
50
|
-
|
|
58
|
+
template1.content,
|
|
51
59
|
);
|
|
52
60
|
|
|
53
61
|
console.log('Size: raw', JSON.stringify(template1.data).length, 'compressed', template1.content.byteLength);
|