@platforma-sdk/tengo-builder 2.1.14 → 2.1.15
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/bin/run.js +6 -0
- package/dist/commands/build.cjs +172 -0
- package/dist/commands/build.cjs.map +1 -0
- package/dist/commands/build.d.ts +4 -6
- package/dist/commands/build.js +149 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/check.cjs +39 -0
- package/dist/commands/check.cjs.map +1 -0
- package/dist/commands/check.d.ts +1 -3
- package/dist/commands/check.js +37 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/dump/all.cjs +20 -0
- package/dist/commands/dump/all.cjs.map +1 -0
- package/dist/commands/dump/all.d.ts +0 -1
- package/dist/commands/dump/all.js +18 -0
- package/dist/commands/dump/all.js.map +1 -0
- package/dist/commands/dump/assets.cjs +20 -0
- package/dist/commands/dump/assets.cjs.map +1 -0
- package/dist/commands/dump/assets.d.ts +0 -1
- package/dist/commands/dump/assets.js +18 -0
- package/dist/commands/dump/assets.js.map +1 -0
- package/dist/commands/dump/libs.cjs +24 -0
- package/dist/commands/dump/libs.cjs.map +1 -0
- package/dist/commands/dump/libs.d.ts +1 -3
- package/dist/commands/dump/libs.js +22 -0
- package/dist/commands/dump/libs.js.map +1 -0
- package/dist/commands/dump/software.cjs +20 -0
- package/dist/commands/dump/software.cjs.map +1 -0
- package/dist/commands/dump/software.d.ts +0 -1
- package/dist/commands/dump/software.js +18 -0
- package/dist/commands/dump/software.js.map +1 -0
- package/dist/commands/dump/templates.cjs +20 -0
- package/dist/commands/dump/templates.cjs.map +1 -0
- package/dist/commands/dump/templates.d.ts +0 -1
- package/dist/commands/dump/templates.js +18 -0
- package/dist/commands/dump/templates.js.map +1 -0
- package/dist/commands/dump/tests.cjs +20 -0
- package/dist/commands/dump/tests.cjs.map +1 -0
- package/dist/commands/dump/tests.d.ts +0 -1
- package/dist/commands/dump/tests.js +18 -0
- package/dist/commands/dump/tests.js.map +1 -0
- package/dist/commands/test.cjs +36 -0
- package/dist/commands/test.cjs.map +1 -0
- package/dist/commands/test.d.ts +1 -3
- package/dist/commands/test.js +34 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/compiler/artifactset.cjs +75 -0
- package/dist/compiler/artifactset.cjs.map +1 -0
- package/dist/compiler/artifactset.d.ts +0 -1
- package/dist/compiler/artifactset.js +71 -0
- package/dist/compiler/artifactset.js.map +1 -0
- package/dist/compiler/compiler.cjs +314 -0
- package/dist/compiler/compiler.cjs.map +1 -0
- package/dist/compiler/compiler.d.ts +0 -1
- package/dist/compiler/compiler.js +312 -0
- package/dist/compiler/compiler.js.map +1 -0
- package/dist/compiler/compileroptions.cjs +45 -0
- package/dist/compiler/compileroptions.cjs.map +1 -0
- package/dist/compiler/compileroptions.d.ts +0 -1
- package/dist/compiler/compileroptions.js +41 -0
- package/dist/compiler/compileroptions.js.map +1 -0
- package/dist/compiler/main.cjs +387 -0
- package/dist/compiler/main.cjs.map +1 -0
- package/dist/compiler/main.d.ts +0 -1
- package/dist/compiler/main.js +359 -0
- package/dist/compiler/main.js.map +1 -0
- package/dist/compiler/package.cjs +65 -0
- package/dist/compiler/package.cjs.map +1 -0
- package/dist/compiler/package.d.ts +0 -1
- package/dist/compiler/package.js +55 -0
- package/dist/compiler/package.js.map +1 -0
- package/dist/compiler/source.cjs +292 -0
- package/dist/compiler/source.cjs.map +1 -0
- package/dist/compiler/source.d.ts +0 -1
- package/dist/compiler/source.js +285 -0
- package/dist/compiler/source.js.map +1 -0
- package/dist/compiler/template.cjs +48 -0
- package/dist/compiler/template.cjs.map +1 -0
- package/dist/compiler/template.d.ts +0 -1
- package/dist/compiler/template.js +44 -0
- package/dist/compiler/template.js.map +1 -0
- package/dist/compiler/test.artifacts.d.ts +0 -1
- package/dist/compiler/util.cjs +75 -0
- package/dist/compiler/util.cjs.map +1 -0
- package/dist/compiler/util.d.ts +0 -1
- package/dist/compiler/util.js +50 -0
- package/dist/compiler/util.js.map +1 -0
- package/dist/index.cjs +28 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +23 -41
- package/dist/index.js.map +1 -1
- package/dist/shared/basecmd.cjs +31 -0
- package/dist/shared/basecmd.cjs.map +1 -0
- package/dist/shared/basecmd.d.ts +4 -6
- package/dist/shared/basecmd.js +28 -0
- package/dist/shared/basecmd.js.map +1 -0
- package/dist/shared/dump.cjs +117 -0
- package/dist/shared/dump.cjs.map +1 -0
- package/dist/shared/dump.d.ts +0 -1
- package/dist/shared/dump.js +110 -0
- package/dist/shared/dump.js.map +1 -0
- package/dist/shared/proc.cjs +26 -0
- package/dist/shared/proc.cjs.map +1 -0
- package/dist/shared/proc.d.ts +0 -1
- package/dist/shared/proc.js +23 -0
- package/dist/shared/proc.js.map +1 -0
- package/package.json +13 -10
- package/dist/commands/build.d.ts.map +0 -1
- package/dist/commands/check.d.ts.map +0 -1
- package/dist/commands/dump/all.d.ts.map +0 -1
- package/dist/commands/dump/assets.d.ts.map +0 -1
- package/dist/commands/dump/libs.d.ts.map +0 -1
- package/dist/commands/dump/software.d.ts.map +0 -1
- package/dist/commands/dump/templates.d.ts.map +0 -1
- package/dist/commands/dump/tests.d.ts.map +0 -1
- package/dist/commands/test.d.ts.map +0 -1
- package/dist/compiler/artifactset.d.ts.map +0 -1
- package/dist/compiler/compiler.d.ts.map +0 -1
- package/dist/compiler/compileroptions.d.ts.map +0 -1
- package/dist/compiler/main.d.ts.map +0 -1
- package/dist/compiler/package.d.ts.map +0 -1
- package/dist/compiler/source.d.ts.map +0 -1
- package/dist/compiler/template.d.ts.map +0 -1
- package/dist/compiler/test.artifacts.d.ts.map +0 -1
- package/dist/compiler/util.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.mjs +0 -1198
- package/dist/index.mjs.map +0 -1
- package/dist/shared/basecmd.d.ts.map +0 -1
- package/dist/shared/dump.d.ts.map +0 -1
- package/dist/shared/proc.d.ts.map +0 -1
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('node:fs');
|
|
4
|
+
var _package = require('./package.cjs');
|
|
5
|
+
var artifactset = require('./artifactset.cjs');
|
|
6
|
+
var node_crypto = require('node:crypto');
|
|
7
|
+
|
|
8
|
+
// matches any valid name in tengo. Don't forget to use '\b' when needed to limit the boundaries!
|
|
9
|
+
const namePattern = '[_a-zA-Z][_a-zA-Z0-9]*';
|
|
10
|
+
const functionCallRE = (moduleName, fnName) => {
|
|
11
|
+
return new RegExp(`\\b${moduleName}\\.(?<fnCall>(?<fnName>`
|
|
12
|
+
+ fnName
|
|
13
|
+
+ `)\\s*\\(\\s*"(?<templateName>[^"]+)"\\s*\\))`);
|
|
14
|
+
};
|
|
15
|
+
const newGetTemplateIdRE = (moduleName) => {
|
|
16
|
+
return functionCallRE(moduleName, 'getTemplateId');
|
|
17
|
+
};
|
|
18
|
+
const newGetSoftwareInfoRE = (moduleName) => {
|
|
19
|
+
return functionCallRE(moduleName, 'getSoftwareInfo');
|
|
20
|
+
};
|
|
21
|
+
const newImportTemplateRE = (moduleName) => {
|
|
22
|
+
return functionCallRE(moduleName, 'importTemplate');
|
|
23
|
+
};
|
|
24
|
+
const newImportSoftwareRE = (moduleName) => {
|
|
25
|
+
return functionCallRE(moduleName, 'importSoftware');
|
|
26
|
+
};
|
|
27
|
+
const newImportAssetRE = (moduleName) => {
|
|
28
|
+
return functionCallRE(moduleName, 'importAsset');
|
|
29
|
+
};
|
|
30
|
+
const emptyLineRE = /^\s*$/;
|
|
31
|
+
const compilerOptionRE = /^\/\/tengo:[\w]/;
|
|
32
|
+
const wrongCompilerOptionRE = /^\s*\/\/\s*tengo:\s*./;
|
|
33
|
+
const inlineCommentRE = /\/\*.*?\*\//g; // .*? = non-greedy search
|
|
34
|
+
const singlelineCommentRE = /^\s*(\/\/)/;
|
|
35
|
+
const multilineCommentStartRE = /^\s*\/\*/;
|
|
36
|
+
const multilineCommentEndRE = /\*\//;
|
|
37
|
+
// import could only be an assignment in a statement,
|
|
38
|
+
// other ways could break a compilation.
|
|
39
|
+
const importRE = /\s*:=\s*import\s*\(\s*"(?<moduleName>[^"]+)"\s*\)/;
|
|
40
|
+
const importNameRE = new RegExp(`\\b(?<importName>${namePattern}(\\.${namePattern})*)${importRE.source}`);
|
|
41
|
+
const dependencyRE = /(?<pkgName>[^"]+)?:(?<depID>[^"]+)/; // use it to parse <moduleName> from importPattern or <templateName> from getTemplateID
|
|
42
|
+
/**
|
|
43
|
+
* Parse compiler option string representation
|
|
44
|
+
* Compiler option line is a comment starting with '//tengo:', say
|
|
45
|
+
* //tengo:hash_override tralala
|
|
46
|
+
*
|
|
47
|
+
* The common compiler option syntax is:
|
|
48
|
+
* //tengo:<option name> [<option arg1> [<option arg 2> [...]]]
|
|
49
|
+
*/
|
|
50
|
+
const parseComplierOption = (opt) => {
|
|
51
|
+
const parts = opt.split(' ');
|
|
52
|
+
const namePart = parts[0].split(':');
|
|
53
|
+
if (namePart.length != 2) {
|
|
54
|
+
throw new Error('compiler option format is wrong: expect to have option name after \'tengo:\' prefix, like \'tengo:MyOption\'');
|
|
55
|
+
}
|
|
56
|
+
const optName = namePart[1];
|
|
57
|
+
return {
|
|
58
|
+
name: optName,
|
|
59
|
+
args: parts.slice(1),
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
class ArtifactSource {
|
|
63
|
+
compileMode;
|
|
64
|
+
fullName;
|
|
65
|
+
sourceHash;
|
|
66
|
+
src;
|
|
67
|
+
srcName;
|
|
68
|
+
dependencies;
|
|
69
|
+
compilerOptions;
|
|
70
|
+
constructor(
|
|
71
|
+
/** The mode this artifact was built (dev or dist) */
|
|
72
|
+
compileMode,
|
|
73
|
+
/** Full artifact id, including package version */
|
|
74
|
+
fullName,
|
|
75
|
+
/** Hash of the source code */
|
|
76
|
+
sourceHash,
|
|
77
|
+
/** Normalized source code */
|
|
78
|
+
src,
|
|
79
|
+
/** Path to source file where artifact came from */
|
|
80
|
+
srcName,
|
|
81
|
+
/** List of dependencies */
|
|
82
|
+
dependencies,
|
|
83
|
+
/** Additional compiler options detected in source code */
|
|
84
|
+
compilerOptions) {
|
|
85
|
+
this.compileMode = compileMode;
|
|
86
|
+
this.fullName = fullName;
|
|
87
|
+
this.sourceHash = sourceHash;
|
|
88
|
+
this.src = src;
|
|
89
|
+
this.srcName = srcName;
|
|
90
|
+
this.dependencies = dependencies;
|
|
91
|
+
this.compilerOptions = compilerOptions;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function parseSourceFile(logger, mode, srcFile, fullSourceName, normalize) {
|
|
95
|
+
const src = fs.readFileSync(srcFile).toString();
|
|
96
|
+
const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);
|
|
97
|
+
return new ArtifactSource(mode, fullSourceName, getSha256(normalized), normalized, srcFile, deps.array, opts);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reads src
|
|
101
|
+
* returns normalized source code,
|
|
102
|
+
* gets dependencies from imports,
|
|
103
|
+
* maps imports to global names if globalizeImports is true,
|
|
104
|
+
* and collects compiler options like hashOverride.
|
|
105
|
+
*/
|
|
106
|
+
function parseSourceData(logger, src, fullSourceName, globalizeImports) {
|
|
107
|
+
const dependencySet = artifactset.createArtifactNameSet();
|
|
108
|
+
const optionList = [];
|
|
109
|
+
// iterating over lines
|
|
110
|
+
const lines = src.split('\n');
|
|
111
|
+
// processedLines keep all the original lines from <src>.
|
|
112
|
+
// If <globalizeImport>==true, the parser modifies 'import' and 'getTemplateId' lines
|
|
113
|
+
// with Platforma Tengo lib and template usages, resolving local names (":<item>") to
|
|
114
|
+
// global ("@milaboratory/pkg:<item>")
|
|
115
|
+
const processedLines = [];
|
|
116
|
+
let parserContext = {
|
|
117
|
+
isInCommentBlock: false,
|
|
118
|
+
canDetectOptions: true,
|
|
119
|
+
tplDepREs: new Map(),
|
|
120
|
+
lineNo: 0,
|
|
121
|
+
};
|
|
122
|
+
for (const line of lines) {
|
|
123
|
+
parserContext.lineNo++;
|
|
124
|
+
try {
|
|
125
|
+
const { line: processedLine, context: newContext, artifact, option } = parseSingleSourceLine(logger, line, parserContext, fullSourceName.pkg, globalizeImports);
|
|
126
|
+
processedLines.push(processedLine);
|
|
127
|
+
parserContext = newContext;
|
|
128
|
+
if (artifact) {
|
|
129
|
+
dependencySet.add(artifact);
|
|
130
|
+
}
|
|
131
|
+
if (option) {
|
|
132
|
+
optionList.push(option);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const err = error;
|
|
137
|
+
throw new Error(`[line ${parserContext.lineNo} in ${_package.fullNameToString(fullSourceName)}]: ${err.message}\n\t${line}`, { cause: err });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
normalized: processedLines.join('\n'),
|
|
142
|
+
deps: dependencySet,
|
|
143
|
+
opts: optionList,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function parseSingleSourceLine(logger, line, context, localPackageName, globalizeImports) {
|
|
147
|
+
// preprocess line and remove inline comments
|
|
148
|
+
line = line.replaceAll(inlineCommentRE, '');
|
|
149
|
+
if (context.isInCommentBlock) {
|
|
150
|
+
if (multilineCommentEndRE.exec(line)) {
|
|
151
|
+
context.isInCommentBlock = false;
|
|
152
|
+
}
|
|
153
|
+
return { line: '', context, artifact: undefined, option: undefined };
|
|
154
|
+
}
|
|
155
|
+
if (compilerOptionRE.exec(line)) {
|
|
156
|
+
if (!context.canDetectOptions) {
|
|
157
|
+
logger.error(`[line ${context.lineNo}]: compiler option '//tengo:' was detected, but it cannot be applied as compiler options can be set only at the file header, before any code line'`);
|
|
158
|
+
throw new Error('tengo compiler options (\'//tengo:\' comments) can be set only in file header');
|
|
159
|
+
}
|
|
160
|
+
return { line, context, artifact: undefined, option: parseComplierOption(line) };
|
|
161
|
+
}
|
|
162
|
+
if (wrongCompilerOptionRE.exec(line) && context.canDetectOptions) {
|
|
163
|
+
logger.warn(`[line ${context.lineNo}]: text simillar to compiler option ('//tengo:...') was detected, but it has wrong format. Leave it as is, if you did not mean to use a line as compiler option. Or format it to '//tengo:<option>' otherwise (no spaces between '//' and 'tengo', no spaces between ':' and option name)`);
|
|
164
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
165
|
+
}
|
|
166
|
+
if (singlelineCommentRE.test(line)) {
|
|
167
|
+
return { line: '', context, artifact: undefined, option: undefined };
|
|
168
|
+
}
|
|
169
|
+
if (multilineCommentStartRE.exec(line)) {
|
|
170
|
+
context.isInCommentBlock = true;
|
|
171
|
+
return { line: '', context, artifact: undefined, option: undefined };
|
|
172
|
+
}
|
|
173
|
+
if (line.includes('/*')) {
|
|
174
|
+
throw new Error('malformed multiline comment');
|
|
175
|
+
}
|
|
176
|
+
if (emptyLineRE.exec(line)) {
|
|
177
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
178
|
+
}
|
|
179
|
+
// options could be only at the top of the file.
|
|
180
|
+
context.canDetectOptions = false;
|
|
181
|
+
const importInstruction = importRE.exec(line);
|
|
182
|
+
if (importInstruction) {
|
|
183
|
+
const iInfo = parseImport(line);
|
|
184
|
+
// If we have plapi, ll or assets, then try to parse
|
|
185
|
+
// getTemplateId, getSoftwareInfo, getSoftware and getAsset calls.
|
|
186
|
+
if (iInfo.module === 'plapi') {
|
|
187
|
+
if (!context.tplDepREs.has(iInfo.module)) {
|
|
188
|
+
context.tplDepREs.set(iInfo.module, [
|
|
189
|
+
['template', newGetTemplateIdRE(iInfo.alias)],
|
|
190
|
+
['software', newGetSoftwareInfoRE(iInfo.alias)],
|
|
191
|
+
]);
|
|
192
|
+
}
|
|
193
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
194
|
+
}
|
|
195
|
+
if (iInfo.module === '@milaboratory/tengo-sdk:ll'
|
|
196
|
+
|| iInfo.module === '@platforma-sdk/workflow-tengo:ll'
|
|
197
|
+
|| ((localPackageName === '@milaboratory/tengo-sdk'
|
|
198
|
+
|| localPackageName === '@platforma-sdk/workflow-tengo')
|
|
199
|
+
&& iInfo.module === ':ll')) {
|
|
200
|
+
if (!context.tplDepREs.has(iInfo.module)) {
|
|
201
|
+
context.tplDepREs.set(iInfo.module, [
|
|
202
|
+
['template', newImportTemplateRE(iInfo.alias)],
|
|
203
|
+
['software', newImportSoftwareRE(iInfo.alias)],
|
|
204
|
+
]);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (iInfo.module === '@milaboratory/tengo-sdk:assets'
|
|
208
|
+
|| iInfo.module === '@platforma-sdk/workflow-tengo:assets'
|
|
209
|
+
|| ((localPackageName === '@milaboratory/tengo-sdk'
|
|
210
|
+
|| localPackageName === '@platforma-sdk/workflow-tengo')
|
|
211
|
+
&& iInfo.module === ':assets')) {
|
|
212
|
+
if (!context.tplDepREs.has(iInfo.module)) {
|
|
213
|
+
context.tplDepREs.set(iInfo.module, [
|
|
214
|
+
['template', newImportTemplateRE(iInfo.alias)],
|
|
215
|
+
['software', newImportSoftwareRE(iInfo.alias)],
|
|
216
|
+
['asset', newImportAssetRE(iInfo.alias)],
|
|
217
|
+
]);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const artifact = parseArtifactName(iInfo.module, 'library', localPackageName);
|
|
221
|
+
if (!artifact) {
|
|
222
|
+
// not a Platforma Tengo library import
|
|
223
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
224
|
+
}
|
|
225
|
+
{
|
|
226
|
+
line = line.replace(importInstruction[0], ` := import("${artifact.pkg}:${artifact.id}")`);
|
|
227
|
+
}
|
|
228
|
+
return { line, context, artifact, option: undefined };
|
|
229
|
+
}
|
|
230
|
+
if (context.tplDepREs.size > 0) {
|
|
231
|
+
for (const [_, artifactRE] of context.tplDepREs) {
|
|
232
|
+
for (const [artifactType, re] of artifactRE) {
|
|
233
|
+
const match = re.exec(line);
|
|
234
|
+
if (!match || !match.groups) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const { fnCall, templateName, fnName } = match.groups;
|
|
238
|
+
if (!fnCall || !templateName || !fnName) {
|
|
239
|
+
throw Error(`failed to parse template import statement`);
|
|
240
|
+
}
|
|
241
|
+
const artifact = parseArtifactName(templateName, artifactType, localPackageName);
|
|
242
|
+
if (!artifact) {
|
|
243
|
+
throw Error(`failed to parse artifact name in ${fnName} import statement`);
|
|
244
|
+
}
|
|
245
|
+
{
|
|
246
|
+
line = line.replace(fnCall, `${fnName}("${artifact.pkg}:${artifact.id}")`);
|
|
247
|
+
}
|
|
248
|
+
return { line, context, artifact, option: undefined };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
253
|
+
}
|
|
254
|
+
function parseImport(line) {
|
|
255
|
+
const match = importNameRE.exec(line);
|
|
256
|
+
if (!match || !match.groups) {
|
|
257
|
+
throw Error(`failed to parse 'import' statement`);
|
|
258
|
+
}
|
|
259
|
+
const { importName, moduleName } = match.groups;
|
|
260
|
+
if (!importName || !moduleName) {
|
|
261
|
+
throw Error(`failed to parse 'import' statement`);
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
module: moduleName, // the module name without wrapping quotes: import("<module>")
|
|
265
|
+
alias: importName, // the name of variable that keeps imported module: <alias> := import("<module>")
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function parseArtifactName(moduleName, aType, localPackageName) {
|
|
269
|
+
const depInfo = dependencyRE.exec(moduleName);
|
|
270
|
+
if (!depInfo) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (!depInfo.groups) {
|
|
274
|
+
throw Error(`failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`);
|
|
275
|
+
}
|
|
276
|
+
const { pkgName, depID } = depInfo.groups;
|
|
277
|
+
if (!depID) {
|
|
278
|
+
throw Error(`failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`);
|
|
279
|
+
}
|
|
280
|
+
return { type: aType, pkg: pkgName ?? localPackageName, id: depID };
|
|
281
|
+
}
|
|
282
|
+
function getSha256(source) {
|
|
283
|
+
return node_crypto.createHash('sha256').update(source).digest('hex');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
exports.ArtifactSource = ArtifactSource;
|
|
287
|
+
exports.getSha256 = getSha256;
|
|
288
|
+
exports.newGetSoftwareInfoRE = newGetSoftwareInfoRE;
|
|
289
|
+
exports.newGetTemplateIdRE = newGetTemplateIdRE;
|
|
290
|
+
exports.parseSingleSourceLine = parseSingleSourceLine;
|
|
291
|
+
exports.parseSourceFile = parseSourceFile;
|
|
292
|
+
//# sourceMappingURL=source.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.cjs","sources":["../../src/compiler/source.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport {\n type TypedArtifactName,\n type FullArtifactName,\n type ArtifactType,\n type CompileMode,\n type CompilerOption,\n fullNameToString,\n} from './package';\nimport type { ArtifactMap } from './artifactset';\nimport { createArtifactNameSet } from './artifactset';\nimport { createHash } from 'node:crypto';\nimport type { MiLogger } from '@milaboratories/ts-helpers';\n\n// matches any valid name in tengo. Don't forget to use '\\b' when needed to limit the boundaries!\nconst namePattern = '[_a-zA-Z][_a-zA-Z0-9]*';\n\nconst functionCallRE = (moduleName: string, fnName: string) => {\n return new RegExp(\n `\\\\b${moduleName}\\\\.(?<fnCall>(?<fnName>`\n + fnName\n + `)\\\\s*\\\\(\\\\s*\"(?<templateName>[^\"]+)\"\\\\s*\\\\))`,\n );\n};\n\nexport const newGetTemplateIdRE = (moduleName: string) => {\n return functionCallRE(moduleName, 'getTemplateId');\n};\nexport const newGetSoftwareInfoRE = (moduleName: string) => {\n return functionCallRE(moduleName, 'getSoftwareInfo');\n};\n\nconst newImportTemplateRE = (moduleName: string) => {\n return functionCallRE(moduleName, 'importTemplate');\n};\nconst newImportSoftwareRE = (moduleName: string) => {\n return functionCallRE(moduleName, 'importSoftware');\n};\nconst newImportAssetRE = (moduleName: string) => {\n return functionCallRE(moduleName, 'importAsset');\n};\n\nconst emptyLineRE = /^\\s*$/;\nconst compilerOptionRE = /^\\/\\/tengo:[\\w]/;\nconst wrongCompilerOptionRE = /^\\s*\\/\\/\\s*tengo:\\s*./;\nconst inlineCommentRE = /\\/\\*.*?\\*\\//g; // .*? = non-greedy search\nconst singlelineCommentRE = /^\\s*(\\/\\/)/;\nconst multilineCommentStartRE = /^\\s*\\/\\*/;\nconst multilineCommentEndRE = /\\*\\//;\n\n// import could only be an assignment in a statement,\n// other ways could break a compilation.\nconst importRE = /\\s*:=\\s*import\\s*\\(\\s*\"(?<moduleName>[^\"]+)\"\\s*\\)/;\nconst importNameRE = new RegExp(\n `\\\\b(?<importName>${namePattern}(\\\\.${namePattern})*)${importRE.source}`,\n);\nconst dependencyRE = /(?<pkgName>[^\"]+)?:(?<depID>[^\"]+)/; // use it to parse <moduleName> from importPattern or <templateName> from getTemplateID\n\n/**\n * Parse compiler option string representation\n * Compiler option line is a comment starting with '//tengo:', say\n * //tengo:hash_override tralala\n *\n * The common compiler option syntax is:\n * //tengo:<option name> [<option arg1> [<option arg 2> [...]]]\n */\nconst parseComplierOption = (opt: string): CompilerOption => {\n const parts = opt.split(' ');\n const namePart = parts[0].split(':');\n if (namePart.length != 2) {\n throw new Error(\n 'compiler option format is wrong: expect to have option name after \\'tengo:\\' prefix, like \\'tengo:MyOption\\'',\n );\n }\n const optName = namePart[1];\n\n return {\n name: optName,\n args: parts.slice(1),\n };\n};\n\nexport class ArtifactSource {\n constructor(\n /** The mode this artifact was built (dev or dist) */\n public readonly compileMode: CompileMode,\n /** Full artifact id, including package version */\n public readonly fullName: FullArtifactName,\n /** Hash of the source code */\n public readonly sourceHash: string,\n /** Normalized source code */\n public readonly src: string,\n /** Path to source file where artifact came from */\n public readonly srcName: string,\n /** List of dependencies */\n public readonly dependencies: TypedArtifactName[],\n /** Additional compiler options detected in source code */\n public readonly compilerOptions: CompilerOption[],\n ) {}\n}\n\nexport function parseSourceFile(\n logger: MiLogger,\n mode: CompileMode,\n srcFile: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const src = readFileSync(srcFile).toString();\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(\n mode,\n fullSourceName,\n getSha256(normalized),\n normalized,\n srcFile,\n deps.array,\n opts,\n );\n}\n\nexport function parseSource(\n logger: MiLogger,\n mode: CompileMode,\n src: string,\n fullSourceName: FullArtifactName,\n normalize: boolean,\n): ArtifactSource {\n const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);\n\n return new ArtifactSource(mode, fullSourceName, getSha256(normalized), normalized, '', deps.array, opts);\n}\n\n/**\n * Reads src\n * returns normalized source code,\n * gets dependencies from imports,\n * maps imports to global names if globalizeImports is true,\n * and collects compiler options like hashOverride.\n */\nfunction parseSourceData(\n logger: MiLogger,\n src: string,\n fullSourceName: FullArtifactName,\n globalizeImports: boolean,\n): {\n normalized: string;\n deps: ArtifactMap<TypedArtifactName>;\n opts: CompilerOption[];\n } {\n const dependencySet = createArtifactNameSet();\n const optionList: CompilerOption[] = [];\n\n // iterating over lines\n const lines = src.split('\\n');\n\n // processedLines keep all the original lines from <src>.\n // If <globalizeImport>==true, the parser modifies 'import' and 'getTemplateId' lines\n // with Platforma Tengo lib and template usages, resolving local names (\":<item>\") to\n // global (\"@milaboratory/pkg:<item>\")\n const processedLines: string[] = [];\n let parserContext: sourceParserContext = {\n isInCommentBlock: false,\n canDetectOptions: true,\n tplDepREs: new Map<string, [ArtifactType, RegExp][]>(),\n lineNo: 0,\n };\n\n for (const line of lines) {\n parserContext.lineNo++;\n\n try {\n const { line: processedLine, context: newContext, artifact, option } = parseSingleSourceLine(\n logger,\n line,\n parserContext,\n fullSourceName.pkg,\n globalizeImports,\n );\n processedLines.push(processedLine);\n parserContext = newContext;\n\n if (artifact) {\n dependencySet.add(artifact);\n }\n if (option) {\n optionList.push(option);\n }\n } catch (error: unknown) {\n const err = error as Error;\n throw new Error(`[line ${parserContext.lineNo} in ${fullNameToString(fullSourceName)}]: ${err.message}\\n\\t${line}`, { cause: err });\n }\n }\n\n return {\n normalized: processedLines.join('\\n'),\n deps: dependencySet,\n opts: optionList,\n };\n}\n\ninterface sourceParserContext {\n isInCommentBlock: boolean;\n canDetectOptions: boolean;\n tplDepREs: Map<string, [ArtifactType, RegExp][]>;\n lineNo: number;\n}\n\nexport function parseSingleSourceLine(\n logger: MiLogger,\n line: string,\n context: sourceParserContext,\n localPackageName: string,\n globalizeImports?: boolean,\n): {\n line: string;\n context: sourceParserContext;\n artifact: TypedArtifactName | undefined;\n option: CompilerOption | undefined;\n } {\n // preprocess line and remove inline comments\n line = line.replaceAll(inlineCommentRE, '');\n\n if (context.isInCommentBlock) {\n if (multilineCommentEndRE.exec(line)) {\n context.isInCommentBlock = false;\n }\n return { line: '', context, artifact: undefined, option: undefined };\n }\n\n if (compilerOptionRE.exec(line)) {\n if (!context.canDetectOptions) {\n logger.error(\n `[line ${context.lineNo}]: compiler option '//tengo:' was detected, but it cannot be applied as compiler options can be set only at the file header, before any code line'`,\n );\n throw new Error('tengo compiler options (\\'//tengo:\\' comments) can be set only in file header');\n }\n return { line, context, artifact: undefined, option: parseComplierOption(line) };\n }\n\n if (wrongCompilerOptionRE.exec(line) && context.canDetectOptions) {\n logger.warn(\n `[line ${context.lineNo}]: text simillar to compiler option ('//tengo:...') was detected, but it has wrong format. Leave it as is, if you did not mean to use a line as compiler option. Or format it to '//tengo:<option>' otherwise (no spaces between '//' and 'tengo', no spaces between ':' and option name)`,\n );\n return { line, context, artifact: undefined, option: undefined };\n }\n\n if (singlelineCommentRE.test(line)) {\n return { line: '', context, artifact: undefined, option: undefined };\n }\n\n if (multilineCommentStartRE.exec(line)) {\n context.isInCommentBlock = true;\n return { line: '', context, artifact: undefined, option: undefined };\n }\n\n if (line.includes('/*')) {\n throw new Error('malformed multiline comment');\n }\n\n if (emptyLineRE.exec(line)) {\n return { line, context, artifact: undefined, option: undefined };\n }\n\n // options could be only at the top of the file.\n context.canDetectOptions = false;\n\n const importInstruction = importRE.exec(line);\n\n if (importInstruction) {\n const iInfo = parseImport(line);\n\n // If we have plapi, ll or assets, then try to parse\n // getTemplateId, getSoftwareInfo, getSoftware and getAsset calls.\n\n if (iInfo.module === 'plapi') {\n if (!context.tplDepREs.has(iInfo.module)) {\n context.tplDepREs.set(iInfo.module, [\n ['template', newGetTemplateIdRE(iInfo.alias)],\n ['software', newGetSoftwareInfoRE(iInfo.alias)],\n ]);\n }\n return { line, context, artifact: undefined, option: undefined };\n }\n\n if (\n iInfo.module === '@milaboratory/tengo-sdk:ll'\n || iInfo.module === '@platforma-sdk/workflow-tengo:ll'\n || ((localPackageName === '@milaboratory/tengo-sdk'\n || localPackageName === '@platforma-sdk/workflow-tengo')\n && iInfo.module === ':ll')\n ) {\n if (!context.tplDepREs.has(iInfo.module)) {\n context.tplDepREs.set(iInfo.module, [\n ['template', newImportTemplateRE(iInfo.alias)],\n ['software', newImportSoftwareRE(iInfo.alias)],\n ]);\n }\n }\n\n if (\n iInfo.module === '@milaboratory/tengo-sdk:assets'\n || iInfo.module === '@platforma-sdk/workflow-tengo:assets'\n || ((localPackageName === '@milaboratory/tengo-sdk'\n || localPackageName === '@platforma-sdk/workflow-tengo')\n && iInfo.module === ':assets')\n ) {\n if (!context.tplDepREs.has(iInfo.module)) {\n context.tplDepREs.set(iInfo.module, [\n ['template', newImportTemplateRE(iInfo.alias)],\n ['software', newImportSoftwareRE(iInfo.alias)],\n ['asset', newImportAssetRE(iInfo.alias)],\n ]);\n }\n }\n\n const artifact = parseArtifactName(iInfo.module, 'library', localPackageName);\n if (!artifact) {\n // not a Platforma Tengo library import\n return { line, context, artifact: undefined, option: undefined };\n }\n\n if (globalizeImports) {\n line = line.replace(importInstruction[0], ` := import(\"${artifact.pkg}:${artifact.id}\")`);\n }\n\n return { line, context, artifact, option: undefined };\n }\n\n if (context.tplDepREs.size > 0) {\n for (const [_, artifactRE] of context.tplDepREs) {\n for (const [artifactType, re] of artifactRE) {\n const match = re.exec(line);\n if (!match || !match.groups) {\n continue;\n }\n\n const { fnCall, templateName, fnName } = match.groups;\n\n if (!fnCall || !templateName || !fnName) {\n throw Error(`failed to parse template import statement`);\n }\n\n const artifact = parseArtifactName(templateName, artifactType, localPackageName);\n if (!artifact) {\n throw Error(`failed to parse artifact name in ${fnName} import statement`);\n }\n\n if (globalizeImports) {\n line = line.replace(fnCall, `${fnName}(\"${artifact.pkg}:${artifact.id}\")`);\n }\n\n return { line, context, artifact, option: undefined };\n }\n }\n }\n\n return { line, context, artifact: undefined, option: undefined };\n}\n\ninterface ImportInfo {\n module: string; // the module name without wrapping quotes: import(\"<module>\")\n alias: string; // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n}\n\nfunction parseImport(line: string): ImportInfo {\n const match = importNameRE.exec(line);\n\n if (!match || !match.groups) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n const { importName, moduleName } = match.groups;\n if (!importName || !moduleName) {\n throw Error(`failed to parse 'import' statement`);\n }\n\n return {\n module: moduleName, // the module name without wrapping quotes: import(\"<module>\")\n alias: importName, // the name of variable that keeps imported module: <alias> := import(\"<module>\")\n };\n}\n\nfunction parseArtifactName(\n moduleName: string,\n aType: ArtifactType,\n localPackageName: string,\n): TypedArtifactName | undefined {\n const depInfo = dependencyRE.exec(moduleName);\n if (!depInfo) {\n return;\n }\n\n if (!depInfo.groups) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n const { pkgName, depID } = depInfo.groups;\n if (!depID) {\n throw Error(\n `failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`,\n );\n }\n\n return { type: aType, pkg: pkgName ?? localPackageName, id: depID };\n}\n\nexport function getSha256(source: string): string {\n return createHash('sha256').update(source).digest('hex');\n}\n"],"names":["readFileSync","createArtifactNameSet","fullNameToString","createHash"],"mappings":"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"}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fullNameToString } from './package.js';
|
|
3
|
+
import { createArtifactNameSet } from './artifactset.js';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
|
|
6
|
+
// matches any valid name in tengo. Don't forget to use '\b' when needed to limit the boundaries!
|
|
7
|
+
const namePattern = '[_a-zA-Z][_a-zA-Z0-9]*';
|
|
8
|
+
const functionCallRE = (moduleName, fnName) => {
|
|
9
|
+
return new RegExp(`\\b${moduleName}\\.(?<fnCall>(?<fnName>`
|
|
10
|
+
+ fnName
|
|
11
|
+
+ `)\\s*\\(\\s*"(?<templateName>[^"]+)"\\s*\\))`);
|
|
12
|
+
};
|
|
13
|
+
const newGetTemplateIdRE = (moduleName) => {
|
|
14
|
+
return functionCallRE(moduleName, 'getTemplateId');
|
|
15
|
+
};
|
|
16
|
+
const newGetSoftwareInfoRE = (moduleName) => {
|
|
17
|
+
return functionCallRE(moduleName, 'getSoftwareInfo');
|
|
18
|
+
};
|
|
19
|
+
const newImportTemplateRE = (moduleName) => {
|
|
20
|
+
return functionCallRE(moduleName, 'importTemplate');
|
|
21
|
+
};
|
|
22
|
+
const newImportSoftwareRE = (moduleName) => {
|
|
23
|
+
return functionCallRE(moduleName, 'importSoftware');
|
|
24
|
+
};
|
|
25
|
+
const newImportAssetRE = (moduleName) => {
|
|
26
|
+
return functionCallRE(moduleName, 'importAsset');
|
|
27
|
+
};
|
|
28
|
+
const emptyLineRE = /^\s*$/;
|
|
29
|
+
const compilerOptionRE = /^\/\/tengo:[\w]/;
|
|
30
|
+
const wrongCompilerOptionRE = /^\s*\/\/\s*tengo:\s*./;
|
|
31
|
+
const inlineCommentRE = /\/\*.*?\*\//g; // .*? = non-greedy search
|
|
32
|
+
const singlelineCommentRE = /^\s*(\/\/)/;
|
|
33
|
+
const multilineCommentStartRE = /^\s*\/\*/;
|
|
34
|
+
const multilineCommentEndRE = /\*\//;
|
|
35
|
+
// import could only be an assignment in a statement,
|
|
36
|
+
// other ways could break a compilation.
|
|
37
|
+
const importRE = /\s*:=\s*import\s*\(\s*"(?<moduleName>[^"]+)"\s*\)/;
|
|
38
|
+
const importNameRE = new RegExp(`\\b(?<importName>${namePattern}(\\.${namePattern})*)${importRE.source}`);
|
|
39
|
+
const dependencyRE = /(?<pkgName>[^"]+)?:(?<depID>[^"]+)/; // use it to parse <moduleName> from importPattern or <templateName> from getTemplateID
|
|
40
|
+
/**
|
|
41
|
+
* Parse compiler option string representation
|
|
42
|
+
* Compiler option line is a comment starting with '//tengo:', say
|
|
43
|
+
* //tengo:hash_override tralala
|
|
44
|
+
*
|
|
45
|
+
* The common compiler option syntax is:
|
|
46
|
+
* //tengo:<option name> [<option arg1> [<option arg 2> [...]]]
|
|
47
|
+
*/
|
|
48
|
+
const parseComplierOption = (opt) => {
|
|
49
|
+
const parts = opt.split(' ');
|
|
50
|
+
const namePart = parts[0].split(':');
|
|
51
|
+
if (namePart.length != 2) {
|
|
52
|
+
throw new Error('compiler option format is wrong: expect to have option name after \'tengo:\' prefix, like \'tengo:MyOption\'');
|
|
53
|
+
}
|
|
54
|
+
const optName = namePart[1];
|
|
55
|
+
return {
|
|
56
|
+
name: optName,
|
|
57
|
+
args: parts.slice(1),
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
class ArtifactSource {
|
|
61
|
+
compileMode;
|
|
62
|
+
fullName;
|
|
63
|
+
sourceHash;
|
|
64
|
+
src;
|
|
65
|
+
srcName;
|
|
66
|
+
dependencies;
|
|
67
|
+
compilerOptions;
|
|
68
|
+
constructor(
|
|
69
|
+
/** The mode this artifact was built (dev or dist) */
|
|
70
|
+
compileMode,
|
|
71
|
+
/** Full artifact id, including package version */
|
|
72
|
+
fullName,
|
|
73
|
+
/** Hash of the source code */
|
|
74
|
+
sourceHash,
|
|
75
|
+
/** Normalized source code */
|
|
76
|
+
src,
|
|
77
|
+
/** Path to source file where artifact came from */
|
|
78
|
+
srcName,
|
|
79
|
+
/** List of dependencies */
|
|
80
|
+
dependencies,
|
|
81
|
+
/** Additional compiler options detected in source code */
|
|
82
|
+
compilerOptions) {
|
|
83
|
+
this.compileMode = compileMode;
|
|
84
|
+
this.fullName = fullName;
|
|
85
|
+
this.sourceHash = sourceHash;
|
|
86
|
+
this.src = src;
|
|
87
|
+
this.srcName = srcName;
|
|
88
|
+
this.dependencies = dependencies;
|
|
89
|
+
this.compilerOptions = compilerOptions;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function parseSourceFile(logger, mode, srcFile, fullSourceName, normalize) {
|
|
93
|
+
const src = readFileSync(srcFile).toString();
|
|
94
|
+
const { deps, normalized, opts } = parseSourceData(logger, src, fullSourceName, normalize);
|
|
95
|
+
return new ArtifactSource(mode, fullSourceName, getSha256(normalized), normalized, srcFile, deps.array, opts);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Reads src
|
|
99
|
+
* returns normalized source code,
|
|
100
|
+
* gets dependencies from imports,
|
|
101
|
+
* maps imports to global names if globalizeImports is true,
|
|
102
|
+
* and collects compiler options like hashOverride.
|
|
103
|
+
*/
|
|
104
|
+
function parseSourceData(logger, src, fullSourceName, globalizeImports) {
|
|
105
|
+
const dependencySet = createArtifactNameSet();
|
|
106
|
+
const optionList = [];
|
|
107
|
+
// iterating over lines
|
|
108
|
+
const lines = src.split('\n');
|
|
109
|
+
// processedLines keep all the original lines from <src>.
|
|
110
|
+
// If <globalizeImport>==true, the parser modifies 'import' and 'getTemplateId' lines
|
|
111
|
+
// with Platforma Tengo lib and template usages, resolving local names (":<item>") to
|
|
112
|
+
// global ("@milaboratory/pkg:<item>")
|
|
113
|
+
const processedLines = [];
|
|
114
|
+
let parserContext = {
|
|
115
|
+
isInCommentBlock: false,
|
|
116
|
+
canDetectOptions: true,
|
|
117
|
+
tplDepREs: new Map(),
|
|
118
|
+
lineNo: 0,
|
|
119
|
+
};
|
|
120
|
+
for (const line of lines) {
|
|
121
|
+
parserContext.lineNo++;
|
|
122
|
+
try {
|
|
123
|
+
const { line: processedLine, context: newContext, artifact, option } = parseSingleSourceLine(logger, line, parserContext, fullSourceName.pkg, globalizeImports);
|
|
124
|
+
processedLines.push(processedLine);
|
|
125
|
+
parserContext = newContext;
|
|
126
|
+
if (artifact) {
|
|
127
|
+
dependencySet.add(artifact);
|
|
128
|
+
}
|
|
129
|
+
if (option) {
|
|
130
|
+
optionList.push(option);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
const err = error;
|
|
135
|
+
throw new Error(`[line ${parserContext.lineNo} in ${fullNameToString(fullSourceName)}]: ${err.message}\n\t${line}`, { cause: err });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
normalized: processedLines.join('\n'),
|
|
140
|
+
deps: dependencySet,
|
|
141
|
+
opts: optionList,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function parseSingleSourceLine(logger, line, context, localPackageName, globalizeImports) {
|
|
145
|
+
// preprocess line and remove inline comments
|
|
146
|
+
line = line.replaceAll(inlineCommentRE, '');
|
|
147
|
+
if (context.isInCommentBlock) {
|
|
148
|
+
if (multilineCommentEndRE.exec(line)) {
|
|
149
|
+
context.isInCommentBlock = false;
|
|
150
|
+
}
|
|
151
|
+
return { line: '', context, artifact: undefined, option: undefined };
|
|
152
|
+
}
|
|
153
|
+
if (compilerOptionRE.exec(line)) {
|
|
154
|
+
if (!context.canDetectOptions) {
|
|
155
|
+
logger.error(`[line ${context.lineNo}]: compiler option '//tengo:' was detected, but it cannot be applied as compiler options can be set only at the file header, before any code line'`);
|
|
156
|
+
throw new Error('tengo compiler options (\'//tengo:\' comments) can be set only in file header');
|
|
157
|
+
}
|
|
158
|
+
return { line, context, artifact: undefined, option: parseComplierOption(line) };
|
|
159
|
+
}
|
|
160
|
+
if (wrongCompilerOptionRE.exec(line) && context.canDetectOptions) {
|
|
161
|
+
logger.warn(`[line ${context.lineNo}]: text simillar to compiler option ('//tengo:...') was detected, but it has wrong format. Leave it as is, if you did not mean to use a line as compiler option. Or format it to '//tengo:<option>' otherwise (no spaces between '//' and 'tengo', no spaces between ':' and option name)`);
|
|
162
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
163
|
+
}
|
|
164
|
+
if (singlelineCommentRE.test(line)) {
|
|
165
|
+
return { line: '', context, artifact: undefined, option: undefined };
|
|
166
|
+
}
|
|
167
|
+
if (multilineCommentStartRE.exec(line)) {
|
|
168
|
+
context.isInCommentBlock = true;
|
|
169
|
+
return { line: '', context, artifact: undefined, option: undefined };
|
|
170
|
+
}
|
|
171
|
+
if (line.includes('/*')) {
|
|
172
|
+
throw new Error('malformed multiline comment');
|
|
173
|
+
}
|
|
174
|
+
if (emptyLineRE.exec(line)) {
|
|
175
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
176
|
+
}
|
|
177
|
+
// options could be only at the top of the file.
|
|
178
|
+
context.canDetectOptions = false;
|
|
179
|
+
const importInstruction = importRE.exec(line);
|
|
180
|
+
if (importInstruction) {
|
|
181
|
+
const iInfo = parseImport(line);
|
|
182
|
+
// If we have plapi, ll or assets, then try to parse
|
|
183
|
+
// getTemplateId, getSoftwareInfo, getSoftware and getAsset calls.
|
|
184
|
+
if (iInfo.module === 'plapi') {
|
|
185
|
+
if (!context.tplDepREs.has(iInfo.module)) {
|
|
186
|
+
context.tplDepREs.set(iInfo.module, [
|
|
187
|
+
['template', newGetTemplateIdRE(iInfo.alias)],
|
|
188
|
+
['software', newGetSoftwareInfoRE(iInfo.alias)],
|
|
189
|
+
]);
|
|
190
|
+
}
|
|
191
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
192
|
+
}
|
|
193
|
+
if (iInfo.module === '@milaboratory/tengo-sdk:ll'
|
|
194
|
+
|| iInfo.module === '@platforma-sdk/workflow-tengo:ll'
|
|
195
|
+
|| ((localPackageName === '@milaboratory/tengo-sdk'
|
|
196
|
+
|| localPackageName === '@platforma-sdk/workflow-tengo')
|
|
197
|
+
&& iInfo.module === ':ll')) {
|
|
198
|
+
if (!context.tplDepREs.has(iInfo.module)) {
|
|
199
|
+
context.tplDepREs.set(iInfo.module, [
|
|
200
|
+
['template', newImportTemplateRE(iInfo.alias)],
|
|
201
|
+
['software', newImportSoftwareRE(iInfo.alias)],
|
|
202
|
+
]);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (iInfo.module === '@milaboratory/tengo-sdk:assets'
|
|
206
|
+
|| iInfo.module === '@platforma-sdk/workflow-tengo:assets'
|
|
207
|
+
|| ((localPackageName === '@milaboratory/tengo-sdk'
|
|
208
|
+
|| localPackageName === '@platforma-sdk/workflow-tengo')
|
|
209
|
+
&& iInfo.module === ':assets')) {
|
|
210
|
+
if (!context.tplDepREs.has(iInfo.module)) {
|
|
211
|
+
context.tplDepREs.set(iInfo.module, [
|
|
212
|
+
['template', newImportTemplateRE(iInfo.alias)],
|
|
213
|
+
['software', newImportSoftwareRE(iInfo.alias)],
|
|
214
|
+
['asset', newImportAssetRE(iInfo.alias)],
|
|
215
|
+
]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const artifact = parseArtifactName(iInfo.module, 'library', localPackageName);
|
|
219
|
+
if (!artifact) {
|
|
220
|
+
// not a Platforma Tengo library import
|
|
221
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
222
|
+
}
|
|
223
|
+
{
|
|
224
|
+
line = line.replace(importInstruction[0], ` := import("${artifact.pkg}:${artifact.id}")`);
|
|
225
|
+
}
|
|
226
|
+
return { line, context, artifact, option: undefined };
|
|
227
|
+
}
|
|
228
|
+
if (context.tplDepREs.size > 0) {
|
|
229
|
+
for (const [_, artifactRE] of context.tplDepREs) {
|
|
230
|
+
for (const [artifactType, re] of artifactRE) {
|
|
231
|
+
const match = re.exec(line);
|
|
232
|
+
if (!match || !match.groups) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const { fnCall, templateName, fnName } = match.groups;
|
|
236
|
+
if (!fnCall || !templateName || !fnName) {
|
|
237
|
+
throw Error(`failed to parse template import statement`);
|
|
238
|
+
}
|
|
239
|
+
const artifact = parseArtifactName(templateName, artifactType, localPackageName);
|
|
240
|
+
if (!artifact) {
|
|
241
|
+
throw Error(`failed to parse artifact name in ${fnName} import statement`);
|
|
242
|
+
}
|
|
243
|
+
{
|
|
244
|
+
line = line.replace(fnCall, `${fnName}("${artifact.pkg}:${artifact.id}")`);
|
|
245
|
+
}
|
|
246
|
+
return { line, context, artifact, option: undefined };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return { line, context, artifact: undefined, option: undefined };
|
|
251
|
+
}
|
|
252
|
+
function parseImport(line) {
|
|
253
|
+
const match = importNameRE.exec(line);
|
|
254
|
+
if (!match || !match.groups) {
|
|
255
|
+
throw Error(`failed to parse 'import' statement`);
|
|
256
|
+
}
|
|
257
|
+
const { importName, moduleName } = match.groups;
|
|
258
|
+
if (!importName || !moduleName) {
|
|
259
|
+
throw Error(`failed to parse 'import' statement`);
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
module: moduleName, // the module name without wrapping quotes: import("<module>")
|
|
263
|
+
alias: importName, // the name of variable that keeps imported module: <alias> := import("<module>")
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function parseArtifactName(moduleName, aType, localPackageName) {
|
|
267
|
+
const depInfo = dependencyRE.exec(moduleName);
|
|
268
|
+
if (!depInfo) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (!depInfo.groups) {
|
|
272
|
+
throw Error(`failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`);
|
|
273
|
+
}
|
|
274
|
+
const { pkgName, depID } = depInfo.groups;
|
|
275
|
+
if (!depID) {
|
|
276
|
+
throw Error(`failed to parse dependency name inside 'import' statement. The dependency name should have format '<package>:<templateName>'`);
|
|
277
|
+
}
|
|
278
|
+
return { type: aType, pkg: pkgName ?? localPackageName, id: depID };
|
|
279
|
+
}
|
|
280
|
+
function getSha256(source) {
|
|
281
|
+
return createHash('sha256').update(source).digest('hex');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export { ArtifactSource, getSha256, newGetSoftwareInfoRE, newGetTemplateIdRE, parseSingleSourceLine, parseSourceFile };
|
|
285
|
+
//# sourceMappingURL=source.js.map
|