@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.
- package/README.md +52 -0
- package/bin/run.js +7 -0
- package/dist/commands/build.d.ts +13 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/check.d.ts +11 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/dump/all.d.ts +7 -0
- package/dist/commands/dump/all.d.ts.map +1 -0
- package/dist/commands/dump/libs.d.ts +10 -0
- package/dist/commands/dump/libs.d.ts.map +1 -0
- package/dist/commands/dump/software.d.ts +7 -0
- package/dist/commands/dump/software.d.ts.map +1 -0
- package/dist/commands/dump/templates.d.ts +7 -0
- package/dist/commands/dump/templates.d.ts.map +1 -0
- package/dist/commands/dump/tests.d.ts +7 -0
- package/dist/commands/dump/tests.d.ts.map +1 -0
- package/dist/commands/index.d.ts +9 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/test.d.ts +11 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/compiler/artifactset.d.ts +22 -0
- package/dist/compiler/artifactset.d.ts.map +1 -0
- package/dist/compiler/compiler.d.ts +34 -0
- package/dist/compiler/compiler.d.ts.map +1 -0
- package/dist/compiler/main.d.ts +17 -0
- package/dist/compiler/main.d.ts.map +1 -0
- package/dist/compiler/package.d.ts +37 -0
- package/dist/compiler/package.d.ts.map +1 -0
- package/dist/compiler/source.d.ts +27 -0
- package/dist/compiler/source.d.ts.map +1 -0
- package/dist/compiler/template.d.ts +49 -0
- package/dist/compiler/template.d.ts.map +1 -0
- package/dist/compiler/test.artifacts.d.ts +32 -0
- package/dist/compiler/test.artifacts.d.ts.map +1 -0
- package/dist/compiler/util.d.ts +5 -0
- package/dist/compiler/util.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +851 -0
- package/dist/index.mjs.map +1 -0
- package/dist/shared/basecmd.d.ts +9 -0
- package/dist/shared/basecmd.d.ts.map +1 -0
- package/dist/shared/dump.d.ts +7 -0
- package/dist/shared/dump.d.ts.map +1 -0
- package/dist/shared/proc.d.ts +5 -0
- package/dist/shared/proc.d.ts.map +1 -0
- package/package.json +44 -0
- package/src/commands/build.ts +175 -0
- package/src/commands/check.ts +45 -0
- package/src/commands/dump/all.ts +17 -0
- package/src/commands/dump/libs.ts +24 -0
- package/src/commands/dump/software.ts +17 -0
- package/src/commands/dump/templates.ts +18 -0
- package/src/commands/dump/tests.ts +17 -0
- package/src/commands/index.ts +10 -0
- package/src/commands/test.ts +41 -0
- package/src/compiler/artifactset.ts +76 -0
- package/src/compiler/compiler.test.ts +48 -0
- package/src/compiler/compiler.ts +300 -0
- package/src/compiler/main.ts +363 -0
- package/src/compiler/package.ts +96 -0
- package/src/compiler/source.test.ts +28 -0
- package/src/compiler/source.ts +319 -0
- package/src/compiler/template.test.ts +54 -0
- package/src/compiler/template.ts +90 -0
- package/src/compiler/test.artifacts.ts +195 -0
- package/src/compiler/util.ts +38 -0
- package/src/index.ts +1 -0
- package/src/shared/basecmd.ts +28 -0
- package/src/shared/dump.ts +164 -0
- 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
|
+
});
|