@sdeverywhere/build 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/index.cjs +724 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +435 -0
- package/dist/index.js +698 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
9
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
10
|
+
var __spreadValues = (a, b) => {
|
|
11
|
+
for (var prop in b || (b = {}))
|
|
12
|
+
if (__hasOwnProp.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
if (__getOwnPropSymbols)
|
|
15
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
16
|
+
if (__propIsEnum.call(b, prop))
|
|
17
|
+
__defNormalProp(a, prop, b[prop]);
|
|
18
|
+
}
|
|
19
|
+
return a;
|
|
20
|
+
};
|
|
21
|
+
var __export = (target, all) => {
|
|
22
|
+
for (var name in all)
|
|
23
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
24
|
+
};
|
|
25
|
+
var __copyProps = (to, from, except, desc) => {
|
|
26
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
27
|
+
for (let key of __getOwnPropNames(from))
|
|
28
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
29
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
30
|
+
}
|
|
31
|
+
return to;
|
|
32
|
+
};
|
|
33
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
|
|
34
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
35
|
+
|
|
36
|
+
// src/index.ts
|
|
37
|
+
var src_exports = {};
|
|
38
|
+
__export(src_exports, {
|
|
39
|
+
build: () => build
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(src_exports);
|
|
42
|
+
|
|
43
|
+
// src/build/build.ts
|
|
44
|
+
var import_path7 = require("path");
|
|
45
|
+
var import_neverthrow3 = require("neverthrow");
|
|
46
|
+
|
|
47
|
+
// src/config/config-loader.ts
|
|
48
|
+
var import_fs = require("fs");
|
|
49
|
+
var import_path = require("path");
|
|
50
|
+
var import_url = require("url");
|
|
51
|
+
var import_neverthrow = require("neverthrow");
|
|
52
|
+
async function loadConfig(mode, config, sdeDir, sdeCmdPath) {
|
|
53
|
+
let userConfig;
|
|
54
|
+
if (typeof config === "object") {
|
|
55
|
+
userConfig = config;
|
|
56
|
+
} else {
|
|
57
|
+
let configPath;
|
|
58
|
+
if (typeof config === "string") {
|
|
59
|
+
configPath = config;
|
|
60
|
+
} else {
|
|
61
|
+
configPath = (0, import_path.join)(process.cwd(), "sde.config.js");
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
if (!(0, import_fs.existsSync)(configPath)) {
|
|
65
|
+
return (0, import_neverthrow.err)(new Error(`Cannot find config file '${configPath}'`));
|
|
66
|
+
}
|
|
67
|
+
const configUrl = (0, import_url.pathToFileURL)(configPath).toString();
|
|
68
|
+
const configModule = await import(configUrl);
|
|
69
|
+
userConfig = await configModule.config();
|
|
70
|
+
} catch (e) {
|
|
71
|
+
return (0, import_neverthrow.err)(new Error(`Failed to load config file '${configPath}': ${e.message}`));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const resolvedConfig = resolveUserConfig(userConfig, mode, sdeDir, sdeCmdPath);
|
|
76
|
+
return (0, import_neverthrow.ok)({
|
|
77
|
+
userConfig,
|
|
78
|
+
resolvedConfig
|
|
79
|
+
});
|
|
80
|
+
} catch (e) {
|
|
81
|
+
return (0, import_neverthrow.err)(e);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function resolveUserConfig(userConfig, mode, sdeDir, sdeCmdPath) {
|
|
85
|
+
function expectDirectory(propName, path) {
|
|
86
|
+
if (!(0, import_fs.existsSync)(path)) {
|
|
87
|
+
throw new Error(`The configured ${propName} (${path}) does not exist`);
|
|
88
|
+
} else if (!(0, import_fs.lstatSync)(path).isDirectory()) {
|
|
89
|
+
throw new Error(`The configured ${propName} (${path}) is not a directory`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
let rootDir;
|
|
93
|
+
if (userConfig.rootDir) {
|
|
94
|
+
rootDir = (0, import_path.resolve)(userConfig.rootDir);
|
|
95
|
+
expectDirectory("rootDir", rootDir);
|
|
96
|
+
} else {
|
|
97
|
+
rootDir = process.cwd();
|
|
98
|
+
}
|
|
99
|
+
let prepDir;
|
|
100
|
+
if (userConfig.prepDir) {
|
|
101
|
+
prepDir = (0, import_path.resolve)(userConfig.prepDir);
|
|
102
|
+
} else {
|
|
103
|
+
prepDir = (0, import_path.resolve)(rootDir, "sde-prep");
|
|
104
|
+
}
|
|
105
|
+
(0, import_fs.mkdirSync)(prepDir, { recursive: true });
|
|
106
|
+
const userModelFiles = userConfig.modelFiles;
|
|
107
|
+
const modelFiles = [];
|
|
108
|
+
for (const userModelFile of userModelFiles) {
|
|
109
|
+
const modelFile = (0, import_path.resolve)(userModelFile);
|
|
110
|
+
if (!(0, import_fs.existsSync)(modelFile)) {
|
|
111
|
+
throw new Error(`The configured model file (${modelFile}) does not exist`);
|
|
112
|
+
}
|
|
113
|
+
modelFiles.push(modelFile);
|
|
114
|
+
}
|
|
115
|
+
let modelInputPaths;
|
|
116
|
+
if (userConfig.modelInputPaths && userConfig.modelInputPaths.length > 0) {
|
|
117
|
+
modelInputPaths = userConfig.modelInputPaths;
|
|
118
|
+
} else {
|
|
119
|
+
modelInputPaths = modelFiles;
|
|
120
|
+
}
|
|
121
|
+
let watchPaths;
|
|
122
|
+
if (userConfig.watchPaths && userConfig.watchPaths.length > 0) {
|
|
123
|
+
watchPaths = userConfig.watchPaths;
|
|
124
|
+
} else {
|
|
125
|
+
watchPaths = modelFiles;
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
mode,
|
|
129
|
+
rootDir,
|
|
130
|
+
prepDir,
|
|
131
|
+
modelFiles,
|
|
132
|
+
modelInputPaths,
|
|
133
|
+
watchPaths,
|
|
134
|
+
sdeDir,
|
|
135
|
+
sdeCmdPath
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/_shared/log.ts
|
|
140
|
+
var import_fs2 = require("fs");
|
|
141
|
+
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
142
|
+
var activeLevels = /* @__PURE__ */ new Set(["error", "info"]);
|
|
143
|
+
var overlayFile;
|
|
144
|
+
var overlayEnabled = false;
|
|
145
|
+
var overlayHtml = "";
|
|
146
|
+
function setActiveLevels(logLevels) {
|
|
147
|
+
activeLevels.clear();
|
|
148
|
+
for (const level of logLevels) {
|
|
149
|
+
activeLevels.add(level);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function setOverlayFile(file, enabled) {
|
|
153
|
+
overlayFile = file;
|
|
154
|
+
overlayEnabled = enabled;
|
|
155
|
+
(0, import_fs2.writeFileSync)(overlayFile, "");
|
|
156
|
+
}
|
|
157
|
+
function log(level, msg) {
|
|
158
|
+
if (activeLevels.has(level)) {
|
|
159
|
+
if (level === "error") {
|
|
160
|
+
console.error(import_picocolors.default.red(msg));
|
|
161
|
+
logToOverlay(msg);
|
|
162
|
+
} else {
|
|
163
|
+
console.log(msg);
|
|
164
|
+
logToOverlay(msg);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function logError(e) {
|
|
169
|
+
const stack = e.stack || "";
|
|
170
|
+
const stackLines = stack.split("\n").filter((s) => s.match(/^\s+at/));
|
|
171
|
+
const trace = stackLines.slice(0, 3).join("\n");
|
|
172
|
+
console.error(import_picocolors.default.red(`
|
|
173
|
+
ERROR: ${e.message}`));
|
|
174
|
+
console.error(import_picocolors.default.dim(import_picocolors.default.red(`${trace}
|
|
175
|
+
`)));
|
|
176
|
+
logToOverlay(`
|
|
177
|
+
ERROR: ${e.message}`, true);
|
|
178
|
+
logToOverlay(`${trace}
|
|
179
|
+
`, true);
|
|
180
|
+
}
|
|
181
|
+
function writeOverlayFiles() {
|
|
182
|
+
(0, import_fs2.writeFileSync)(overlayFile, overlayHtml);
|
|
183
|
+
}
|
|
184
|
+
function clearOverlay() {
|
|
185
|
+
if (!overlayEnabled) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
overlayHtml = "";
|
|
189
|
+
writeOverlayFiles();
|
|
190
|
+
}
|
|
191
|
+
var indent = " ".repeat(4);
|
|
192
|
+
function logToOverlay(msg, error = false) {
|
|
193
|
+
if (!overlayEnabled) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (error) {
|
|
197
|
+
msg = `<span class="overlay-error">${msg}</span>`;
|
|
198
|
+
}
|
|
199
|
+
const msgHtml = msg.replace(/\n/g, "\n<br/>").replace(/\s{2}/g, indent);
|
|
200
|
+
if (overlayHtml) {
|
|
201
|
+
overlayHtml += `<br/>${msgHtml}`;
|
|
202
|
+
} else {
|
|
203
|
+
overlayHtml = `${msgHtml}`;
|
|
204
|
+
}
|
|
205
|
+
writeOverlayFiles();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/build/impl/build-once.ts
|
|
209
|
+
var import_fs4 = require("fs");
|
|
210
|
+
var import_promises2 = require("fs/promises");
|
|
211
|
+
var import_path5 = require("path");
|
|
212
|
+
var import_neverthrow2 = require("neverthrow");
|
|
213
|
+
|
|
214
|
+
// src/context/spawn-child.ts
|
|
215
|
+
var import_cross_spawn = require("cross-spawn");
|
|
216
|
+
function spawnChild(cwd, command, args, abortSignal, opts) {
|
|
217
|
+
return new Promise((resolve, reject) => {
|
|
218
|
+
if (abortSignal == null ? void 0 : abortSignal.aborted) {
|
|
219
|
+
reject(new Error("ABORT"));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
let childProc;
|
|
223
|
+
const localLog = (s, err4 = false) => {
|
|
224
|
+
if (childProc === void 0) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
log(err4 ? "error" : "info", s);
|
|
228
|
+
};
|
|
229
|
+
const abortHandler = () => {
|
|
230
|
+
if (childProc) {
|
|
231
|
+
log("info", "Killing existing build process...");
|
|
232
|
+
childProc.kill("SIGKILL");
|
|
233
|
+
childProc = void 0;
|
|
234
|
+
}
|
|
235
|
+
reject(new Error("ABORT"));
|
|
236
|
+
};
|
|
237
|
+
abortSignal == null ? void 0 : abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
238
|
+
const stdoutMessages = [];
|
|
239
|
+
const stderrMessages = [];
|
|
240
|
+
const logMessage = (msg, err4) => {
|
|
241
|
+
let includeMessage = true;
|
|
242
|
+
if ((opts == null ? void 0 : opts.ignoredMessageFilter) && msg.trim().startsWith(opts.ignoredMessageFilter)) {
|
|
243
|
+
includeMessage = false;
|
|
244
|
+
}
|
|
245
|
+
if (includeMessage) {
|
|
246
|
+
const lines = msg.trim().split("\n");
|
|
247
|
+
for (const line of lines) {
|
|
248
|
+
localLog(` ${line}`, err4);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
childProc = (0, import_cross_spawn.spawn)(command, args, {
|
|
253
|
+
cwd
|
|
254
|
+
});
|
|
255
|
+
childProc.stdout.on("data", (data) => {
|
|
256
|
+
const msg = data.toString();
|
|
257
|
+
if ((opts == null ? void 0 : opts.captureOutput) === true) {
|
|
258
|
+
stdoutMessages.push(msg);
|
|
259
|
+
}
|
|
260
|
+
if ((opts == null ? void 0 : opts.logOutput) !== false) {
|
|
261
|
+
logMessage(msg, false);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
childProc.stderr.on("data", (data) => {
|
|
265
|
+
const msg = data.toString();
|
|
266
|
+
if ((opts == null ? void 0 : opts.captureOutput) === true) {
|
|
267
|
+
stderrMessages.push(msg);
|
|
268
|
+
}
|
|
269
|
+
if ((opts == null ? void 0 : opts.logOutput) !== false) {
|
|
270
|
+
logMessage(msg, true);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
childProc.on("error", (err4) => {
|
|
274
|
+
localLog(`Process error: ${err4}`, true);
|
|
275
|
+
});
|
|
276
|
+
childProc.on("close", (code, signal) => {
|
|
277
|
+
abortSignal == null ? void 0 : abortSignal.removeEventListener("abort", abortHandler);
|
|
278
|
+
childProc = void 0;
|
|
279
|
+
if (signal) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const processOutput = {
|
|
283
|
+
exitCode: code,
|
|
284
|
+
stdoutMessages,
|
|
285
|
+
stderrMessages
|
|
286
|
+
};
|
|
287
|
+
if (code === 0) {
|
|
288
|
+
resolve(processOutput);
|
|
289
|
+
} else if (!signal) {
|
|
290
|
+
if ((opts == null ? void 0 : opts.ignoreError) === true) {
|
|
291
|
+
resolve(processOutput);
|
|
292
|
+
} else {
|
|
293
|
+
reject(new Error(`Child process failed (code=${code})`));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/context/context.ts
|
|
301
|
+
var BuildContext = class {
|
|
302
|
+
constructor(config, stagedFiles, abortSignal) {
|
|
303
|
+
this.config = config;
|
|
304
|
+
this.stagedFiles = stagedFiles;
|
|
305
|
+
this.abortSignal = abortSignal;
|
|
306
|
+
}
|
|
307
|
+
log(level, msg) {
|
|
308
|
+
log(level, msg);
|
|
309
|
+
}
|
|
310
|
+
prepareStagedFile(srcDir, srcFile, dstDir, dstFile) {
|
|
311
|
+
return this.stagedFiles.prepareStagedFile(srcDir, srcFile, dstDir, dstFile);
|
|
312
|
+
}
|
|
313
|
+
writeStagedFile(srcDir, dstDir, filename, content) {
|
|
314
|
+
this.stagedFiles.writeStagedFile(srcDir, dstDir, filename, content);
|
|
315
|
+
}
|
|
316
|
+
spawnChild(cwd, command, args, opts) {
|
|
317
|
+
return spawnChild(cwd, command, args, this.abortSignal, opts);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// src/context/staged-files.ts
|
|
322
|
+
var import_fs3 = require("fs");
|
|
323
|
+
var import_path2 = require("path");
|
|
324
|
+
var StagedFiles = class {
|
|
325
|
+
constructor(prepDir) {
|
|
326
|
+
this.stagedFiles = [];
|
|
327
|
+
this.baseStagedDir = (0, import_path2.join)(prepDir, "staged");
|
|
328
|
+
}
|
|
329
|
+
prepareStagedFile(srcDir, srcFile, dstDir, dstFile) {
|
|
330
|
+
const stagedFile = {
|
|
331
|
+
srcDir,
|
|
332
|
+
srcFile,
|
|
333
|
+
dstDir,
|
|
334
|
+
dstFile
|
|
335
|
+
};
|
|
336
|
+
if (this.stagedFiles.indexOf(stagedFile) < 0) {
|
|
337
|
+
this.stagedFiles.push(stagedFile);
|
|
338
|
+
}
|
|
339
|
+
const stagedDir = (0, import_path2.join)(this.baseStagedDir, srcDir);
|
|
340
|
+
if (!(0, import_fs3.existsSync)(stagedDir)) {
|
|
341
|
+
(0, import_fs3.mkdirSync)(stagedDir, { recursive: true });
|
|
342
|
+
}
|
|
343
|
+
return (0, import_path2.join)(stagedDir, srcFile);
|
|
344
|
+
}
|
|
345
|
+
writeStagedFile(srcDir, dstDir, filename, content) {
|
|
346
|
+
const stagedFilePath = this.prepareStagedFile(srcDir, filename, dstDir, filename);
|
|
347
|
+
(0, import_fs3.writeFileSync)(stagedFilePath, content);
|
|
348
|
+
}
|
|
349
|
+
getStagedFilePath(srcDir, srcFile) {
|
|
350
|
+
return (0, import_path2.join)(this.baseStagedDir, srcDir, srcFile);
|
|
351
|
+
}
|
|
352
|
+
stagedFileExists(srcDir, srcFile) {
|
|
353
|
+
const fullSrcPath = this.getStagedFilePath(srcDir, srcFile);
|
|
354
|
+
return (0, import_fs3.existsSync)(fullSrcPath);
|
|
355
|
+
}
|
|
356
|
+
destinationFileExists(srcDir, srcFile) {
|
|
357
|
+
const f = this.stagedFiles.find((f2) => f2.srcDir === srcDir && f2.srcFile === srcFile);
|
|
358
|
+
if (f === void 0) {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
const fullDstPath = (0, import_path2.join)(f.dstDir, f.dstFile);
|
|
362
|
+
return (0, import_fs3.existsSync)(fullDstPath);
|
|
363
|
+
}
|
|
364
|
+
copyChangedFiles() {
|
|
365
|
+
log("info", "Copying changed files into place...");
|
|
366
|
+
for (const f of this.stagedFiles) {
|
|
367
|
+
this.copyStagedFile(f);
|
|
368
|
+
}
|
|
369
|
+
log("info", "Done copying files");
|
|
370
|
+
}
|
|
371
|
+
copyStagedFile(f) {
|
|
372
|
+
if (!(0, import_fs3.existsSync)(f.dstDir)) {
|
|
373
|
+
(0, import_fs3.mkdirSync)(f.dstDir, { recursive: true });
|
|
374
|
+
}
|
|
375
|
+
const fullSrcPath = this.getStagedFilePath(f.srcDir, f.srcFile);
|
|
376
|
+
const fullDstPath = (0, import_path2.join)(f.dstDir, f.dstFile);
|
|
377
|
+
const needsCopy = filesDiffer(fullSrcPath, fullDstPath);
|
|
378
|
+
if (needsCopy) {
|
|
379
|
+
log("verbose", ` Copying ${f.srcFile} to ${fullDstPath}`);
|
|
380
|
+
(0, import_fs3.copyFileSync)(fullSrcPath, fullDstPath);
|
|
381
|
+
}
|
|
382
|
+
return needsCopy;
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
function filesDiffer(aPath, bPath) {
|
|
386
|
+
if ((0, import_fs3.existsSync)(aPath) && (0, import_fs3.existsSync)(bPath)) {
|
|
387
|
+
const aSize = (0, import_fs3.statSync)(aPath).size;
|
|
388
|
+
const bSize = (0, import_fs3.statSync)(bPath).size;
|
|
389
|
+
if (aSize !== bSize) {
|
|
390
|
+
return true;
|
|
391
|
+
} else {
|
|
392
|
+
const aBuf = (0, import_fs3.readFileSync)(aPath);
|
|
393
|
+
const bBuf = (0, import_fs3.readFileSync)(bPath);
|
|
394
|
+
return !aBuf.equals(bBuf);
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// src/build/impl/gen-model.ts
|
|
402
|
+
var import_promises = require("fs/promises");
|
|
403
|
+
var import_path3 = require("path");
|
|
404
|
+
async function generateModel(context, plugins) {
|
|
405
|
+
log("info", "Generating model...");
|
|
406
|
+
const t0 = performance.now();
|
|
407
|
+
const config = context.config;
|
|
408
|
+
const prepDir = config.prepDir;
|
|
409
|
+
const isWin = process.platform === "win32";
|
|
410
|
+
const sdeCmdPath = isWin ? `${config.sdeCmdPath}.cmd` : config.sdeCmdPath;
|
|
411
|
+
for (const plugin of plugins) {
|
|
412
|
+
if (plugin.preProcessMdl) {
|
|
413
|
+
await plugin.preProcessMdl(context);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (config.modelFiles.length === 0) {
|
|
417
|
+
throw new Error("No model input files specified");
|
|
418
|
+
} else if (config.modelFiles.length === 1) {
|
|
419
|
+
await preprocessMdl(context, sdeCmdPath, prepDir, config.modelFiles[0]);
|
|
420
|
+
} else {
|
|
421
|
+
await flattenMdls(context, sdeCmdPath, prepDir, config.modelFiles);
|
|
422
|
+
}
|
|
423
|
+
for (const plugin of plugins) {
|
|
424
|
+
if (plugin.postProcessMdl) {
|
|
425
|
+
const mdlPath = (0, import_path3.join)(prepDir, "processed.mdl");
|
|
426
|
+
let mdlContent = await (0, import_promises.readFile)(mdlPath, "utf8");
|
|
427
|
+
mdlContent = await plugin.postProcessMdl(context, mdlContent);
|
|
428
|
+
await (0, import_promises.writeFile)(mdlPath, mdlContent);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
for (const plugin of plugins) {
|
|
432
|
+
if (plugin.preGenerateC) {
|
|
433
|
+
await plugin.preGenerateC(context);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
await generateC(context, config.sdeDir, sdeCmdPath, prepDir);
|
|
437
|
+
for (const plugin of plugins) {
|
|
438
|
+
if (plugin.postGenerateC) {
|
|
439
|
+
const cPath = (0, import_path3.join)(prepDir, "build", "processed.c");
|
|
440
|
+
let cContent = await (0, import_promises.readFile)(cPath, "utf8");
|
|
441
|
+
cContent = await plugin.postGenerateC(context, cContent);
|
|
442
|
+
await (0, import_promises.writeFile)(cPath, cContent);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
const t1 = performance.now();
|
|
446
|
+
const elapsed = ((t1 - t0) / 1e3).toFixed(1);
|
|
447
|
+
log("info", `Done generating model (${elapsed}s)`);
|
|
448
|
+
}
|
|
449
|
+
async function preprocessMdl(context, sdeCmdPath, prepDir, modelFile) {
|
|
450
|
+
log("verbose", " Preprocessing mdl file");
|
|
451
|
+
await (0, import_promises.copyFile)(modelFile, (0, import_path3.join)(prepDir, "processed.mdl"));
|
|
452
|
+
const command = sdeCmdPath;
|
|
453
|
+
const args = ["generate", "--preprocess", "processed.mdl"];
|
|
454
|
+
await context.spawnChild(prepDir, command, args);
|
|
455
|
+
await (0, import_promises.copyFile)((0, import_path3.join)(prepDir, "build", "processed.mdl"), (0, import_path3.join)(prepDir, "processed.mdl"));
|
|
456
|
+
}
|
|
457
|
+
async function flattenMdls(context, sdeCmdPath, prepDir, modelFiles) {
|
|
458
|
+
log("verbose", " Flattening and preprocessing mdl files");
|
|
459
|
+
const command = sdeCmdPath;
|
|
460
|
+
const args = [];
|
|
461
|
+
args.push("flatten");
|
|
462
|
+
args.push("processed.mdl");
|
|
463
|
+
args.push("--inputs");
|
|
464
|
+
for (const path of modelFiles) {
|
|
465
|
+
args.push(path);
|
|
466
|
+
}
|
|
467
|
+
const output = await context.spawnChild(prepDir, command, args, {
|
|
468
|
+
logOutput: false,
|
|
469
|
+
captureOutput: true,
|
|
470
|
+
ignoreError: true
|
|
471
|
+
});
|
|
472
|
+
let flattenErrors = false;
|
|
473
|
+
for (const msg of output.stderrMessages) {
|
|
474
|
+
if (msg.includes("ERROR")) {
|
|
475
|
+
flattenErrors = true;
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (flattenErrors) {
|
|
480
|
+
log("error", "There were errors reported when flattening the model:");
|
|
481
|
+
for (const msg of output.stderrMessages) {
|
|
482
|
+
const lines = msg.split("\n");
|
|
483
|
+
for (const line of lines) {
|
|
484
|
+
log("error", ` ${line}`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
throw new Error(`Flatten command failed (code=${output.exitCode})`);
|
|
488
|
+
} else if (output.exitCode !== 0) {
|
|
489
|
+
throw new Error(`Flatten command failed (code=${output.exitCode})`);
|
|
490
|
+
}
|
|
491
|
+
await (0, import_promises.copyFile)((0, import_path3.join)(prepDir, "build", "processed.mdl"), (0, import_path3.join)(prepDir, "processed.mdl"));
|
|
492
|
+
}
|
|
493
|
+
async function generateC(context, sdeDir, sdeCmdPath, prepDir) {
|
|
494
|
+
log("verbose", " Generating C code");
|
|
495
|
+
const command = sdeCmdPath;
|
|
496
|
+
const args = ["generate", "--genc", "--spec", "spec.json", "processed"];
|
|
497
|
+
await context.spawnChild(prepDir, command, args, {});
|
|
498
|
+
const buildDir = (0, import_path3.join)(prepDir, "build");
|
|
499
|
+
const sdeCDir = (0, import_path3.join)(sdeDir, "src", "c");
|
|
500
|
+
const files = await (0, import_promises.readdir)(sdeCDir);
|
|
501
|
+
const copyOps = [];
|
|
502
|
+
for (const file of files) {
|
|
503
|
+
if (file.endsWith(".c") || file.endsWith(".h")) {
|
|
504
|
+
copyOps.push((0, import_promises.copyFile)((0, import_path3.join)(sdeCDir, file), (0, import_path3.join)(buildDir, file)));
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
await Promise.all(copyOps);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/build/impl/hash-files.ts
|
|
511
|
+
var import_path4 = require("path");
|
|
512
|
+
var import_folder_hash = require("folder-hash");
|
|
513
|
+
var import_tiny_glob = __toESM(require("tiny-glob"), 1);
|
|
514
|
+
async function computeInputFilesHash(config) {
|
|
515
|
+
const inputFiles = [];
|
|
516
|
+
const specFile = (0, import_path4.join)(config.prepDir, "spec.json");
|
|
517
|
+
inputFiles.push(specFile);
|
|
518
|
+
if (config.modelInputPaths && config.modelInputPaths.length > 0) {
|
|
519
|
+
for (const globPath of config.modelInputPaths) {
|
|
520
|
+
const paths = await (0, import_tiny_glob.default)(globPath, {
|
|
521
|
+
cwd: config.rootDir,
|
|
522
|
+
absolute: true,
|
|
523
|
+
filesOnly: true
|
|
524
|
+
});
|
|
525
|
+
inputFiles.push(...paths);
|
|
526
|
+
}
|
|
527
|
+
} else {
|
|
528
|
+
inputFiles.push(...config.modelFiles);
|
|
529
|
+
}
|
|
530
|
+
let hash = "";
|
|
531
|
+
for (const inputFile of inputFiles) {
|
|
532
|
+
const result = await (0, import_folder_hash.hashElement)(inputFile);
|
|
533
|
+
hash += result.hash;
|
|
534
|
+
}
|
|
535
|
+
return hash;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/build/impl/build-once.ts
|
|
539
|
+
async function buildOnce(config, userConfig, plugins, options) {
|
|
540
|
+
const stagedFiles = new StagedFiles(config.prepDir);
|
|
541
|
+
const context = new BuildContext(config, stagedFiles, options.abortSignal);
|
|
542
|
+
let modelSpec;
|
|
543
|
+
try {
|
|
544
|
+
modelSpec = await userConfig.modelSpec(context);
|
|
545
|
+
if (modelSpec === void 0) {
|
|
546
|
+
return (0, import_neverthrow2.err)(new Error("The model spec must be defined"));
|
|
547
|
+
}
|
|
548
|
+
} catch (e) {
|
|
549
|
+
return (0, import_neverthrow2.err)(e);
|
|
550
|
+
}
|
|
551
|
+
for (const plugin of plugins) {
|
|
552
|
+
if (plugin.preGenerate) {
|
|
553
|
+
plugin.preGenerate(context, modelSpec);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
const specJson = __spreadValues({
|
|
557
|
+
inputVarNames: modelSpec.inputs.map((input) => input.varName),
|
|
558
|
+
outputVarNames: modelSpec.outputs.map((output) => output.varName),
|
|
559
|
+
externalDatfiles: modelSpec.datFiles
|
|
560
|
+
}, modelSpec.options);
|
|
561
|
+
const specPath = (0, import_path5.join)(config.prepDir, "spec.json");
|
|
562
|
+
await (0, import_promises2.writeFile)(specPath, JSON.stringify(specJson, null, 2));
|
|
563
|
+
const modelHashPath = (0, import_path5.join)(config.prepDir, "model-hash.txt");
|
|
564
|
+
let previousModelHash;
|
|
565
|
+
if ((0, import_fs4.existsSync)(modelHashPath)) {
|
|
566
|
+
previousModelHash = (0, import_fs4.readFileSync)(modelHashPath, "utf8");
|
|
567
|
+
} else {
|
|
568
|
+
previousModelHash = "NONE";
|
|
569
|
+
}
|
|
570
|
+
const inputFilesHash = await computeInputFilesHash(config);
|
|
571
|
+
let needModelGen;
|
|
572
|
+
if (options.forceModelGen === true) {
|
|
573
|
+
needModelGen = true;
|
|
574
|
+
} else {
|
|
575
|
+
const hashMismatch = inputFilesHash !== previousModelHash;
|
|
576
|
+
needModelGen = hashMismatch;
|
|
577
|
+
}
|
|
578
|
+
let succeeded = true;
|
|
579
|
+
try {
|
|
580
|
+
if (needModelGen) {
|
|
581
|
+
await generateModel(context, plugins);
|
|
582
|
+
(0, import_fs4.writeFileSync)(modelHashPath, inputFilesHash);
|
|
583
|
+
} else {
|
|
584
|
+
log("info", "Skipping model code generation; already up-to-date");
|
|
585
|
+
}
|
|
586
|
+
for (const plugin of plugins) {
|
|
587
|
+
if (plugin.postGenerate) {
|
|
588
|
+
const pluginSucceeded = await plugin.postGenerate(context, modelSpec);
|
|
589
|
+
if (!pluginSucceeded) {
|
|
590
|
+
succeeded = false;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
stagedFiles.copyChangedFiles();
|
|
595
|
+
for (const plugin of plugins) {
|
|
596
|
+
if (plugin.postBuild) {
|
|
597
|
+
const pluginSucceeded = await plugin.postBuild(context, modelSpec);
|
|
598
|
+
if (!pluginSucceeded) {
|
|
599
|
+
succeeded = false;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
if (config.mode === "development") {
|
|
604
|
+
log("info", "Waiting for changes...\n");
|
|
605
|
+
clearOverlay();
|
|
606
|
+
}
|
|
607
|
+
} catch (e) {
|
|
608
|
+
if (e.message !== "ABORT") {
|
|
609
|
+
(0, import_fs4.writeFileSync)(modelHashPath, "");
|
|
610
|
+
return (0, import_neverthrow2.err)(e);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return (0, import_neverthrow2.ok)(succeeded);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// src/build/impl/watch.ts
|
|
617
|
+
var import_path6 = require("path");
|
|
618
|
+
var import_chokidar = __toESM(require("chokidar"), 1);
|
|
619
|
+
var BuildState = class {
|
|
620
|
+
constructor() {
|
|
621
|
+
this.abortController = new AbortController();
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
function watch(config, userConfig, plugins) {
|
|
625
|
+
const delay = 150;
|
|
626
|
+
const changedPaths = /* @__PURE__ */ new Set();
|
|
627
|
+
let currentBuildState;
|
|
628
|
+
function performBuild() {
|
|
629
|
+
clearOverlay();
|
|
630
|
+
for (const path of changedPaths) {
|
|
631
|
+
log("info", `Input file ${(0, import_path6.basename)(path)} has been changed`);
|
|
632
|
+
}
|
|
633
|
+
changedPaths.clear();
|
|
634
|
+
if (currentBuildState) {
|
|
635
|
+
currentBuildState.abortController.abort();
|
|
636
|
+
currentBuildState = void 0;
|
|
637
|
+
}
|
|
638
|
+
currentBuildState = new BuildState();
|
|
639
|
+
const buildOptions = {
|
|
640
|
+
abortSignal: currentBuildState.abortController.signal
|
|
641
|
+
};
|
|
642
|
+
buildOnce(config, userConfig, plugins, buildOptions).catch((e) => {
|
|
643
|
+
logError(e);
|
|
644
|
+
}).finally(() => {
|
|
645
|
+
currentBuildState = void 0;
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
function scheduleBuild(changedPath) {
|
|
649
|
+
const schedule = changedPaths.size === 0;
|
|
650
|
+
changedPaths.add(changedPath);
|
|
651
|
+
if (schedule) {
|
|
652
|
+
setTimeout(() => {
|
|
653
|
+
performBuild();
|
|
654
|
+
}, delay);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
let watchPaths;
|
|
658
|
+
if (config.watchPaths && config.watchPaths.length > 0) {
|
|
659
|
+
watchPaths = config.watchPaths;
|
|
660
|
+
} else {
|
|
661
|
+
watchPaths = config.modelFiles;
|
|
662
|
+
}
|
|
663
|
+
const watcher = import_chokidar.default.watch(watchPaths, {
|
|
664
|
+
cwd: config.rootDir,
|
|
665
|
+
awaitWriteFinish: {
|
|
666
|
+
stabilityThreshold: 200
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
watcher.on("change", (path) => {
|
|
670
|
+
scheduleBuild(path);
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// src/build/build.ts
|
|
675
|
+
async function build(mode, options) {
|
|
676
|
+
const configResult = await loadConfig(mode, options.config, options.sdeDir, options.sdeCmdPath);
|
|
677
|
+
if (configResult.isErr()) {
|
|
678
|
+
return (0, import_neverthrow3.err)(configResult.error);
|
|
679
|
+
}
|
|
680
|
+
const { userConfig, resolvedConfig } = configResult.value;
|
|
681
|
+
if (options.logLevels !== void 0) {
|
|
682
|
+
setActiveLevels(options.logLevels);
|
|
683
|
+
}
|
|
684
|
+
const messagesPath = (0, import_path7.join)(resolvedConfig.prepDir, "messages.html");
|
|
685
|
+
const overlayEnabled2 = mode === "development";
|
|
686
|
+
setOverlayFile(messagesPath, overlayEnabled2);
|
|
687
|
+
const plugins = userConfig.plugins || [];
|
|
688
|
+
for (const plugin of plugins) {
|
|
689
|
+
if (plugin.init) {
|
|
690
|
+
await plugin.init(resolvedConfig);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
try {
|
|
694
|
+
const plugins2 = userConfig.plugins || [];
|
|
695
|
+
if (mode === "development") {
|
|
696
|
+
const buildResult = await buildOnce(resolvedConfig, userConfig, plugins2, {});
|
|
697
|
+
if (buildResult.isErr()) {
|
|
698
|
+
return (0, import_neverthrow3.err)(buildResult.error);
|
|
699
|
+
}
|
|
700
|
+
for (const plugin of plugins2) {
|
|
701
|
+
if (plugin.watch) {
|
|
702
|
+
await plugin.watch(resolvedConfig);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
watch(resolvedConfig, userConfig, plugins2);
|
|
706
|
+
return (0, import_neverthrow3.ok)({});
|
|
707
|
+
} else {
|
|
708
|
+
const buildResult = await buildOnce(resolvedConfig, userConfig, plugins2, {});
|
|
709
|
+
if (buildResult.isErr()) {
|
|
710
|
+
return (0, import_neverthrow3.err)(buildResult.error);
|
|
711
|
+
}
|
|
712
|
+
const allPluginsSucceeded = buildResult.value;
|
|
713
|
+
const exitCode = allPluginsSucceeded ? 0 : 2;
|
|
714
|
+
return (0, import_neverthrow3.ok)({ exitCode });
|
|
715
|
+
}
|
|
716
|
+
} catch (e) {
|
|
717
|
+
return (0, import_neverthrow3.err)(e);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
721
|
+
0 && (module.exports = {
|
|
722
|
+
build
|
|
723
|
+
});
|
|
724
|
+
//# sourceMappingURL=index.cjs.map
|