@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
package/src/compiler/compiler.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ArtifactSource } from './source';
|
|
2
|
-
import {
|
|
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 {
|
|
18
|
+
import type { CompiledTemplateV3 } from '@milaboratories/pl-model-backend';
|
|
18
19
|
|
|
20
|
+
/** A compilation result. */
|
|
19
21
|
export interface TemplatesAndLibs {
|
|
20
|
-
templates:
|
|
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<
|
|
32
|
+
private readonly templates = new ArtifactStore<TemplateWithSource>((tpl) => tpl.fullName);
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
private readonly compileMode: CompileMode,
|
|
36
|
+
) { }
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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):
|
|
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:
|
|
110
|
-
type: 'pl.tengo-template.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
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:
|
|
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():
|
|
245
|
+
allTemplates(): TemplateWithSource[] {
|
|
215
246
|
return this.templates.array(this.compileMode);
|
|
216
247
|
}
|
|
217
248
|
|
|
218
|
-
getTemplate(name: TypedArtifactName):
|
|
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):
|
|
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 |
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
389
|
+
return result;
|
|
363
390
|
}
|
|
364
391
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
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:
|
|
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:
|
|
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
|
+
});
|
package/src/compiler/main.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 ${
|
|
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(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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.
|
|
490
|
+
fs.writeFileSync(file, serializeTemplate(tpl.data));
|
|
451
491
|
}
|
|
452
492
|
}
|
|
453
493
|
|