forked from tact-lang/tact
-
Notifications
You must be signed in to change notification settings - Fork 0
/
node.ts
146 lines (130 loc) · 4.26 KB
/
node.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import path from "path";
import fs from "fs";
import { ConfigProject, Config, parseConfig } from "./config/parseConfig";
import { createNodeFileSystem } from "./vfs/createNodeFileSystem";
import { build } from "./pipeline/build";
import { LogLevel, Logger } from "./logger";
import { TactErrorCollection } from "./errors";
type AdditionalCliOptions = {
mode?: ConfigProject["mode"];
};
type ConfigWithRootPath = Config & {
rootPath: string;
singleFile: boolean;
};
function configForSingleFile(fileName: string): ConfigWithRootPath {
return {
projects: [
{
name: path.basename(fileName, ".tact"),
path: fileName,
output: path.dirname(fileName),
options: {
debug: true,
external: true,
ipfsAbiGetter: false,
interfacesGetter: false,
},
mode: "full",
},
],
rootPath: process.cwd(),
singleFile: true,
};
}
function loadConfig(
fileName?: string,
configPath?: string,
): ConfigWithRootPath | null {
if (fileName) return configForSingleFile(fileName);
if (!configPath) return null;
let config: Config;
// Load config
const resolvedPath = path.resolve(configPath);
const rootPath = path.dirname(resolvedPath);
if (!fs.existsSync(resolvedPath)) {
console.warn("Unable to find config file at " + resolvedPath);
return null;
}
try {
config = parseConfig(fs.readFileSync(resolvedPath, "utf8"));
} catch (e) {
console.log(e);
console.warn("Unable to parse config file at " + resolvedPath);
return null;
}
return { singleFile: false, rootPath, ...config };
}
export async function run(args: {
fileName?: string;
configPath?: string;
projectNames?: string[];
additionalCliOptions?: AdditionalCliOptions;
suppressLog?: boolean;
}) {
const configWithRootPath = await loadConfig(args.fileName, args.configPath);
if (!configWithRootPath) {
return {
ok: false,
error: [
new Error(
`Unable to load config from path: ${args.configPath}`,
),
],
};
}
const logger = new Logger(args.suppressLog ? LogLevel.NONE : LogLevel.INFO);
// Resolve projects
let projects = configWithRootPath.projects;
if (args.projectNames && args.projectNames.length > 0) {
// Check that all project names are valid
for (const pp of args.projectNames) {
if (!projects.find((v) => v.name === pp)) {
const message = "Unable to find project " + pp;
logger.warn(message);
return {
ok: false,
error: [new Error(message)],
};
}
}
// Filter by names
projects = projects.filter((v) => args.projectNames!.includes(v.name));
}
if (projects.length === 0) {
const message = "No projects to compile";
console.warn(message);
return { ok: false, error: [new Error(message)] };
}
// Compile
let success = true;
let errorMessages: TactErrorCollection[] = [];
const project = createNodeFileSystem(
configWithRootPath.rootPath as string,
false,
);
const stdlib = createNodeFileSystem(
path.resolve(__dirname, "..", "stdlib"),
false,
); // Improves developer experience
for (const config of projects) {
logger.info(`💼 Compiling project ${config.name} ...`);
let cliConfig = { ...config };
if (args.additionalCliOptions?.mode !== undefined) {
cliConfig = { ...config, ...args.additionalCliOptions };
}
const built = await build({
config: cliConfig,
project,
stdlib,
logger,
});
success = success && built.ok;
if (!built.ok && built.error.length > 0) {
errorMessages = [...errorMessages, ...built.error];
}
}
return { ok: success, error: errorMessages };
}
export { createNodeFileSystem } from "./vfs/createNodeFileSystem";
export { parseAndEvalExpression } from "./interpreter";