@sdeverywhere/create 0.2.42 → 0.2.44

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/dist/index.cjs DELETED
@@ -1,982 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
-
29
- // src/index.ts
30
- var index_exports = {};
31
- __export(index_exports, {
32
- main: () => main
33
- });
34
- module.exports = __toCommonJS(index_exports);
35
- var import_fs5 = require("fs");
36
- var import_path6 = require("path");
37
- var import_colors9 = require("kleur/colors");
38
- var import_ora9 = __toESM(require("ora"), 1);
39
- var import_prompts9 = __toESM(require("prompts"), 1);
40
- var import_which_pm_runs = __toESM(require("which-pm-runs"), 1);
41
- var import_yargs_parser = __toESM(require("yargs-parser"), 1);
42
-
43
- // src/step-code-format.ts
44
- var import_colors = require("kleur/colors");
45
- var import_ora = __toESM(require("ora"), 1);
46
- var import_prompts = __toESM(require("prompts"), 1);
47
- var promptMessage = `Would you like your project to use WebAssembly?`;
48
- var noDesc = `* Choose this if you want to get started using SDEverywhere quickly
49
- and you don't want to install the Emscripten SDK.
50
- * This will generate a model that uses JavaScript code only, which
51
- doesn't require extra build tools, but runs slower than WebAssembly.`;
52
- var yesDesc = `* Choose this if you want this script to install the Emscripten SDK
53
- for you, or if you already have it installed.
54
- * This will generate a model that uses WebAssembly, which requires an
55
- additional build step, but runs faster than pure JavaScript code.`;
56
- var FORMATS = [
57
- {
58
- title: "No, generate a JavaScript model",
59
- description: noDesc,
60
- value: "js"
61
- },
62
- {
63
- title: "Yes, generate a WebAssembly model",
64
- description: yesDesc,
65
- value: "c"
66
- }
67
- ];
68
- async function chooseCodeFormat() {
69
- const options = await (0, import_prompts.default)(
70
- [
71
- {
72
- type: "select",
73
- name: "format",
74
- message: promptMessage,
75
- choices: FORMATS
76
- }
77
- ],
78
- {
79
- onCancel: () => {
80
- (0, import_ora.default)().info((0, import_colors.dim)("Operation cancelled."));
81
- process.exit(0);
82
- }
83
- }
84
- );
85
- const target = options.format === "c" ? "WebAssembly" : "JavaScript";
86
- const successMessage = (0, import_colors.green)(
87
- `Configuring your project to generate ${target}. See "${(0, import_colors.bold)("sde.config.js")}" for details.`
88
- );
89
- (0, import_ora.default)(successMessage).succeed();
90
- return options.format;
91
- }
92
-
93
- // src/step-config.ts
94
- var import_fs = require("fs");
95
- var import_promises = require("fs/promises");
96
- var import_path = require("path");
97
- var import_colors2 = require("kleur/colors");
98
- var import_ora2 = __toESM(require("ora"), 1);
99
- var import_prompts2 = __toESM(require("prompts"), 1);
100
- var import_compile = require("@sdeverywhere/compile");
101
- var sampleChecksContent = `# yaml-language-server: $schema=SCHEMA_PATH
102
-
103
- #
104
- # This file contains "check" tests that exercise your model under different input
105
- # scenarios. For more guidance, consult this wiki page:
106
- # https://github.com/climateinteractive/SDEverywhere/wiki/Testing-and-Comparing-Your-Model
107
- #
108
-
109
- # NOTE: The following is an example of a simple check just to get you started.
110
- # Replace "Some output" with the name of some variable you'd like to test.
111
- - describe: Some output
112
- tests:
113
- - it: should be > 0 for all input scenarios
114
- scenarios:
115
- - preset: matrix
116
- datasets:
117
- - name: Some output
118
- predicates:
119
- - gt: 0
120
- `;
121
- var sampleComparisonsContent = `# yaml-language-server: $schema=SCHEMA_PATH
122
-
123
- #
124
- # This file contains definitions of custom comparison scenarios, which allow you to see
125
- # how the behavior of the model compares to that of previous versions. For more guidance,
126
- # consult the following wiki page:
127
- # https://github.com/climateinteractive/SDEverywhere/wiki/Testing-and-Comparing-Your-Model
128
- #
129
-
130
- # NOTE: The following is an example of a custom scenario just to get you started.
131
- # Replace "Some input" and "Another input" with the names of some variables you'd
132
- # like to test.
133
- - scenario:
134
- title: Custom scenario
135
- subtitle: gradual ramp-up
136
- with:
137
- - input: Some input
138
- at: 10
139
- - input: Another input
140
- at: 20
141
- `;
142
- async function updateSdeConfig(projDir, modelPath, genFormat) {
143
- const configPath = (0, import_path.join)(projDir, "sde.config.js");
144
- let configText = await (0, import_promises.readFile)(configPath, "utf8");
145
- configText = configText.replace(`const genFormat = 'js'`, `const genFormat = '${genFormat}'`);
146
- configText = configText.replaceAll("model/MODEL_NAME.mdl", modelPath);
147
- await (0, import_promises.writeFile)(configPath, configText);
148
- }
149
- async function generateYaml(projDir, kind, template) {
150
- const yamlDir = (0, import_path.join)(projDir, "model", kind);
151
- const yamlPath = (0, import_path.join)(yamlDir, `${kind}.yaml`);
152
- if (!(0, import_fs.existsSync)(yamlPath)) {
153
- let relProjPath = (0, import_path.relative)((0, import_path.dirname)(yamlPath), projDir);
154
- if (relProjPath.length === 0) {
155
- relProjPath = "./";
156
- }
157
- await (0, import_promises.mkdir)(yamlDir, { recursive: true });
158
- const nodeModulesPart = (0, import_path.join)(relProjPath, "node_modules");
159
- const schemaName = kind === "checks" ? "check" : "comparison";
160
- const checkCorePart = `@sdeverywhere/check-core/schema/${schemaName}.schema.json`;
161
- const schemaPath = `${nodeModulesPart}/${checkCorePart}`;
162
- const yamlContent = template.replace("SCHEMA_PATH", schemaPath);
163
- await (0, import_promises.writeFile)(yamlPath, yamlContent);
164
- }
165
- }
166
- async function generateSampleYamlFiles(projDir) {
167
- await generateYaml(projDir, "checks", sampleChecksContent);
168
- await generateYaml(projDir, "comparisons", sampleComparisonsContent);
169
- }
170
- async function chooseGenConfig(projDir, modelPath) {
171
- let mdlVars;
172
- try {
173
- mdlVars = await readModelVars(projDir, modelPath);
174
- } catch (e) {
175
- console.log(e);
176
- (0, import_ora2.default)(
177
- (0, import_colors2.yellow)("The model file failed to load. We will continue setting things up, and you can diagnose the issue later.")
178
- ).warn();
179
- return;
180
- }
181
- let initialTime;
182
- let finalTime;
183
- const validVars = [];
184
- for (const v of mdlVars) {
185
- const varName = v.name.toLowerCase();
186
- let skip = false;
187
- switch (varName) {
188
- case "final time":
189
- skip = true;
190
- if (v.kind === "const") {
191
- finalTime = v.value;
192
- }
193
- break;
194
- case "initial time":
195
- skip = true;
196
- if (v.kind === "const") {
197
- initialTime = v.value;
198
- }
199
- break;
200
- case "saveper":
201
- case "time":
202
- case "time step":
203
- skip = true;
204
- break;
205
- default:
206
- break;
207
- }
208
- if (!skip) {
209
- validVars.push(v);
210
- }
211
- }
212
- if (initialTime === void 0) {
213
- initialTime = 0;
214
- }
215
- if (finalTime === void 0) {
216
- finalTime = 100;
217
- }
218
- const datFiles = [];
219
- const datPart = datFiles.join(";");
220
- const modelCsvFile = (0, import_path.join)(projDir, "config", "model.csv");
221
- const origModelCsvContent = await (0, import_promises.readFile)(modelCsvFile, "utf8");
222
- const modelCsvHeader = origModelCsvContent.split("\n")[0];
223
- const bundleListing = "false";
224
- const customConstants = "false";
225
- const customLookups = "false";
226
- const customOutputs = "false";
227
- const modelCsvLine = `${initialTime},${finalTime},${datPart},${bundleListing},${customConstants},${customLookups},${customOutputs}`;
228
- const newModelCsvContent = `${modelCsvHeader}
229
- ${modelCsvLine}
230
- `;
231
- await (0, import_promises.writeFile)(modelCsvFile, newModelCsvContent);
232
- await chooseGenGraphConfig(projDir, validVars);
233
- console.log();
234
- await chooseGenSliderConfig(projDir, validVars);
235
- }
236
- async function chooseGenGraphConfig(projDir, mdlVars) {
237
- const genResponse = await (0, import_prompts2.default)(
238
- {
239
- type: "confirm",
240
- name: "genGraph",
241
- message: `Would you like to configure a graph to get you started? ${(0, import_colors2.reset)((0, import_colors2.dim)("(recommended)"))}`,
242
- initial: true
243
- },
244
- {
245
- onCancel: () => {
246
- (0, import_ora2.default)().info((0, import_colors2.dim)("Operation cancelled."));
247
- process.exit(0);
248
- }
249
- }
250
- );
251
- if (!genResponse.genGraph) {
252
- (0, import_ora2.default)().info((0, import_colors2.dim)(`No problem! You can edit the "${(0, import_colors2.cyan)("config/graphs.csv")}" file later.`));
253
- return;
254
- }
255
- const outputVarNames = [];
256
- for (const mdlVar of mdlVars) {
257
- if (mdlVar.kind === "aux" || mdlVar.kind === "level") {
258
- outputVarNames.push(mdlVar.name);
259
- }
260
- }
261
- outputVarNames.sort((a, b) => {
262
- return a.toLowerCase().localeCompare(b.toLowerCase());
263
- });
264
- const choices = outputVarNames.map((f) => {
265
- return {
266
- title: f,
267
- value: f
268
- };
269
- });
270
- const varsResponse = await (0, import_prompts2.default)(
271
- {
272
- type: "autocompleteMultiselect",
273
- name: "vars",
274
- message: "Choose up to three output variables to display in the graph",
275
- choices,
276
- max: 3
277
- },
278
- {
279
- onCancel: () => {
280
- (0, import_ora2.default)().info((0, import_colors2.dim)("Operation cancelled."));
281
- process.exit(0);
282
- }
283
- }
284
- );
285
- const graphsCsvFile = (0, import_path.join)(projDir, "config", "graphs.csv");
286
- const origGraphsCsvContent = await (0, import_promises.readFile)(graphsCsvFile, "utf8");
287
- const graphsCsvHeader = origGraphsCsvContent.split("\n")[0];
288
- let newGraphsCsvContent = `${graphsCsvHeader}
289
- `;
290
- if (varsResponse.vars.length > 0) {
291
- const csvLine = graphsCsvLine(varsResponse.vars);
292
- newGraphsCsvContent += `${csvLine}
293
- `;
294
- }
295
- await (0, import_promises.writeFile)(graphsCsvFile, newGraphsCsvContent);
296
- if (varsResponse.vars.length === 0) {
297
- (0, import_ora2.default)().info((0, import_colors2.dim)(`No variables selected. You can edit the "${(0, import_colors2.cyan)("config/graphs.csv")}" file later.`));
298
- return;
299
- }
300
- (0, import_ora2.default)(
301
- (0, import_colors2.green)(`Added graph to "${(0, import_colors2.bold)("config/graphs.csv")}". ${(0, import_colors2.dim)("You can configure graphs in that file later.")}`)
302
- ).succeed();
303
- }
304
- function graphsCsvLine(outputVarNames) {
305
- const colors = ["blue", "red", "green"];
306
- const a = Array(131).fill("");
307
- a[0] = "1";
308
- a[2] = "Graphs";
309
- a[3] = "Graph Title";
310
- a[7] = "line";
311
- let index = 26;
312
- let colorIndex = 0;
313
- for (const outputVarName of outputVarNames) {
314
- const escapedName = escapeCsvField(outputVarName);
315
- a[index + 0] = escapedName;
316
- a[index + 2] = "line";
317
- a[index + 3] = escapedName;
318
- a[index + 4] = colors[colorIndex];
319
- index += 7;
320
- colorIndex++;
321
- }
322
- return a.join(",");
323
- }
324
- async function chooseGenSliderConfig(projDir, mdlVars) {
325
- const genResponse = await (0, import_prompts2.default)(
326
- {
327
- type: "confirm",
328
- name: "genSliders",
329
- message: `Would you like to configure a few sliders to get you started? ${(0, import_colors2.reset)((0, import_colors2.dim)("(recommended)"))}`,
330
- initial: true
331
- },
332
- {
333
- onCancel: () => {
334
- (0, import_ora2.default)().info((0, import_colors2.dim)("Operation cancelled."));
335
- process.exit(0);
336
- }
337
- }
338
- );
339
- if (!genResponse.genSliders) {
340
- (0, import_ora2.default)().info((0, import_colors2.dim)(`No problem! You can edit the "${(0, import_colors2.cyan)("config/inputs.csv")}" file later.`));
341
- return;
342
- }
343
- const inputVarNames = [];
344
- for (const mdlVar of mdlVars) {
345
- if (mdlVar.kind === "const") {
346
- inputVarNames.push(mdlVar.name);
347
- }
348
- }
349
- inputVarNames.sort((a, b) => {
350
- return a.toLowerCase().localeCompare(b.toLowerCase());
351
- });
352
- const choices = inputVarNames.map((f) => {
353
- return {
354
- title: f,
355
- value: f
356
- };
357
- });
358
- const varsResponse = await (0, import_prompts2.default)(
359
- {
360
- type: "autocompleteMultiselect",
361
- name: "vars",
362
- message: "Choose up to three input variables to control with sliders",
363
- choices,
364
- max: 3
365
- },
366
- {
367
- onCancel: () => {
368
- (0, import_ora2.default)().info((0, import_colors2.dim)("Operation cancelled."));
369
- process.exit(0);
370
- }
371
- }
372
- );
373
- const inputsCsvFile = (0, import_path.join)(projDir, "config", "inputs.csv");
374
- const origInputsCsvContent = await (0, import_promises.readFile)(inputsCsvFile, "utf8");
375
- const inputsCsvHeader = origInputsCsvContent.split("\n")[0];
376
- let newInputsCsvContent = `${inputsCsvHeader}
377
- `;
378
- if (varsResponse.vars.length > 0) {
379
- let idNumber = 1;
380
- for (const inputVarName of varsResponse.vars) {
381
- const inputVar = mdlVars.find((v) => v.name === inputVarName);
382
- if (inputVar && inputVar.kind === "const") {
383
- const defaultValue = inputVar.value;
384
- const csvLine = inputsCsvLine(inputVarName, defaultValue, idNumber.toString());
385
- newInputsCsvContent += `${csvLine}
386
- `;
387
- idNumber++;
388
- }
389
- }
390
- }
391
- await (0, import_promises.writeFile)(inputsCsvFile, newInputsCsvContent);
392
- if (varsResponse.vars.length === 0) {
393
- (0, import_ora2.default)().info((0, import_colors2.dim)(`No variables selected. You can edit the "${(0, import_colors2.cyan)("config/inputs.csv")}" file later.`));
394
- return;
395
- }
396
- const slidersText = varsResponse.vars.length > 1 ? "sliders" : "sliders";
397
- (0, import_ora2.default)(
398
- (0, import_colors2.green)(
399
- `Added ${slidersText} to "${(0, import_colors2.bold)("config/inputs.csv")}". ${(0, import_colors2.dim)("You can configure sliders in that file later.")}`
400
- )
401
- ).succeed();
402
- }
403
- function inputsCsvLine(inputVarName, defaultValue, id) {
404
- const escapedName = escapeCsvField(inputVarName);
405
- const minValue = defaultValue - 1;
406
- const maxValue = defaultValue + 1;
407
- const step = 0.1;
408
- const a = Array(28).fill("");
409
- a[0] = id;
410
- a[1] = "slider";
411
- a[2] = "view1";
412
- a[3] = escapedName;
413
- a[4] = escapedName;
414
- a[6] = "Sliders";
415
- a[7] = minValue;
416
- a[8] = maxValue;
417
- a[9] = defaultValue;
418
- a[10] = step;
419
- a[11] = "(units)";
420
- return a.join(",");
421
- }
422
- function escapeCsvField(s) {
423
- return s.includes(",") ? `"${s}"` : s;
424
- }
425
- async function readModelVars(projDir, modelPath) {
426
- const buildDir = (0, import_path.resolve)(projDir, "sde-prep", "build");
427
- await (0, import_promises.mkdir)(buildDir, { recursive: true });
428
- const spec = {};
429
- const modelFile = (0, import_path.resolve)(projDir, modelPath);
430
- const modelContent = await (0, import_promises.readFile)(modelFile, "utf8");
431
- const modelKind = modelContent.includes("<xmile") ? "xmile" : "vensim";
432
- const modelDir = (0, import_path.dirname)(modelFile);
433
- const modelName = (0, import_path.parse)(modelFile).name;
434
- await (0, import_compile.parseAndGenerate)(modelContent, modelKind, spec, ["printVarList"], modelDir, modelName, buildDir);
435
- const jsonListFile = (0, import_path.join)(buildDir, `${modelName}.json`);
436
- const jsonListContent = await (0, import_promises.readFile)(jsonListFile, "utf8");
437
- const jsonList = JSON.parse(jsonListContent);
438
- const varObjs = jsonList.variables;
439
- const mdlVars = [];
440
- for (const varObj of varObjs) {
441
- switch (varObj.varType) {
442
- case "const":
443
- mdlVars.push({
444
- kind: "const",
445
- name: varObj.modelLHS,
446
- value: Number.parseFloat(varObj.modelFormula)
447
- });
448
- break;
449
- case "aux":
450
- mdlVars.push({
451
- kind: "aux",
452
- name: varObj.modelLHS
453
- });
454
- break;
455
- case "level":
456
- mdlVars.push({
457
- kind: "level",
458
- name: varObj.modelLHS
459
- });
460
- break;
461
- default:
462
- break;
463
- }
464
- }
465
- return mdlVars;
466
- }
467
-
468
- // src/step-deps.ts
469
- var import_execa = require("execa");
470
- var import_colors3 = require("kleur/colors");
471
- var import_ora3 = __toESM(require("ora"), 1);
472
- var import_prompts3 = __toESM(require("prompts"), 1);
473
- async function chooseInstallDeps(projDir, args, pkgManager) {
474
- const installResponse = await (0, import_prompts3.default)(
475
- {
476
- type: "confirm",
477
- name: "install",
478
- message: `Would you like to install ${pkgManager} dependencies? ${(0, import_colors3.reset)((0, import_colors3.dim)("(recommended)"))}`,
479
- initial: true
480
- },
481
- {
482
- onCancel: () => {
483
- (0, import_ora3.default)().info(
484
- (0, import_colors3.dim)("Operation cancelled. Your project folder has been created, but no dependencies have been installed.")
485
- );
486
- process.exit(0);
487
- }
488
- }
489
- );
490
- if (args.dryRun) {
491
- (0, import_ora3.default)().info((0, import_colors3.dim)(`--dry-run enabled, skipping.`));
492
- return;
493
- } else if (!installResponse.install) {
494
- (0, import_ora3.default)().info((0, import_colors3.dim)(`No problem! Remember to install dependencies after setup.`));
495
- return;
496
- }
497
- const installExec = (0, import_execa.execa)(pkgManager, ["install"], { cwd: projDir });
498
- const installingPackagesMsg = "Installing packages...";
499
- const installSpinner = (0, import_ora3.default)(installingPackagesMsg).start();
500
- try {
501
- await new Promise((resolve, reject) => {
502
- installExec.stdout?.on("data", function(data) {
503
- installSpinner.text = `${installingPackagesMsg}
504
- ${(0, import_colors3.bold)(`[${pkgManager}]`)} ${data}`;
505
- });
506
- installExec.stderr?.on("data", function(data) {
507
- installSpinner.text = `${installingPackagesMsg}
508
- ${(0, import_colors3.bold)(`[${pkgManager}]`)} ${data}`;
509
- });
510
- installExec.on("error", (error) => reject(error));
511
- installExec.on("close", (code) => {
512
- if (code !== 0) {
513
- reject(`Install failed (code=${code})`);
514
- } else {
515
- resolve();
516
- }
517
- });
518
- });
519
- installSpinner.text = (0, import_colors3.green)("Packages installed!");
520
- installSpinner.succeed();
521
- } catch {
522
- installSpinner.text = (0, import_colors3.yellow)(
523
- `There was an error installing packages. Try running ${(0, import_colors3.cyan)(
524
- `${pkgManager} install`
525
- )} in your project directory later.`
526
- );
527
- installSpinner.warn();
528
- }
529
- }
530
-
531
- // src/step-directory.ts
532
- var import_fs2 = require("fs");
533
- var import_path2 = require("path");
534
- var import_colors4 = require("kleur/colors");
535
- var import_ora4 = __toESM(require("ora"), 1);
536
- var import_prompts4 = __toESM(require("prompts"), 1);
537
- async function chooseProjectDir(args) {
538
- function isValidDir(dir) {
539
- const packageJson = (0, import_path2.resolve)(dir, "package.json");
540
- const packagesDir = (0, import_path2.resolve)(dir, "packages");
541
- return !(0, import_fs2.existsSync)(dir) || !(0, import_fs2.existsSync)(packageJson) && !(0, import_fs2.existsSync)(packagesDir);
542
- }
543
- const showValidDirMsg = (dir) => {
544
- (0, import_ora4.default)((0, import_colors4.green)(`Using "${(0, import_colors4.bold)(dir)}" as the project directory.`)).succeed();
545
- };
546
- const showInvalidDirMsg = (dir) => {
547
- (0, import_ora4.default)((0, import_colors4.red)(`"${(0, import_colors4.bold)(dir)}" contains existing 'package.json' and/or 'packages' directory, stopping.`)).fail();
548
- };
549
- let projDir = args["_"][2];
550
- if (projDir) {
551
- if (isValidDir(projDir)) {
552
- showValidDirMsg(projDir);
553
- } else {
554
- showInvalidDirMsg(projDir);
555
- process.exit(0);
556
- }
557
- } else {
558
- const dirResponse = await (0, import_prompts4.default)(
559
- {
560
- type: "text",
561
- name: "directory",
562
- message: "Where would you like to create your new project?",
563
- initial: "<current directory>"
564
- // validate(value) {
565
- // if (value === '<current directory>') {
566
- // value = process.cwd()
567
- // }
568
- // if (!isValidDir(value)) {
569
- // return notValidMsg(value)
570
- // }
571
- // return true
572
- // }
573
- },
574
- {
575
- onCancel: () => {
576
- (0, import_ora4.default)().info((0, import_colors4.dim)("Operation cancelled."));
577
- process.exit(0);
578
- }
579
- }
580
- );
581
- projDir = dirResponse.directory;
582
- if (projDir === "<current directory>") {
583
- projDir = process.cwd();
584
- }
585
- if (isValidDir(projDir)) {
586
- showValidDirMsg(projDir);
587
- } else {
588
- showInvalidDirMsg(projDir);
589
- process.exit(0);
590
- }
591
- }
592
- return projDir;
593
- }
594
-
595
- // src/step-emsdk.ts
596
- var import_fs3 = require("fs");
597
- var import_path3 = require("path");
598
- var import_execa2 = require("execa");
599
- var import_find_up = require("find-up");
600
- var import_colors5 = require("kleur/colors");
601
- var import_ora5 = __toESM(require("ora"), 1);
602
- var import_prompts5 = __toESM(require("prompts"), 1);
603
- var version = "2.0.34";
604
- async function chooseInstallEmsdk(projDir, args) {
605
- const existingEmsdkDir = await (0, import_find_up.findUp)("emsdk", {
606
- cwd: projDir,
607
- type: "directory"
608
- });
609
- if (existingEmsdkDir) {
610
- (0, import_ora5.default)().succeed("Found existing Emscripten SDK installation.");
611
- (0, import_ora5.default)().info((0, import_colors5.dim)(`Your project will use "${(0, import_colors5.cyan)(existingEmsdkDir)}".`));
612
- return;
613
- }
614
- const underParentDir = (0, import_path3.resolve)(projDir, "..", "emsdk");
615
- const underProjDir = (0, import_path3.join)(projDir, "emsdk");
616
- const installResponse = await (0, import_prompts5.default)(
617
- {
618
- type: "select",
619
- name: "install",
620
- message: `Would you like to install the Emscripten SDK that is used to generate WebAssembly?`,
621
- choices: [
622
- // ${reset(dim('(recommended)'))
623
- {
624
- title: `Install under parent directory (${(0, import_colors5.bold)(underParentDir)})`,
625
- description: "This is recommended so that it can be shared by multiple projects",
626
- value: "parent"
627
- },
628
- {
629
- title: `Install under project directory (${(0, import_colors5.bold)(underProjDir)})"`,
630
- description: "This is useful for keeping everything under a single project directory",
631
- value: "project"
632
- },
633
- {
634
- title: `Don't install`,
635
- description: `It's OK, you can install it later`,
636
- value: "skip"
637
- }
638
- ]
639
- },
640
- {
641
- onCancel: () => {
642
- (0, import_ora5.default)().info(
643
- (0, import_colors5.dim)(
644
- "Operation cancelled. Your project folder has been created, but the Emscripten SDK and other dependencies have not been installed."
645
- )
646
- );
647
- process.exit(0);
648
- }
649
- }
650
- );
651
- if (args.dryRun) {
652
- (0, import_ora5.default)().info((0, import_colors5.dim)(`--dry-run enabled, skipping.`));
653
- return;
654
- } else if (installResponse.install === "skip") {
655
- (0, import_ora5.default)().info(
656
- (0, import_colors5.dim)(
657
- `No problem! Be sure to install the Emscripten SDK and configure it in "${(0, import_colors5.cyan)("sde.config.js")}" after setup.`
658
- )
659
- );
660
- return;
661
- }
662
- const installDir = installResponse.install === "parent" ? underParentDir : underProjDir;
663
- try {
664
- await installEmscripten(installDir);
665
- } catch (e) {
666
- (0, import_ora5.default)((0, import_colors5.red)(`Failed to install Emscripten SDK: ${e.message}`)).fail();
667
- process.exit(0);
668
- }
669
- (0, import_ora5.default)((0, import_colors5.green)(`Installed the Emscripten SDK in "${(0, import_colors5.bold)(installDir)}"`)).succeed();
670
- }
671
- async function installEmscripten(emsdkDir) {
672
- if (!(0, import_fs3.existsSync)(emsdkDir)) {
673
- console.log(`Downloading Emscripten SDK to ${emsdkDir}`);
674
- await (0, import_execa2.execa)("git", ["clone", "https://github.com/emscripten-core/emsdk.git", emsdkDir]);
675
- } else {
676
- console.log(`Found existing Emscripten SDK directory: ${emsdkDir}`);
677
- }
678
- if (process.env.CI) {
679
- console.log("CI detected, removing .git directory...");
680
- const gitDir = (0, import_path3.join)(emsdkDir, ".git");
681
- (0, import_fs3.rmSync)(gitDir, { recursive: true, force: true });
682
- } else {
683
- console.log("Local development detected, performing git pull...");
684
- await (0, import_execa2.execa)("git", ["pull"], { cwd: emsdkDir });
685
- }
686
- const emsdkCmd = async (...args) => {
687
- return (0, import_execa2.execa)("python3", ["emsdk.py", ...args], { cwd: emsdkDir });
688
- };
689
- console.log(`Activating Emscripten SDK ${version}...`);
690
- await emsdkCmd("install", version);
691
- await emsdkCmd("activate", version);
692
- }
693
-
694
- // src/step-git.ts
695
- var import_execa3 = require("execa");
696
- var import_colors6 = require("kleur/colors");
697
- var import_ora6 = __toESM(require("ora"), 1);
698
- var import_prompts6 = __toESM(require("prompts"), 1);
699
- async function chooseGitInit(projDir, args) {
700
- const gitResponse = await (0, import_prompts6.default)(
701
- {
702
- type: "confirm",
703
- name: "git",
704
- message: `Would you like to initialize a new git repository? ${(0, import_colors6.reset)((0, import_colors6.dim)("(optional)"))}`,
705
- initial: true
706
- },
707
- {
708
- onCancel: () => {
709
- (0, import_ora6.default)().info((0, import_colors6.dim)("Operation cancelled. Your project folder has already been created."));
710
- process.exit(0);
711
- }
712
- }
713
- );
714
- if (args.dryRun) {
715
- (0, import_ora6.default)().info((0, import_colors6.dim)(`--dry-run enabled, skipping.`));
716
- return;
717
- } else if (!gitResponse.git) {
718
- (0, import_ora6.default)().info((0, import_colors6.dim)(`No problem! You can come back and run ${(0, import_colors6.cyan)(`git init`)} later.`));
719
- return;
720
- }
721
- try {
722
- await (0, import_execa3.execaCommand)("git init", { cwd: projDir });
723
- (0, import_ora6.default)().succeed((0, import_colors6.green)("Git repository initialized!"));
724
- } catch {
725
- (0, import_ora6.default)().warn(
726
- (0, import_colors6.yellow)(
727
- `There was a problem initializing the Git repository, but no problem, you can run ${(0, import_colors6.cyan)(`git init`)} later.`
728
- )
729
- );
730
- }
731
- }
732
-
733
- // src/step-model-file.ts
734
- var import_promises2 = require("fs/promises");
735
- var import_path4 = require("path");
736
- var import_colors7 = require("kleur/colors");
737
- var import_ora7 = __toESM(require("ora"), 1);
738
- var import_prompts7 = __toESM(require("prompts"), 1);
739
- var supportedModelFileExtensions = /* @__PURE__ */ new Set([".mdl", ".xmile", ".stmx", ".itmx"]);
740
- async function chooseModelFile(projDir) {
741
- async function getFiles(dir) {
742
- const dirents = await (0, import_promises2.readdir)(dir, { withFileTypes: true });
743
- const files = await Promise.all(
744
- dirents.map((dirent) => {
745
- const res = (0, import_path4.resolve)(dir, dirent.name);
746
- return dirent.isDirectory() ? getFiles(res) : res;
747
- })
748
- );
749
- return files.flat();
750
- }
751
- const allFiles = await getFiles(projDir);
752
- const modelFiles = allFiles.filter((f) => {
753
- const ext = (0, import_path4.extname)(f).toLowerCase();
754
- return supportedModelFileExtensions.has(ext);
755
- }).map((f) => (0, import_path4.relative)(projDir, f).replaceAll(import_path4.sep, import_path4.posix.sep));
756
- const modelChoices = modelFiles.map((f) => {
757
- return {
758
- title: f,
759
- value: f
760
- };
761
- });
762
- let modelFile;
763
- if (modelFiles.length === 0) {
764
- (0, import_ora7.default)(
765
- (0, import_colors7.yellow)(`No model files were found in "${projDir}". The model file from the template will be used instead.`)
766
- ).warn();
767
- modelFile = void 0;
768
- } else if (modelFiles.length === 1) {
769
- modelFile = modelFiles[0];
770
- (0, import_ora7.default)().succeed(`Found "${modelFile}", will configure the project to use that model file.`);
771
- } else {
772
- const options = await (0, import_prompts7.default)(
773
- [
774
- {
775
- type: "select",
776
- name: "modelFile",
777
- message: "It looks like there are multiple model files. Which one would you like to use?",
778
- choices: modelChoices
779
- }
780
- ],
781
- {
782
- onCancel: () => {
783
- (0, import_ora7.default)().info((0, import_colors7.dim)("Operation cancelled."));
784
- process.exit(0);
785
- }
786
- }
787
- );
788
- modelFile = options.modelFile;
789
- (0, import_ora7.default)((0, import_colors7.green)(`Using "${(0, import_colors7.bold)(modelFile)}" as the model for the project.`)).succeed();
790
- }
791
- return modelFile;
792
- }
793
-
794
- // src/step-template.ts
795
- var import_fs4 = require("fs");
796
- var import_promises3 = require("fs/promises");
797
- var import_fs_extra = require("fs-extra");
798
- var import_os = require("os");
799
- var import_path5 = require("path");
800
- var import_giget = require("giget");
801
- var import_colors8 = require("kleur/colors");
802
- var import_ora8 = __toESM(require("ora"), 1);
803
- var import_prompts8 = __toESM(require("prompts"), 1);
804
- var TEMPLATES = [
805
- {
806
- title: "Svelte project (recommended)",
807
- description: "Includes recommended structure with config files, Svelte-based app, core library, model-check, etc",
808
- value: "svelte"
809
- },
810
- {
811
- title: "jQuery project",
812
- description: "Includes recommended structure with config files, jQuery-based app, core library, model-check, etc",
813
- value: "jquery"
814
- },
815
- {
816
- title: "Minimal project",
817
- description: "Includes simple config for model-check",
818
- value: "minimal"
819
- }
820
- ];
821
- async function chooseTemplate(args) {
822
- let templateName;
823
- if (args.template) {
824
- templateName = args.template;
825
- } else {
826
- const options = await (0, import_prompts8.default)(
827
- [
828
- {
829
- type: "select",
830
- name: "template",
831
- message: "Which template would you like to use?",
832
- choices: TEMPLATES
833
- }
834
- ],
835
- {
836
- onCancel: () => {
837
- (0, import_ora8.default)().info((0, import_colors8.dim)("Operation cancelled."));
838
- process.exit(0);
839
- }
840
- }
841
- );
842
- templateName = options.template;
843
- }
844
- const defaultRev = "main";
845
- const commit = args.commit || defaultRev;
846
- let baseTemplateUri;
847
- if (templateName.includes(":")) {
848
- baseTemplateUri = templateName;
849
- } else if (templateName.includes("/")) {
850
- baseTemplateUri = `github:${templateName}`;
851
- } else {
852
- baseTemplateUri = `github:climateinteractive/SDEverywhere/examples/template-${templateName}`;
853
- }
854
- const templateUri = `${baseTemplateUri}#${commit}`;
855
- (0, import_ora8.default)((0, import_colors8.green)(`Using "${(0, import_colors8.bold)(templateUri)}" as the template for the project.`)).succeed();
856
- return {
857
- uri: templateUri,
858
- name: templateName
859
- };
860
- }
861
- async function copyTemplate(template, projDir, pkgManager, configDirExisted, modelExisted) {
862
- const templateSpinner = (0, import_ora8.default)("Copying template files...").start();
863
- try {
864
- const tmpDir = (0, import_fs4.mkdtempSync)((0, import_path5.join)((0, import_os.tmpdir)(), "sde-create-"));
865
- await (0, import_giget.downloadTemplate)(template.uri, {
866
- force: true,
867
- dir: tmpDir
868
- });
869
- if (!(0, import_fs4.existsSync)(tmpDir) || (0, import_fs4.readdirSync)(tmpDir).length === 0) {
870
- throw new Error("Failed to download the requested template: the temporary directory is empty.");
871
- }
872
- if (configDirExisted) {
873
- (0, import_fs4.rmSync)((0, import_path5.join)(tmpDir, "config"), { recursive: true, force: true });
874
- }
875
- if (modelExisted) {
876
- (0, import_fs4.rmSync)((0, import_path5.join)(tmpDir, "model"), { recursive: true, force: true });
877
- }
878
- await (0, import_fs_extra.copy)(tmpDir, projDir, {
879
- overwrite: false,
880
- errorOnExist: false
881
- });
882
- if (!modelExisted) {
883
- (0, import_fs4.renameSync)((0, import_path5.join)(projDir, "model", "MODEL_NAME.mdl"), (0, import_path5.join)(projDir, "model", "sample.mdl"));
884
- }
885
- (0, import_fs4.rmSync)(tmpDir, { recursive: true, force: true });
886
- } catch (e) {
887
- templateSpinner.fail();
888
- console.error((0, import_colors8.red)(e.message));
889
- console.error((0, import_colors8.yellow)("\nThere was a problem copying the template."));
890
- console.error(
891
- (0, import_colors8.yellow)(
892
- "Please start a new discussion thread and include the command output so that we can help:\n https://github.com/climateinteractive/SDEverywhere/discussions/categories/q-a\n"
893
- )
894
- );
895
- process.exit(0);
896
- }
897
- if ((0, import_fs4.existsSync)((0, import_path5.join)(projDir, "packages")) && pkgManager === "pnpm") {
898
- const workspaceFile = (0, import_path5.join)(projDir, "pnpm-workspace.yaml");
899
- const workspaceContent = `packages:
900
- - packages/*
901
- `;
902
- await (0, import_promises3.writeFile)(workspaceFile, workspaceContent);
903
- }
904
- templateSpinner.text = (0, import_colors8.green)("Template copied!");
905
- templateSpinner.succeed();
906
- }
907
-
908
- // src/index.ts
909
- async function main() {
910
- const pkgManager = (0, import_which_pm_runs.default)()?.name || "npm";
911
- const args = (0, import_yargs_parser.default)(process.argv);
912
- import_prompts9.default.override(args);
913
- if (args.dryRun) {
914
- console.log();
915
- (0, import_ora9.default)().info((0, import_colors9.dim)(`--dry-run enabled, no files will be written.`));
916
- }
917
- console.log(`
918
- ${(0, import_colors9.bold)("Welcome to SDEverywhere!")}`);
919
- console.log(`Let's create a new SDEverywhere project for your model.
920
- `);
921
- const projDir = await chooseProjectDir(args);
922
- console.log();
923
- const configDirExisted = (0, import_fs5.existsSync)((0, import_path6.resolve)(projDir, "config"));
924
- const template = await chooseTemplate(args);
925
- console.log();
926
- let modelPath = await chooseModelFile(projDir);
927
- const modelExisted = modelPath !== void 0;
928
- console.log();
929
- if (!args.dryRun) {
930
- await copyTemplate(template, projDir, pkgManager, configDirExisted, modelExisted);
931
- console.log();
932
- }
933
- if (modelPath === void 0) {
934
- modelPath = `model${import_path6.posix.sep}sample.mdl`;
935
- }
936
- const genFormat = await chooseCodeFormat();
937
- if (!args.dryRun) {
938
- await updateSdeConfig(projDir, modelPath, genFormat);
939
- const modelCheckFilesExist = (0, import_fs5.existsSync)((0, import_path6.resolve)(projDir, "model", "checks")) || (0, import_fs5.existsSync)((0, import_path6.resolve)(projDir, "model", "comparisons"));
940
- if (!modelCheckFilesExist) {
941
- await generateSampleYamlFiles(projDir);
942
- }
943
- }
944
- console.log();
945
- if (configDirExisted) {
946
- (0, import_ora9.default)().succeed(`Found existing "${(0, import_colors9.bold)("config")}" directory.`);
947
- (0, import_ora9.default)().info(
948
- (0, import_colors9.dim)(`You can edit the files in the "${(0, import_colors9.cyan)("config")}" directory later to configure graphs and sliders.`)
949
- );
950
- console.log();
951
- } else {
952
- const configDirExistsNow = (0, import_fs5.existsSync)((0, import_path6.resolve)(projDir, "config"));
953
- if (configDirExistsNow && modelExisted && !args.dryRun) {
954
- await chooseGenConfig(projDir, modelPath);
955
- console.log();
956
- }
957
- }
958
- if (genFormat === "c") {
959
- await chooseInstallEmsdk(projDir, args);
960
- console.log();
961
- }
962
- await chooseInstallDeps(projDir, args, pkgManager);
963
- console.log();
964
- await chooseGitInit(projDir, args);
965
- console.log();
966
- (0, import_ora9.default)((0, import_colors9.green)("Setup complete!")).succeed();
967
- console.log(`
968
- ${(0, import_colors9.bgCyan)((0, import_colors9.black)(" Next steps "))}
969
- `);
970
- const relProjDir = (0, import_path6.relative)(process.cwd(), projDir);
971
- const devCmd = pkgManager === "npm" ? "npm run dev" : `${pkgManager} dev`;
972
- if (relProjDir !== "") {
973
- console.log(`You can now ${(0, import_colors9.bold)((0, import_colors9.cyan)("cd"))} into the ${(0, import_colors9.bold)((0, import_colors9.cyan)(relProjDir))} project directory.`);
974
- }
975
- console.log(`Run ${(0, import_colors9.bold)((0, import_colors9.cyan)(devCmd))} to start the local dev server. ${(0, import_colors9.bold)((0, import_colors9.cyan)("CTRL-C"))} to close.`);
976
- console.log("");
977
- }
978
- // Annotate the CommonJS export names for ESM import in node:
979
- 0 && (module.exports = {
980
- main
981
- });
982
- //# sourceMappingURL=index.cjs.map