@taqueria/plugin-ligo 0.37.21 → 0.37.34
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/common.ts +3 -2
- package/compile-all.ts +15 -111
- package/compile.ts +413 -174
- package/createContract.ts +1 -5
- package/index.js +396 -329
- package/index.js.map +1 -1
- package/index.mjs +407 -333
- package/index.mjs.map +1 -1
- package/index.ts +7 -0
- package/ligo.ts +1 -1
- package/ligo_templates.ts +17 -94
- package/package.json +3 -3
- package/postinstall.js +19 -0
package/compile.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
execCmd,
|
|
3
|
+
getArch,
|
|
4
|
+
getArtifactsDir,
|
|
5
|
+
sendAsyncErr,
|
|
6
|
+
sendErr,
|
|
7
|
+
sendJsonRes,
|
|
8
|
+
sendRes,
|
|
9
|
+
sendWarn,
|
|
10
|
+
} from '@taqueria/node-sdk';
|
|
2
11
|
import { access, readFile, writeFile } from 'fs/promises';
|
|
3
12
|
import { basename, extname, join } from 'path';
|
|
4
13
|
import {
|
|
@@ -7,34 +16,98 @@ import {
|
|
|
7
16
|
getInputFilenameAbsPath,
|
|
8
17
|
getInputFilenameRelPath,
|
|
9
18
|
getLigoDockerImage,
|
|
19
|
+
UnionOpts,
|
|
10
20
|
} from './common';
|
|
11
21
|
|
|
12
|
-
export type TableRow = {
|
|
22
|
+
export type TableRow = { source: string; artifact: string };
|
|
13
23
|
|
|
14
24
|
export type ExprKind = 'storage' | 'default_storage' | 'parameter';
|
|
15
25
|
|
|
26
|
+
export type ModuleInfo = {
|
|
27
|
+
moduleName: string;
|
|
28
|
+
sourceName: string;
|
|
29
|
+
sourceFile: string;
|
|
30
|
+
syntax: 'mligo' | 'jsligo' | 'religo' | 'ligo';
|
|
31
|
+
type: 'file-main' | 'file-entry' | 'module-main' | 'module-entry';
|
|
32
|
+
};
|
|
33
|
+
|
|
16
34
|
const COMPILE_ERR_MSG: string = 'Not compiled';
|
|
17
35
|
|
|
18
36
|
const isStorageKind = (exprKind: ExprKind): boolean => exprKind === 'storage' || exprKind === 'default_storage';
|
|
19
37
|
|
|
20
|
-
const
|
|
38
|
+
export const isSupportedLigoSyntax = (sourceFile: string) => /\.(mligo|jsligo)$/.test(sourceFile);
|
|
39
|
+
|
|
40
|
+
export const isUnsupportedLigoSyntax = (sourceFile: string) => /\.(ligo|religo)$/.test(sourceFile);
|
|
21
41
|
|
|
22
|
-
const
|
|
42
|
+
export const isLIGOFile = (sourceFile: string) =>
|
|
43
|
+
isSupportedLigoSyntax(sourceFile) || isUnsupportedLigoSyntax(sourceFile);
|
|
44
|
+
|
|
45
|
+
export const isStorageListFile = (sourceFile: string): boolean =>
|
|
23
46
|
/.+\.(storageList|storages)\.(ligo|religo|mligo|jsligo)$/.test(sourceFile);
|
|
24
47
|
|
|
25
|
-
const isParameterListFile = (sourceFile: string): boolean =>
|
|
48
|
+
export const isParameterListFile = (sourceFile: string): boolean =>
|
|
26
49
|
/.+\.(parameterList|parameters)\.(ligo|religo|mligo|jsligo)$/.test(sourceFile);
|
|
27
50
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return
|
|
51
|
+
export const listContractModules = async (parsedArgs: UnionOpts, sourceFile: string): Promise<ModuleInfo[]> => {
|
|
52
|
+
try {
|
|
53
|
+
await getArch();
|
|
54
|
+
const cmd = await getListDeclarationsCmd(parsedArgs, sourceFile);
|
|
55
|
+
const { stderr, stdout } = await execCmd(cmd);
|
|
56
|
+
if (stderr.length > 0) return Promise.reject(stderr);
|
|
57
|
+
|
|
58
|
+
return JSON.parse(stdout).declarations.reduce(
|
|
59
|
+
(acc: ModuleInfo[], decl: string) => {
|
|
60
|
+
// We need to process delcarations (decl) like so:
|
|
61
|
+
// 1. If the decl is equal to the string "main", then the module type is "file-main" and the name of the module is the sourceFile.
|
|
62
|
+
// 2. If the decl is equal to $main, then the module type is "file-entry" and the name fo the module is the sourceFile.
|
|
63
|
+
// 3. If the decl ends with .main, then the module type is "module-main" and the name of the module is the decl without the .main suffix.
|
|
64
|
+
// 4. If the decl ends with .$main, then the module type is "module-entry" and the name of the module is the decl without the .$main suffix.
|
|
65
|
+
// Otherwise, this is not a declaration we care about.
|
|
66
|
+
const srcFile = removeExt(basename(sourceFile));
|
|
67
|
+
const syntax = extractExt(sourceFile).replace('.', '');
|
|
68
|
+
|
|
69
|
+
if (decl === 'main') {
|
|
70
|
+
return [...acc, { moduleName: srcFile, sourceName: sourceFile, sourceFile, type: 'file-main', syntax }];
|
|
71
|
+
} else if (decl === '$main') {
|
|
72
|
+
return [...acc, { moduleName: srcFile, sourceName: sourceFile, sourceFile, type: 'file-entry', syntax }];
|
|
73
|
+
} else if (decl.endsWith('.main')) {
|
|
74
|
+
const moduleName = decl.replace(/\.main$/, '');
|
|
75
|
+
return [...acc, {
|
|
76
|
+
moduleName,
|
|
77
|
+
sourceName: `${sourceFile}/${moduleName}`,
|
|
78
|
+
sourceFile,
|
|
79
|
+
type: 'module-main',
|
|
80
|
+
syntax,
|
|
81
|
+
}];
|
|
82
|
+
} else if (decl.endsWith('.$main')) {
|
|
83
|
+
const moduleName = decl.replace(/\.\$main$/, '');
|
|
84
|
+
return [...acc, {
|
|
85
|
+
moduleName,
|
|
86
|
+
sourceName: `${sourceFile}/${moduleName}`,
|
|
87
|
+
sourceFile,
|
|
88
|
+
type: 'module-entry',
|
|
89
|
+
syntax,
|
|
90
|
+
}];
|
|
91
|
+
}
|
|
92
|
+
return acc;
|
|
93
|
+
},
|
|
94
|
+
[],
|
|
95
|
+
);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
emitExternalError(err, sourceFile);
|
|
98
|
+
return [];
|
|
36
99
|
}
|
|
37
|
-
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const getListDeclarationsCmd = async (parsedArgs: UnionOpts, sourceFile: string): Promise<string> => {
|
|
103
|
+
const projectDir = process.env.PROJECT_DIR ?? parsedArgs.projectDir;
|
|
104
|
+
if (!projectDir) throw new Error(`No project directory provided`);
|
|
105
|
+
const baseCmd =
|
|
106
|
+
`DOCKER_DEFAULT_PLATFORM=linux/amd64 docker run --rm -v \"${projectDir}\":/project -w /project -u $(id -u):$(id -g) ${getLigoDockerImage()} info list-declarations`;
|
|
107
|
+
const inputFile = getInputFilenameRelPath(parsedArgs, sourceFile);
|
|
108
|
+
const flags = '--display-format json';
|
|
109
|
+
const cmd = `${baseCmd} ${inputFile} ${flags}`;
|
|
110
|
+
return cmd;
|
|
38
111
|
};
|
|
39
112
|
|
|
40
113
|
const extractExt = (path: string): string => {
|
|
@@ -49,27 +122,13 @@ const removeExt = (path: string): string => {
|
|
|
49
122
|
|
|
50
123
|
const isOutputFormatJSON = (parsedArgs: Opts): boolean => parsedArgs.json;
|
|
51
124
|
|
|
52
|
-
const getOutputContractFilename = (parsedArgs: Opts,
|
|
53
|
-
const outputFile = basename(sourceFile, extname(sourceFile));
|
|
125
|
+
const getOutputContractFilename = (parsedArgs: Opts, module: ModuleInfo): string => {
|
|
54
126
|
const ext = isOutputFormatJSON(parsedArgs) ? '.json' : '.tz';
|
|
55
|
-
return join(getArtifactsDir(parsedArgs), `${
|
|
127
|
+
return join(getArtifactsDir(parsedArgs), `${module.moduleName}${ext}`);
|
|
56
128
|
};
|
|
57
129
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const getContractNameForExpr = (sourceFile: string, exprKind: ExprKind): string => {
|
|
61
|
-
try {
|
|
62
|
-
return isStorageKind(exprKind)
|
|
63
|
-
? sourceFile.match(/.+(?=\.(?:storageList|storages)\.(ligo|religo|mligo|jsligo))/)!.join('.')
|
|
64
|
-
: sourceFile.match(/.+(?=\.(?:parameterList|parameters)\.(ligo|religo|mligo|jsligo))/)!.join('.');
|
|
65
|
-
} catch (err) {
|
|
66
|
-
throw new Error(`Something went wrong internally when dealing with filename format: ${err}`);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// If sourceFile is token.storageList.mligo, then it'll return token.storage.{storageName}.tz
|
|
71
|
-
const getOutputExprFilename = (parsedArgs: Opts, sourceFile: string, exprKind: ExprKind, exprName: string): string => {
|
|
72
|
-
const contractName = basename(getContractNameForExpr(sourceFile, exprKind), extname(sourceFile));
|
|
130
|
+
const getOutputExprFilename = (parsedArgs: Opts, module: ModuleInfo, exprKind: ExprKind, exprName: string): string => {
|
|
131
|
+
const contractName = module.moduleName;
|
|
73
132
|
const ext = isOutputFormatJSON(parsedArgs) ? '.json' : '.tz';
|
|
74
133
|
const outputFile = exprKind === 'default_storage'
|
|
75
134
|
? `${contractName}.default_storage${ext}`
|
|
@@ -77,78 +136,103 @@ const getOutputExprFilename = (parsedArgs: Opts, sourceFile: string, exprKind: E
|
|
|
77
136
|
return join(getArtifactsDir(parsedArgs), `${outputFile}`);
|
|
78
137
|
};
|
|
79
138
|
|
|
80
|
-
const getCompileContractCmd = async (parsedArgs: Opts, sourceFile: string): Promise<string> => {
|
|
139
|
+
const getCompileContractCmd = async (parsedArgs: Opts, sourceFile: string, module: ModuleInfo): Promise<string> => {
|
|
81
140
|
const projectDir = process.env.PROJECT_DIR ?? parsedArgs.projectDir;
|
|
82
|
-
if (!projectDir) throw `No project directory provided
|
|
141
|
+
if (!projectDir) throw new Error(`No project directory provided`);
|
|
83
142
|
const baseCmd =
|
|
84
143
|
`DOCKER_DEFAULT_PLATFORM=linux/amd64 docker run --rm -v \"${projectDir}\":/project -w /project -u $(id -u):$(id -g) ${getLigoDockerImage()} compile contract`;
|
|
85
144
|
const inputFile = getInputFilenameRelPath(parsedArgs, sourceFile);
|
|
86
|
-
const outputFile = `-o ${getOutputContractFilename(parsedArgs,
|
|
145
|
+
const outputFile = `-o ${getOutputContractFilename(parsedArgs, module)}`;
|
|
87
146
|
const flags = isOutputFormatJSON(parsedArgs) ? ' --michelson-format json ' : '';
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const cmd = `${baseCmd} ${inputFile} ${outputFile} ${flags}${entryFlag}`;
|
|
147
|
+
const moduleFlag = module.type.startsWith('file-') ? '' : `-m ${module.moduleName}`;
|
|
148
|
+
const cmd = `${baseCmd} ${inputFile} ${outputFile} ${flags}${moduleFlag}`;
|
|
91
149
|
return cmd;
|
|
92
150
|
};
|
|
93
151
|
|
|
94
|
-
const getCompileExprCmd = (
|
|
152
|
+
const getCompileExprCmd = (
|
|
153
|
+
parsedArgs: Opts,
|
|
154
|
+
sourceFile: string,
|
|
155
|
+
module: ModuleInfo,
|
|
156
|
+
exprKind: ExprKind,
|
|
157
|
+
exprName: string,
|
|
158
|
+
): string => {
|
|
95
159
|
const projectDir = process.env.PROJECT_DIR ?? parsedArgs.projectDir;
|
|
96
|
-
if (!projectDir) throw `No project directory provided
|
|
160
|
+
if (!projectDir) throw new Error(`No project directory provided`);
|
|
97
161
|
const compilerType = isStorageKind(exprKind) ? 'storage' : 'parameter';
|
|
98
162
|
const baseCmd =
|
|
99
163
|
`DOCKER_DEFAULT_PLATFORM=linux/amd64 docker run --rm -v \"${projectDir}\":/project -w /project -u $(id -u):$(id -g) ${getLigoDockerImage()} compile ${compilerType}`;
|
|
100
164
|
const inputFile = getInputFilenameRelPath(parsedArgs, sourceFile);
|
|
101
|
-
const outputFile = `-o ${getOutputExprFilename(parsedArgs,
|
|
165
|
+
const outputFile = `-o ${getOutputExprFilename(parsedArgs, module, exprKind, exprName)}`;
|
|
102
166
|
const flags = isOutputFormatJSON(parsedArgs) ? ' --michelson-format json ' : '';
|
|
103
|
-
|
|
167
|
+
|
|
168
|
+
// Parameter and Storage list files are expected to import the smart contract file as the "Contract" module.
|
|
169
|
+
const moduleFlag = (() => {
|
|
170
|
+
switch (module.type) {
|
|
171
|
+
case 'file-main':
|
|
172
|
+
case 'file-entry':
|
|
173
|
+
return '-m Contract';
|
|
174
|
+
default:
|
|
175
|
+
return `-m Contract.${module.moduleName}`;
|
|
176
|
+
}
|
|
177
|
+
})();
|
|
178
|
+
|
|
179
|
+
const cmd = `${baseCmd} ${inputFile} ${exprName} ${outputFile} ${flags} ${moduleFlag}`;
|
|
104
180
|
return cmd;
|
|
105
181
|
};
|
|
106
182
|
|
|
107
|
-
const compileContract = async (parsedArgs: Opts, sourceFile: string): Promise<TableRow> => {
|
|
183
|
+
const compileContract = async (parsedArgs: Opts, sourceFile: string, module: ModuleInfo): Promise<TableRow> => {
|
|
108
184
|
try {
|
|
109
185
|
await getArch();
|
|
110
|
-
const cmd = await getCompileContractCmd(parsedArgs, sourceFile);
|
|
186
|
+
const cmd = await getCompileContractCmd(parsedArgs, sourceFile, module);
|
|
111
187
|
const { stderr } = await execCmd(cmd);
|
|
112
188
|
if (stderr.length > 0) sendWarn(stderr);
|
|
189
|
+
|
|
113
190
|
return {
|
|
114
|
-
|
|
115
|
-
artifact: getOutputContractFilename(parsedArgs,
|
|
191
|
+
source: module.sourceName,
|
|
192
|
+
artifact: getOutputContractFilename(parsedArgs, module),
|
|
116
193
|
};
|
|
117
194
|
} catch (err) {
|
|
118
195
|
emitExternalError(err, sourceFile);
|
|
119
196
|
return {
|
|
120
|
-
|
|
197
|
+
source: module.sourceName,
|
|
121
198
|
artifact: COMPILE_ERR_MSG,
|
|
122
199
|
};
|
|
123
200
|
}
|
|
124
201
|
};
|
|
125
202
|
|
|
126
|
-
const compileExpr =
|
|
127
|
-
(
|
|
128
|
-
|
|
129
|
-
|
|
203
|
+
const compileExpr =
|
|
204
|
+
(parsedArgs: Opts, sourceFile: string, module: ModuleInfo, exprKind: ExprKind) =>
|
|
205
|
+
(exprName: string): Promise<TableRow> => {
|
|
206
|
+
return getArch()
|
|
207
|
+
.then(() => getCompileExprCmd(parsedArgs, sourceFile, module, exprKind, exprName))
|
|
130
208
|
.then(execCmd)
|
|
131
209
|
.then(({ stderr }) => {
|
|
132
210
|
if (stderr.length > 0) sendWarn(stderr);
|
|
133
|
-
const artifactName = getOutputExprFilename(parsedArgs,
|
|
211
|
+
const artifactName = getOutputExprFilename(parsedArgs, module, exprKind, exprName);
|
|
134
212
|
return {
|
|
135
|
-
|
|
213
|
+
source: module.sourceName,
|
|
136
214
|
artifact: artifactName,
|
|
137
215
|
};
|
|
138
216
|
})
|
|
139
217
|
.catch(err => {
|
|
140
218
|
emitExternalError(err, sourceFile);
|
|
141
219
|
return {
|
|
142
|
-
|
|
143
|
-
artifact:
|
|
220
|
+
source: module.sourceName,
|
|
221
|
+
artifact: `${sourceFile} not compiled`,
|
|
144
222
|
};
|
|
145
223
|
});
|
|
224
|
+
};
|
|
146
225
|
|
|
147
226
|
const getExprNames = (parsedArgs: Opts, sourceFile: string): Promise<string[]> =>
|
|
148
227
|
readFile(getInputFilenameAbsPath(parsedArgs, sourceFile), 'utf8')
|
|
149
228
|
.then(data => data.match(/(?<=\n\s*(let|const)\s+)[a-zA-Z0-9_]+/g) ?? []);
|
|
150
229
|
|
|
151
|
-
const compileExprs = (
|
|
230
|
+
const compileExprs = (
|
|
231
|
+
parsedArgs: Opts,
|
|
232
|
+
sourceFile: string,
|
|
233
|
+
module: ModuleInfo,
|
|
234
|
+
exprKind: ExprKind,
|
|
235
|
+
): Promise<TableRow[]> =>
|
|
152
236
|
getExprNames(parsedArgs, sourceFile)
|
|
153
237
|
.then(exprNames => {
|
|
154
238
|
if (exprNames.length === 0) return [];
|
|
@@ -156,165 +240,320 @@ const compileExprs = (parsedArgs: Opts, sourceFile: string, exprKind: ExprKind):
|
|
|
156
240
|
const restExprNames = exprNames.slice(1, exprNames.length);
|
|
157
241
|
const firstExprKind = isStorageKind(exprKind) ? 'default_storage' : 'parameter';
|
|
158
242
|
const restExprKind = isStorageKind(exprKind) ? 'storage' : 'parameter';
|
|
159
|
-
const firstExprResult = compileExpr(parsedArgs, sourceFile, firstExprKind)(firstExprName);
|
|
160
|
-
const restExprResults = restExprNames.map(compileExpr(parsedArgs, sourceFile, restExprKind));
|
|
243
|
+
const firstExprResult = compileExpr(parsedArgs, sourceFile, module, firstExprKind)(firstExprName);
|
|
244
|
+
const restExprResults = restExprNames.map(compileExpr(parsedArgs, sourceFile, module, restExprKind));
|
|
161
245
|
return Promise.all([firstExprResult].concat(restExprResults));
|
|
162
246
|
})
|
|
163
247
|
.catch(err => {
|
|
164
248
|
emitExternalError(err, sourceFile);
|
|
165
249
|
return [{
|
|
166
|
-
|
|
250
|
+
source: module.sourceName,
|
|
167
251
|
artifact: `No ${isStorageKind(exprKind) ? 'storage' : 'parameter'} expressions compiled`,
|
|
168
252
|
}];
|
|
169
253
|
})
|
|
170
254
|
.then(results =>
|
|
171
255
|
results.length > 0 ? results : [{
|
|
172
|
-
|
|
256
|
+
source: module.sourceName,
|
|
173
257
|
artifact: `No ${isStorageKind(exprKind) ? 'storage' : 'parameter'} expressions found`,
|
|
174
258
|
}]
|
|
175
|
-
)
|
|
176
|
-
.then(mergeArtifactsOutput(sourceFile));
|
|
177
|
-
|
|
178
|
-
// TODO: Just for backwards compatibility. Can be deleted in the future.
|
|
179
|
-
const tryLegacyStorageNamingConvention = (parsedArgs: Opts, sourceFile: string) => {
|
|
180
|
-
const storageListFile = `${removeExt(sourceFile)}.storages${extractExt(sourceFile)}`;
|
|
181
|
-
const storageListFilename = getInputFilenameAbsPath(parsedArgs, storageListFile);
|
|
182
|
-
return access(storageListFilename).then(() => {
|
|
183
|
-
sendWarn(
|
|
184
|
-
`Warning: The naming convention of "<CONTRACT>.storages.<EXTENSION>" is deprecated and renamed to "<CONTRACT>.storageList.<EXTENSION>". Please adjust your storage file names accordingly\n`,
|
|
185
|
-
);
|
|
186
|
-
return compileExprs(parsedArgs, storageListFile, 'storage');
|
|
187
|
-
});
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
// TODO: Just for backwards compatibility. Can be deleted in the future.
|
|
191
|
-
const tryLegacyParameterNamingConvention = (parsedArgs: Opts, sourceFile: string) => {
|
|
192
|
-
const parameterListFile = `${removeExt(sourceFile)}.parameters${extractExt(sourceFile)}`;
|
|
193
|
-
const parameterListFilename = getInputFilenameAbsPath(parsedArgs, parameterListFile);
|
|
194
|
-
return access(parameterListFilename).then(() => {
|
|
195
|
-
sendWarn(
|
|
196
|
-
`Warning: The naming convention of "<CONTRACT>.parameters.<EXTENSION>" is deprecated and renamed to "<CONTRACT>.parameterList.<EXTENSION>". Please adjust your parameter file names accordingly\n`,
|
|
197
259
|
);
|
|
198
|
-
return compileExprs(parsedArgs, parameterListFile, 'parameter');
|
|
199
|
-
});
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
const initContentForStorage = (sourceFile: string): string => {
|
|
203
|
-
const linkToContract = `#include "${sourceFile}"\n\n`;
|
|
204
260
|
|
|
261
|
+
const initContentForStorage = (module: ModuleInfo): string => {
|
|
262
|
+
const linkToContract = `#import "${module.sourceFile}" "Contract"\n\n`;
|
|
205
263
|
const instruction =
|
|
206
|
-
'// Define your initial storage values as a list of LIGO variable definitions
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
264
|
+
'// Define your initial storage values as a list of LIGO variable definitions, the first of which will be considered the default value to be used for origination later on\n';
|
|
265
|
+
|
|
266
|
+
const syntax = (() => {
|
|
267
|
+
const pair = [module.syntax, module.type].join('-');
|
|
268
|
+
switch (pair) {
|
|
269
|
+
case 'mligo-file-main':
|
|
270
|
+
return [
|
|
271
|
+
'// When this file was created, the smart contract was defined with a main function that was not within a named module. As such, the examples below are written with that assumption in mind.',
|
|
272
|
+
'',
|
|
273
|
+
'// If your storage is a simple value, you can define it directly',
|
|
274
|
+
'// E.g. let storage = 10',
|
|
275
|
+
'',
|
|
276
|
+
'// For added type-safety, you can reference the type of your storage from the contract',
|
|
277
|
+
'// E.g. let storage : Contract.storage = 10',
|
|
278
|
+
];
|
|
279
|
+
break;
|
|
280
|
+
case 'mligo-file-entry':
|
|
281
|
+
return [
|
|
282
|
+
'// When this file was created, the smart contract was defined with an entrypoint using `@entry` that was not within a named module. As such, the examples below are written with that assumption in mind.',
|
|
283
|
+
'',
|
|
284
|
+
'// If your storage is a simple value, you can define it directly',
|
|
285
|
+
'// E.g. let storage = 10',
|
|
286
|
+
'',
|
|
287
|
+
'// For added type-safety, you can reference the type of your storage from the contract',
|
|
288
|
+
'// E.g. let storage : Contract.storage = 10',
|
|
289
|
+
];
|
|
290
|
+
break;
|
|
291
|
+
case 'mligo-module-main':
|
|
292
|
+
return [
|
|
293
|
+
'// When this file was created, the smart contract was defined with a main function that was within a named module. As such, the examples below are written with that assumption in mind.',
|
|
294
|
+
'',
|
|
295
|
+
'// If your storage is a simple value, you can define it directly',
|
|
296
|
+
'// E.g. let storage = 10',
|
|
297
|
+
'',
|
|
298
|
+
'// For added type-safety, you can reference the type of your storage from the contract',
|
|
299
|
+
`// E.g. let storage : Contract.${module.moduleName}.storage = 10`,
|
|
300
|
+
];
|
|
301
|
+
break;
|
|
302
|
+
case 'mligo-module-entry':
|
|
303
|
+
return [
|
|
304
|
+
'// When this file was created, the smart contract was defined with an entrypoint using `@entry` that was within a named module. As such, the examples below are written with that assumption in mind.',
|
|
305
|
+
'',
|
|
306
|
+
'// If your storage is a simple value, you can define it directly',
|
|
307
|
+
'// E.g. let storage = 10',
|
|
308
|
+
'',
|
|
309
|
+
'// For added type-safety, you can reference the type of your storage from the contract',
|
|
310
|
+
`// E.g. let storage : Contract.${module.moduleName}.storage = 10`,
|
|
311
|
+
];
|
|
312
|
+
break;
|
|
313
|
+
case 'jsligo-file-main':
|
|
314
|
+
return [
|
|
315
|
+
'// When this file was created, the smart contract was defined with a main function that was not within a namespace. As such, the examples below are written with that assumption in mind.',
|
|
316
|
+
`// NOTE: The "storage" type should be exported from the contract file (${module.sourceFile})`,
|
|
317
|
+
'',
|
|
318
|
+
'// If your storage is a simple value, you can define it directly',
|
|
319
|
+
'// E.g. const storage = 10',
|
|
320
|
+
'',
|
|
321
|
+
'// For added type-safety, you can reference the type of your storage from the contract. This assumes that you have exported your `storage` type from the contract file.',
|
|
322
|
+
'// E.g. const storage : Contract.storage = 10',
|
|
323
|
+
];
|
|
324
|
+
break;
|
|
325
|
+
case 'jsligo-file-entry':
|
|
326
|
+
return [
|
|
327
|
+
'// When this file was created, the smart contract was defined with an entrypoint using `@entry` that was not within a namespace. As such, the examples below are written with that assumption in mind.',
|
|
328
|
+
'',
|
|
329
|
+
'// If your storage is a simple value, you can define it directly',
|
|
330
|
+
'// E.g. const storage = 10',
|
|
331
|
+
'',
|
|
332
|
+
'// For added type-safety, you can reference the type of your storage from the contract. This assumes that you have exported your `storage` type from the contract file.',
|
|
333
|
+
'// E.g. const storage : Contract.storage = 10',
|
|
334
|
+
];
|
|
335
|
+
break;
|
|
336
|
+
case 'jsligo-module-main':
|
|
337
|
+
return [
|
|
338
|
+
'// When this file was created, the smart contract was defined with a main function that was within a namespace. As such, the examples below are written with that assumption in mind.',
|
|
339
|
+
`// NOTE: The "storage" type should be exported from the contract file (${module.sourceFile})`,
|
|
340
|
+
'',
|
|
341
|
+
'// If your storage is a simple value, you can define it directly',
|
|
342
|
+
'// E.g. const storage = 10',
|
|
343
|
+
'',
|
|
344
|
+
'// For added type-safety, you can reference the type of your storage from the contract. This assumes that you have exported your `storage` type from the contract file.',
|
|
345
|
+
`// E.g. const storage : Contract.${module.moduleName}.storage = 10`,
|
|
346
|
+
];
|
|
347
|
+
break;
|
|
348
|
+
case 'jsligo-module-entry':
|
|
349
|
+
return [
|
|
350
|
+
'// When this file was created, the smart contract was defined with an entrypoint using `@entry` that was within a namespace. As such, the examples below are written with that assumption in mind.',
|
|
351
|
+
'',
|
|
352
|
+
'// If your storage is a simple value, you can define it directly',
|
|
353
|
+
'// E.g. const storage = 10',
|
|
354
|
+
'',
|
|
355
|
+
'// For added type-safety, you can reference the type of your storage from the contract. This assumes that you have exported your `storage` type from the contract file.',
|
|
356
|
+
`// E.g. const storage : Contract.${module.moduleName}.storage = 10`,
|
|
357
|
+
];
|
|
358
|
+
break;
|
|
359
|
+
default:
|
|
360
|
+
return [];
|
|
361
|
+
}
|
|
362
|
+
})();
|
|
363
|
+
return linkToContract + instruction + syntax.join('\n');
|
|
216
364
|
};
|
|
217
365
|
|
|
218
|
-
const initContentForParameter = (
|
|
219
|
-
const linkToContract = `#
|
|
220
|
-
|
|
366
|
+
const initContentForParameter = (module: ModuleInfo): string => {
|
|
367
|
+
const linkToContract = `#import "${module.sourceFile}" "Contract"\n\n`;
|
|
221
368
|
const instruction = '// Define your parameter values as a list of LIGO variable definitions\n';
|
|
222
369
|
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
370
|
+
const syntax = (() => {
|
|
371
|
+
const pair = [module.syntax, module.type].join('-');
|
|
372
|
+
switch (pair) {
|
|
373
|
+
case 'mligo-file-main':
|
|
374
|
+
return [
|
|
375
|
+
'// When this file was created, the smart contract was defined with a main function that was not within a named module. As such, the examples below are written with that assumption in mind.',
|
|
376
|
+
'',
|
|
377
|
+
'// If your parameter is a simple value, you can define it directly',
|
|
378
|
+
'// E.g. let default_parameter = 10',
|
|
379
|
+
'',
|
|
380
|
+
'// For added type-safety, you can reference the type of your parameter from the contract',
|
|
381
|
+
'// E.g. let default_parameter : Contract.parameter = 10',
|
|
382
|
+
];
|
|
383
|
+
break;
|
|
384
|
+
case 'mligo-file-entry':
|
|
385
|
+
return [
|
|
386
|
+
'// When this file was created, the smart contract was defined with an entrypoint using `@entry` that was not within a named module. As such, the examples below are written with that assumption in mind.',
|
|
387
|
+
'',
|
|
388
|
+
'// If your parameter is a simple value, you can define it directly',
|
|
389
|
+
'// E.g. let default_parameter = 10',
|
|
390
|
+
'',
|
|
391
|
+
'// For added type-safety, you can reference the type of your parameter from the contract',
|
|
392
|
+
'// E.g. let default_parameter : parameter_of Contract = 10',
|
|
393
|
+
];
|
|
394
|
+
break;
|
|
395
|
+
case 'mligo-module-main':
|
|
396
|
+
return [
|
|
397
|
+
'// When this file was created, the smart contract was defined with a main function that was within a named module. As such, the examples below are written with that assumption in mind.',
|
|
398
|
+
'',
|
|
399
|
+
'// If your parameter is a simple value, you can define it directly',
|
|
400
|
+
'// E.g. let default_parameter = 10',
|
|
401
|
+
'',
|
|
402
|
+
'// For added type-safety, you can reference the type of your parameter from the contract',
|
|
403
|
+
`// E.g. let default_parameter : Contract.${module.moduleName}.parameter = 10`,
|
|
404
|
+
];
|
|
405
|
+
break;
|
|
406
|
+
case 'mligo-module-entry':
|
|
407
|
+
return [
|
|
408
|
+
'// When this file was created, the smart contract was defined with an entrypoint using `@entry` that was within a named module. As such, the examples below are written with that assumption in mind.',
|
|
409
|
+
'',
|
|
410
|
+
'// If your parameter is a simple value, you can define it directly',
|
|
411
|
+
'// E.g. let default_parameter = 10',
|
|
412
|
+
'',
|
|
413
|
+
'// For added type-safety, you can reference the type of your parameter from the contract',
|
|
414
|
+
`// E.g. let default_parameter : parameter_of Contract.${module.moduleName} = 10`,
|
|
415
|
+
];
|
|
416
|
+
break;
|
|
417
|
+
case 'jsligo-file-main':
|
|
418
|
+
return [
|
|
419
|
+
'// When this file was created, the smart contract was defined with a main function that was not within a namespace. As such, the examples below are written with that assumption in mind.',
|
|
420
|
+
`// NOTE: The "parameter" type should be exported from the contract file (${module.sourceFile})`,
|
|
421
|
+
'',
|
|
422
|
+
'// If your parameter is a simple value, you can define it directly',
|
|
423
|
+
'// E.g. const default_parameter = 10',
|
|
424
|
+
'',
|
|
425
|
+
'// For added type-safety, you can reference the type of your parameter from the contract',
|
|
426
|
+
'// E.g. const default_parameter : Contract.parameter = 10',
|
|
427
|
+
];
|
|
428
|
+
break;
|
|
429
|
+
case 'jsligo-file-entry':
|
|
430
|
+
return [
|
|
431
|
+
'// When this file was created, the smart contract was defined with an entrypoint using `@entry` that was not within a namespace. As such, the examples below are written with that assumption in mind.',
|
|
432
|
+
'',
|
|
433
|
+
'// If your parameter is a simple value, you can define it directly',
|
|
434
|
+
'// E.g. const default_parameter = 10',
|
|
435
|
+
'',
|
|
436
|
+
'// For added type-safety, you can reference the type of your parameter from the contract',
|
|
437
|
+
'// E.g. const default_parameter : parameter_of Contract = 10',
|
|
438
|
+
];
|
|
439
|
+
break;
|
|
440
|
+
case 'jsligo-module-main':
|
|
441
|
+
return [
|
|
442
|
+
'// When this file was created, the smart contract was defined with a main function that was within a namespace. As such, the examples below are written with that assumption in mind.',
|
|
443
|
+
`// NOTE: The "parameter" type should be exported from the contract file (${module.sourceFile})`,
|
|
444
|
+
'',
|
|
445
|
+
'// If your parameter is a simple value, you can define it directly',
|
|
446
|
+
'// E.g. const default_parameter = 10',
|
|
447
|
+
'',
|
|
448
|
+
'// For added type-safety, you can reference the type of your parameter from the contract',
|
|
449
|
+
`// E.g. const default_parameter : Contract.${module.moduleName}.parameter = 10`,
|
|
450
|
+
];
|
|
451
|
+
break;
|
|
452
|
+
case 'jsligo-module-entry':
|
|
453
|
+
return [
|
|
454
|
+
'// When this file was created, the smart contract was defined with an entrypoint using `@entry` that was within a namespace. As such, the examples below are written with that assumption in mind.',
|
|
455
|
+
'',
|
|
456
|
+
'// If your parameter is a simple value, you can define it directly',
|
|
457
|
+
'// E.g. const default_parameter = 10',
|
|
458
|
+
'',
|
|
459
|
+
'// For added type-safety, you can reference the type of your parameter from the contract',
|
|
460
|
+
`// E.g. const default_parameter : parameter_of Contract.${module.moduleName} = 10`,
|
|
461
|
+
];
|
|
462
|
+
break;
|
|
463
|
+
default:
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
})();
|
|
467
|
+
|
|
468
|
+
return linkToContract + instruction + syntax.join('\n');
|
|
231
469
|
};
|
|
232
470
|
|
|
233
471
|
export const compileContractWithStorageAndParameter = async (
|
|
234
472
|
parsedArgs: Opts,
|
|
235
473
|
sourceFile: string,
|
|
474
|
+
module: ModuleInfo,
|
|
236
475
|
): Promise<TableRow[]> => {
|
|
237
|
-
const contractCompileResult = await compileContract(parsedArgs, sourceFile);
|
|
476
|
+
const contractCompileResult = await compileContract(parsedArgs, sourceFile, module);
|
|
238
477
|
if (contractCompileResult.artifact === COMPILE_ERR_MSG) return [contractCompileResult];
|
|
239
478
|
|
|
240
|
-
const storageListFile = `${
|
|
479
|
+
const storageListFile = `${module.moduleName}.storageList${extractExt(sourceFile)}`;
|
|
241
480
|
const storageListFilename = getInputFilenameAbsPath(parsedArgs, storageListFile);
|
|
242
|
-
const storageCompileResult = await
|
|
243
|
-
.then(() => compileExprs(parsedArgs, storageListFile, 'storage'))
|
|
244
|
-
.catch(() => tryLegacyStorageNamingConvention(parsedArgs, sourceFile))
|
|
481
|
+
const storageCompileResult = await access(storageListFilename)
|
|
482
|
+
.then(() => compileExprs(parsedArgs, storageListFile, module, 'storage'))
|
|
245
483
|
.catch(() => {
|
|
246
484
|
sendWarn(
|
|
247
|
-
`Note: storage file associated with "${
|
|
485
|
+
`Note: storage file associated with "${module.moduleName}" can't be found, so "${storageListFile}" has been created for you. Use this file to define all initial storage values for this contract\n`,
|
|
248
486
|
);
|
|
249
|
-
writeFile(storageListFilename, initContentForStorage(
|
|
250
|
-
})
|
|
487
|
+
return writeFile(storageListFilename, initContentForStorage(module), 'utf8');
|
|
488
|
+
});
|
|
251
489
|
|
|
252
|
-
const parameterListFile = `${
|
|
490
|
+
const parameterListFile = `${module.moduleName}.parameterList${extractExt(sourceFile)}`;
|
|
253
491
|
const parameterListFilename = getInputFilenameAbsPath(parsedArgs, parameterListFile);
|
|
254
|
-
const parameterCompileResult = await
|
|
255
|
-
.then(() => compileExprs(parsedArgs, parameterListFile, 'parameter'))
|
|
256
|
-
.catch(() => tryLegacyParameterNamingConvention(parsedArgs, sourceFile))
|
|
492
|
+
const parameterCompileResult = await access(parameterListFilename)
|
|
493
|
+
.then(() => compileExprs(parsedArgs, parameterListFile, module, 'parameter'))
|
|
257
494
|
.catch(() => {
|
|
258
495
|
sendWarn(
|
|
259
|
-
`Note: parameter file associated with "${
|
|
496
|
+
`Note: parameter file associated with "${module.moduleName}" can't be found, so "${parameterListFile}" has been created for you. Use this file to define all parameter values for this contract\n`,
|
|
260
497
|
);
|
|
261
|
-
writeFile(parameterListFilename, initContentForParameter(
|
|
262
|
-
})
|
|
498
|
+
return writeFile(parameterListFilename, initContentForParameter(module), 'utf8');
|
|
499
|
+
});
|
|
263
500
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (parameterCompileResult) compileResults = compileResults.concat(parameterCompileResult);
|
|
267
|
-
return compileResults;
|
|
268
|
-
};
|
|
501
|
+
const storageArtifacts = storageCompileResult ? storageCompileResult.map(res => res.artifact).join('\n') : '';
|
|
502
|
+
const parameterArtifacts = parameterCompileResult ? parameterCompileResult.map(res => res.artifact).join('\n') : '';
|
|
269
503
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
├─────────────────────────┼─────────────────────────────────────────────┤
|
|
280
|
-
│ hello.storageList.mligo │ artifacts/hello.storage.storage2.tz │
|
|
281
|
-
└─────────────────────────┴─────────────────────────────────────────────┘
|
|
282
|
-
versus
|
|
283
|
-
┌─────────────────────────┬─────────────────────────────────────────────┐
|
|
284
|
-
│ Contract │ Artifact │
|
|
285
|
-
├─────────────────────────┼─────────────────────────────────────────────┤
|
|
286
|
-
│ hello.storageList.mligo │ artifacts/hello.default_storage.storage1.tz │
|
|
287
|
-
│ │ artifacts/hello.storage.storage2.tz │
|
|
288
|
-
└─────────────────────────┴─────────────────────────────────────────────┘
|
|
289
|
-
*/
|
|
290
|
-
const mergeArtifactsOutput = (sourceFile: string) =>
|
|
291
|
-
(tableRows: TableRow[]): TableRow[] => {
|
|
292
|
-
const artifactsOutput = tableRows.reduce(
|
|
293
|
-
(acc: string, row: TableRow) => row.artifact === COMPILE_ERR_MSG ? acc : `${acc}${row.artifact}\n`,
|
|
294
|
-
'',
|
|
295
|
-
);
|
|
296
|
-
return [{
|
|
297
|
-
contract: sourceFile,
|
|
298
|
-
artifact: artifactsOutput,
|
|
299
|
-
}];
|
|
504
|
+
const combinedArtifact = [
|
|
505
|
+
contractCompileResult.artifact,
|
|
506
|
+
storageArtifacts,
|
|
507
|
+
parameterArtifacts,
|
|
508
|
+
].filter(Boolean).join('\n');
|
|
509
|
+
|
|
510
|
+
const combinedRow: TableRow = {
|
|
511
|
+
source: module.sourceName,
|
|
512
|
+
artifact: combinedArtifact,
|
|
300
513
|
};
|
|
301
514
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
return
|
|
310
|
-
|
|
311
|
-
|
|
515
|
+
return [combinedRow];
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
export const compile = async (parsedArgs: Opts): Promise<void> => {
|
|
519
|
+
const sourceFile = parsedArgs.sourceFile;
|
|
520
|
+
if (!isLIGOFile(sourceFile)) {
|
|
521
|
+
sendErr(`${sourceFile} is not a LIGO file`);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
if (isStorageListFile(sourceFile) || isParameterListFile(sourceFile)) {
|
|
525
|
+
sendErr(`Storage and parameter list files are not meant to be compiled directly`);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
if (isUnsupportedLigoSyntax(sourceFile)) {
|
|
529
|
+
sendErr(`Unsupported LIGO syntax detected in ${sourceFile}. Note, we only support .jsligo and .mligo files.`);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
try {
|
|
534
|
+
const modules = await listContractModules(parsedArgs, sourceFile);
|
|
535
|
+
if (modules.length === 0) {
|
|
536
|
+
return sendJsonRes([
|
|
537
|
+
{
|
|
538
|
+
source: sourceFile,
|
|
539
|
+
artifact: `No contract modules found in "${sourceFile}"`,
|
|
540
|
+
},
|
|
541
|
+
]);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
let allCompileResults: TableRow[] = [];
|
|
545
|
+
for (const module of modules) {
|
|
546
|
+
// If we're only to compile a particular module, then we'll skip any that don't match
|
|
547
|
+
if (parsedArgs.module && parsedArgs.module !== module.moduleName) continue;
|
|
548
|
+
|
|
549
|
+
const compileResults = await compileContractWithStorageAndParameter(parsedArgs, sourceFile, module);
|
|
550
|
+
allCompileResults = allCompileResults.concat(compileResults);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
sendJsonRes(allCompileResults, { footer: `\nCompiled ${allCompileResults.length} contract(s) in "${sourceFile}"` });
|
|
554
|
+
} catch (err) {
|
|
555
|
+
sendErr(`Error processing "${sourceFile}": ${err}`);
|
|
312
556
|
}
|
|
313
|
-
return p.then(sendJsonRes).catch(err => sendErr(err, false));
|
|
314
557
|
};
|
|
315
558
|
|
|
316
559
|
export default compile;
|
|
317
|
-
export const ___TEST___ = {
|
|
318
|
-
getContractNameForExpr,
|
|
319
|
-
getOutputExprFilename,
|
|
320
|
-
};
|