@sdeverywhere/create 0.2.25 → 0.2.27
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 +128 -108
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +141 -121
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { existsSync as existsSync5 } from "fs";
|
|
3
|
-
import { relative as relative3, resolve as resolvePath5 } from "path";
|
|
4
|
-
import { bgCyan, black, bold as
|
|
3
|
+
import { posix as posix2, relative as relative3, resolve as resolvePath5 } from "path";
|
|
4
|
+
import { bgCyan, black, bold as bold8, cyan as cyan5, dim as dim9, green as green9 } from "kleur/colors";
|
|
5
5
|
import ora9 from "ora";
|
|
6
6
|
import prompts9 from "prompts";
|
|
7
7
|
import detectPackageManager from "which-pm-runs";
|
|
@@ -64,7 +64,6 @@ import { dirname, join as joinPath, parse as parsePath, relative, resolve as res
|
|
|
64
64
|
import { bold as bold2, cyan, dim as dim2, green as green2, reset, yellow } from "kleur/colors";
|
|
65
65
|
import ora2 from "ora";
|
|
66
66
|
import prompts2 from "prompts";
|
|
67
|
-
import yaml from "yaml";
|
|
68
67
|
import { parseAndGenerate } from "@sdeverywhere/compile";
|
|
69
68
|
var sampleChecksContent = `# yaml-language-server: $schema=SCHEMA_PATH
|
|
70
69
|
|
|
@@ -111,7 +110,7 @@ async function updateSdeConfig(projDir, mdlPath, genFormat) {
|
|
|
111
110
|
const configPath = joinPath(projDir, "sde.config.js");
|
|
112
111
|
let configText = await readFile(configPath, "utf8");
|
|
113
112
|
configText = configText.replace(`const genFormat = 'js'`, `const genFormat = '${genFormat}'`);
|
|
114
|
-
configText = configText.replaceAll("MODEL_NAME.mdl", mdlPath);
|
|
113
|
+
configText = configText.replaceAll("model/MODEL_NAME.mdl", mdlPath);
|
|
115
114
|
await writeFile(configPath, configText);
|
|
116
115
|
}
|
|
117
116
|
async function generateYaml(projDir, kind, template) {
|
|
@@ -249,16 +248,21 @@ async function chooseGenGraphConfig(projDir, mdlVars) {
|
|
|
249
248
|
}
|
|
250
249
|
}
|
|
251
250
|
);
|
|
251
|
+
const graphsCsvFile = joinPath(projDir, "config", "graphs.csv");
|
|
252
|
+
const origGraphsCsvContent = await readFile(graphsCsvFile, "utf8");
|
|
253
|
+
const graphsCsvHeader = origGraphsCsvContent.split("\n")[0];
|
|
254
|
+
let newGraphsCsvContent = `${graphsCsvHeader}
|
|
255
|
+
`;
|
|
256
|
+
if (varsResponse.vars.length > 0) {
|
|
257
|
+
const csvLine = graphsCsvLine(varsResponse.vars);
|
|
258
|
+
newGraphsCsvContent += `${csvLine}
|
|
259
|
+
`;
|
|
260
|
+
}
|
|
261
|
+
await writeFile(graphsCsvFile, newGraphsCsvContent);
|
|
252
262
|
if (varsResponse.vars.length === 0) {
|
|
253
263
|
ora2().info(dim2(`No variables selected. You can edit the "${cyan("config/graphs.csv")}" file later.`));
|
|
254
264
|
return;
|
|
255
265
|
}
|
|
256
|
-
const graphsCsvFile = joinPath(projDir, "config", "graphs.csv");
|
|
257
|
-
const csvLine = graphsCsvLine(varsResponse.vars);
|
|
258
|
-
let graphsCsvContent = await readFile(graphsCsvFile, "utf8");
|
|
259
|
-
graphsCsvContent += `${csvLine}
|
|
260
|
-
`;
|
|
261
|
-
await writeFile(graphsCsvFile, graphsCsvContent);
|
|
262
266
|
ora2(
|
|
263
267
|
green2(`Added graph to "${bold2("config/graphs.csv")}". ${dim2("You can configure graphs in that file later.")}`)
|
|
264
268
|
).succeed();
|
|
@@ -332,24 +336,29 @@ async function chooseGenSliderConfig(projDir, mdlVars) {
|
|
|
332
336
|
}
|
|
333
337
|
}
|
|
334
338
|
);
|
|
335
|
-
if (varsResponse.vars.length === 0) {
|
|
336
|
-
ora2().info(dim2(`No variables selected. You can edit the "${cyan("config/inputs.csv")}" file later.`));
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
339
|
const inputsCsvFile = joinPath(projDir, "config", "inputs.csv");
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const inputVar = mdlVars.find((v) => v.name === inputVarName);
|
|
344
|
-
if (inputVar && inputVar.kind === "const") {
|
|
345
|
-
const defaultValue = inputVar.value;
|
|
346
|
-
const csvLine = inputsCsvLine(inputVarName, defaultValue, idNumber.toString());
|
|
347
|
-
inputsCsvContent += `${csvLine}
|
|
340
|
+
const origInputsCsvContent = await readFile(inputsCsvFile, "utf8");
|
|
341
|
+
const inputsCsvHeader = origInputsCsvContent.split("\n")[0];
|
|
342
|
+
let newInputsCsvContent = `${inputsCsvHeader}
|
|
348
343
|
`;
|
|
349
|
-
|
|
344
|
+
if (varsResponse.vars.length > 0) {
|
|
345
|
+
let idNumber = 1;
|
|
346
|
+
for (const inputVarName of varsResponse.vars) {
|
|
347
|
+
const inputVar = mdlVars.find((v) => v.name === inputVarName);
|
|
348
|
+
if (inputVar && inputVar.kind === "const") {
|
|
349
|
+
const defaultValue = inputVar.value;
|
|
350
|
+
const csvLine = inputsCsvLine(inputVarName, defaultValue, idNumber.toString());
|
|
351
|
+
newInputsCsvContent += `${csvLine}
|
|
352
|
+
`;
|
|
353
|
+
idNumber++;
|
|
354
|
+
}
|
|
350
355
|
}
|
|
351
356
|
}
|
|
352
|
-
await writeFile(inputsCsvFile,
|
|
357
|
+
await writeFile(inputsCsvFile, newInputsCsvContent);
|
|
358
|
+
if (varsResponse.vars.length === 0) {
|
|
359
|
+
ora2().info(dim2(`No variables selected. You can edit the "${cyan("config/inputs.csv")}" file later.`));
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
353
362
|
const slidersText = varsResponse.vars.length > 1 ? "sliders" : "sliders";
|
|
354
363
|
ora2(
|
|
355
364
|
green2(
|
|
@@ -388,9 +397,10 @@ async function readModelVars(projDir, mdlPath) {
|
|
|
388
397
|
const mdlDir = dirname(mdlFile);
|
|
389
398
|
const mdlName = parsePath(mdlFile).name;
|
|
390
399
|
await parseAndGenerate(mdlContent, spec, ["printVarList"], mdlDir, mdlName, buildDir);
|
|
391
|
-
const
|
|
392
|
-
const
|
|
393
|
-
const
|
|
400
|
+
const jsonListFile = joinPath(buildDir, `${mdlName}.json`);
|
|
401
|
+
const jsonListContent = await readFile(jsonListFile, "utf8");
|
|
402
|
+
const jsonList = JSON.parse(jsonListContent);
|
|
403
|
+
const varObjs = jsonList.variables;
|
|
394
404
|
const mdlVars = [];
|
|
395
405
|
for (const varObj of varObjs) {
|
|
396
406
|
switch (varObj.varType) {
|
|
@@ -686,29 +696,11 @@ async function chooseGitInit(projDir, args) {
|
|
|
686
696
|
}
|
|
687
697
|
|
|
688
698
|
// src/step-mdl.ts
|
|
689
|
-
import { readdir
|
|
690
|
-
import {
|
|
691
|
-
import { bold as bold6,
|
|
699
|
+
import { readdir } from "fs/promises";
|
|
700
|
+
import { relative as relative2, resolve as resolvePath4, sep, posix } from "path";
|
|
701
|
+
import { bold as bold6, dim as dim7, green as green7, yellow as yellow4 } from "kleur/colors";
|
|
692
702
|
import ora7 from "ora";
|
|
693
703
|
import prompts7 from "prompts";
|
|
694
|
-
var sampleMdlContent = `{UTF-8}
|
|
695
|
-
|
|
696
|
-
X = TIME
|
|
697
|
-
~~|
|
|
698
|
-
|
|
699
|
-
Y = 0
|
|
700
|
-
~ [-10,10,0.1]
|
|
701
|
-
~
|
|
702
|
-
|
|
|
703
|
-
|
|
704
|
-
Z = X + Y
|
|
705
|
-
~~|
|
|
706
|
-
|
|
707
|
-
INITIAL TIME = 2000 ~~|
|
|
708
|
-
FINAL TIME = 2100 ~~|
|
|
709
|
-
TIME STEP = 1 ~~|
|
|
710
|
-
SAVEPER = TIME STEP ~~|
|
|
711
|
-
`;
|
|
712
704
|
async function chooseMdlFile(projDir) {
|
|
713
705
|
async function getFiles(dir) {
|
|
714
706
|
const dirents = await readdir(dir, { withFileTypes: true });
|
|
@@ -730,19 +722,11 @@ async function chooseMdlFile(projDir) {
|
|
|
730
722
|
});
|
|
731
723
|
let mdlFile;
|
|
732
724
|
if (mdlFiles.length === 0) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
ora7(
|
|
736
|
-
yellow4(
|
|
737
|
-
`No mdl files were found in "${projDir}". A "${cyan5(
|
|
738
|
-
"sample.mdl"
|
|
739
|
-
)}" file has been added to the project to get you started.`
|
|
740
|
-
)
|
|
741
|
-
).warn();
|
|
742
|
-
mdlFile = "sample.mdl";
|
|
725
|
+
ora7(yellow4(`No mdl files were found in "${projDir}". The mdl file from the template will be used instead.`)).warn();
|
|
726
|
+
mdlFile = void 0;
|
|
743
727
|
} else if (mdlFiles.length === 1) {
|
|
744
|
-
ora7().succeed(`Found "${mdlFiles[0]}", will configure the project to use that mdl file.`);
|
|
745
728
|
mdlFile = mdlFiles[0];
|
|
729
|
+
ora7().succeed(`Found "${mdlFile}", will configure the project to use that mdl file.`);
|
|
746
730
|
} else {
|
|
747
731
|
const options = await prompts7(
|
|
748
732
|
[
|
|
@@ -761,88 +745,105 @@ async function chooseMdlFile(projDir) {
|
|
|
761
745
|
}
|
|
762
746
|
);
|
|
763
747
|
mdlFile = options.mdlFile;
|
|
748
|
+
ora7(green7(`Using "${bold6(mdlFile)}" as the model for the project.`)).succeed();
|
|
764
749
|
}
|
|
765
|
-
ora7(green7(`Using "${bold6(mdlFile)}" as the model for the project.`)).succeed();
|
|
766
750
|
return mdlFile;
|
|
767
751
|
}
|
|
768
752
|
|
|
769
753
|
// src/step-template.ts
|
|
770
|
-
import { existsSync as existsSync4, mkdtempSync, readdirSync, rmSync as rmSync2 } from "fs";
|
|
771
|
-
import { writeFile as
|
|
754
|
+
import { existsSync as existsSync4, mkdtempSync, readdirSync, renameSync, rmSync as rmSync2 } from "fs";
|
|
755
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
772
756
|
import { copy } from "fs-extra";
|
|
773
757
|
import { tmpdir } from "os";
|
|
774
|
-
import { join as
|
|
758
|
+
import { join as joinPath3 } from "path";
|
|
775
759
|
import { downloadTemplate } from "giget";
|
|
776
|
-
import { dim as dim8, green as green8, red as red3, yellow as yellow5 } from "kleur/colors";
|
|
760
|
+
import { bold as bold7, dim as dim8, green as green8, red as red3, yellow as yellow5 } from "kleur/colors";
|
|
777
761
|
import ora8 from "ora";
|
|
778
762
|
import prompts8 from "prompts";
|
|
779
763
|
var TEMPLATES = [
|
|
780
764
|
{
|
|
781
|
-
title: "Default project",
|
|
782
|
-
description: "Includes recommended structure with config files, app, core library, model-check, etc",
|
|
783
|
-
value: "
|
|
765
|
+
title: "Default (jQuery) project",
|
|
766
|
+
description: "Includes recommended structure with config files, jQuery-based app, core library, model-check, etc",
|
|
767
|
+
value: "default"
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
title: "Svelte project",
|
|
771
|
+
description: "Includes recommended structure with config files, Svelte-based app, core library, model-check, etc",
|
|
772
|
+
value: "svelte"
|
|
784
773
|
},
|
|
785
774
|
{
|
|
786
775
|
title: "Minimal project",
|
|
787
776
|
description: "Includes simple config for model-check",
|
|
788
|
-
value: "
|
|
777
|
+
value: "minimal"
|
|
789
778
|
}
|
|
790
779
|
];
|
|
791
|
-
async function chooseTemplate(
|
|
792
|
-
|
|
793
|
-
|
|
780
|
+
async function chooseTemplate(args) {
|
|
781
|
+
let templateName;
|
|
782
|
+
if (args.template) {
|
|
783
|
+
templateName = args.template;
|
|
784
|
+
} else {
|
|
785
|
+
const options = await prompts8(
|
|
786
|
+
[
|
|
787
|
+
{
|
|
788
|
+
type: "select",
|
|
789
|
+
name: "template",
|
|
790
|
+
message: "Which template would you like to use?",
|
|
791
|
+
choices: TEMPLATES
|
|
792
|
+
}
|
|
793
|
+
],
|
|
794
794
|
{
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
}
|
|
800
|
-
],
|
|
801
|
-
{
|
|
802
|
-
onCancel: () => {
|
|
803
|
-
ora8().info(dim8("Operation cancelled."));
|
|
804
|
-
process.exit(0);
|
|
795
|
+
onCancel: () => {
|
|
796
|
+
ora8().info(dim8("Operation cancelled."));
|
|
797
|
+
process.exit(0);
|
|
798
|
+
}
|
|
805
799
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
if (args.dryRun) {
|
|
809
|
-
ora8().info(dim8(`--dry-run enabled, skipping.`));
|
|
810
|
-
return;
|
|
800
|
+
);
|
|
801
|
+
templateName = options.template;
|
|
811
802
|
}
|
|
812
803
|
const defaultRev = "main";
|
|
813
804
|
const commit = args.commit || defaultRev;
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
const workspaceContent = `packages:
|
|
822
|
-
- packages/*
|
|
823
|
-
`;
|
|
824
|
-
await writeFile3(workspaceFile, workspaceContent);
|
|
805
|
+
let baseTemplateUri;
|
|
806
|
+
if (templateName.includes(":")) {
|
|
807
|
+
baseTemplateUri = templateName;
|
|
808
|
+
} else if (templateName.includes("/")) {
|
|
809
|
+
baseTemplateUri = `github:${templateName}`;
|
|
810
|
+
} else {
|
|
811
|
+
baseTemplateUri = `github:climateinteractive/SDEverywhere/examples/template-${templateName}`;
|
|
825
812
|
}
|
|
826
|
-
|
|
813
|
+
const templateUri = `${baseTemplateUri}#${commit}`;
|
|
814
|
+
ora8(green8(`Using "${bold7(templateUri)}" as the template for the project.`)).succeed();
|
|
815
|
+
return {
|
|
816
|
+
uri: templateUri,
|
|
817
|
+
name: templateName
|
|
818
|
+
};
|
|
827
819
|
}
|
|
828
|
-
async function copyTemplate(
|
|
820
|
+
async function copyTemplate(template, projDir, pkgManager, configDirExisted, mdlExisted) {
|
|
821
|
+
const templateSpinner = ora8("Copying template files...").start();
|
|
829
822
|
try {
|
|
830
|
-
const tmpDir = mkdtempSync(
|
|
831
|
-
await downloadTemplate(
|
|
823
|
+
const tmpDir = mkdtempSync(joinPath3(tmpdir(), "sde-create-"));
|
|
824
|
+
await downloadTemplate(template.uri, {
|
|
832
825
|
force: true,
|
|
833
|
-
provider: "github",
|
|
834
826
|
dir: tmpDir
|
|
835
827
|
});
|
|
836
828
|
if (!existsSync4(tmpDir) || readdirSync(tmpDir).length === 0) {
|
|
837
829
|
throw new Error("Failed to download the requested template: the temporary directory is empty.");
|
|
838
830
|
}
|
|
839
|
-
|
|
831
|
+
if (configDirExisted) {
|
|
832
|
+
rmSync2(joinPath3(tmpDir, "config"), { recursive: true, force: true });
|
|
833
|
+
}
|
|
834
|
+
if (mdlExisted) {
|
|
835
|
+
rmSync2(joinPath3(tmpDir, "model"), { recursive: true, force: true });
|
|
836
|
+
}
|
|
837
|
+
await copy(tmpDir, projDir, {
|
|
840
838
|
overwrite: false,
|
|
841
839
|
errorOnExist: false
|
|
842
840
|
});
|
|
841
|
+
if (!mdlExisted) {
|
|
842
|
+
renameSync(joinPath3(projDir, "model", "MODEL_NAME.mdl"), joinPath3(projDir, "model", "sample.mdl"));
|
|
843
|
+
}
|
|
843
844
|
rmSync2(tmpDir, { recursive: true, force: true });
|
|
844
845
|
} catch (e) {
|
|
845
|
-
|
|
846
|
+
templateSpinner.fail();
|
|
846
847
|
console.error(red3(e.message));
|
|
847
848
|
console.error(yellow5("\nThere was a problem copying the template."));
|
|
848
849
|
console.error(
|
|
@@ -852,6 +853,15 @@ async function copyTemplate(templateTarget, dstDir, spinner) {
|
|
|
852
853
|
);
|
|
853
854
|
process.exit(0);
|
|
854
855
|
}
|
|
856
|
+
if (existsSync4(joinPath3(projDir, "packages")) && pkgManager === "pnpm") {
|
|
857
|
+
const workspaceFile = joinPath3(projDir, "pnpm-workspace.yaml");
|
|
858
|
+
const workspaceContent = `packages:
|
|
859
|
+
- packages/*
|
|
860
|
+
`;
|
|
861
|
+
await writeFile2(workspaceFile, workspaceContent);
|
|
862
|
+
}
|
|
863
|
+
templateSpinner.text = green8("Template copied!");
|
|
864
|
+
templateSpinner.succeed();
|
|
855
865
|
}
|
|
856
866
|
|
|
857
867
|
// src/index.ts
|
|
@@ -864,34 +874,44 @@ async function main() {
|
|
|
864
874
|
ora9().info(dim9(`--dry-run enabled, no files will be written.`));
|
|
865
875
|
}
|
|
866
876
|
console.log(`
|
|
867
|
-
${
|
|
877
|
+
${bold8("Welcome to SDEverywhere!")}`);
|
|
868
878
|
console.log(`Let's create a new SDEverywhere project for your model.
|
|
869
879
|
`);
|
|
870
880
|
const projDir = await chooseProjectDir(args);
|
|
871
881
|
console.log();
|
|
872
882
|
const configDirExisted = existsSync5(resolvePath5(projDir, "config"));
|
|
873
|
-
const
|
|
883
|
+
const template = await chooseTemplate(args);
|
|
874
884
|
console.log();
|
|
875
|
-
|
|
885
|
+
let mdlPath = await chooseMdlFile(projDir);
|
|
886
|
+
const mdlExisted = mdlPath !== void 0;
|
|
876
887
|
console.log();
|
|
888
|
+
if (!args.dryRun) {
|
|
889
|
+
await copyTemplate(template, projDir, pkgManager, configDirExisted, mdlExisted);
|
|
890
|
+
console.log();
|
|
891
|
+
}
|
|
892
|
+
if (mdlPath === void 0) {
|
|
893
|
+
mdlPath = `model${posix2.sep}sample.mdl`;
|
|
894
|
+
}
|
|
877
895
|
const genFormat = await chooseCodeFormat();
|
|
878
896
|
if (!args.dryRun) {
|
|
879
897
|
await updateSdeConfig(projDir, mdlPath, genFormat);
|
|
880
|
-
|
|
898
|
+
const modelCheckFilesExist = existsSync5(resolvePath5(projDir, "model", "checks")) || existsSync5(resolvePath5(projDir, "model", "comparisons"));
|
|
899
|
+
if (!modelCheckFilesExist) {
|
|
900
|
+
await generateSampleYamlFiles(projDir);
|
|
901
|
+
}
|
|
881
902
|
}
|
|
882
903
|
console.log();
|
|
883
|
-
if (
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
904
|
+
if (configDirExisted) {
|
|
905
|
+
ora9().succeed(`Found existing "${bold8("config")}" directory.`);
|
|
906
|
+
ora9().info(
|
|
907
|
+
dim9(`You can edit the files in the "${cyan5("config")}" directory later to configure graphs and sliders.`)
|
|
908
|
+
);
|
|
909
|
+
console.log();
|
|
910
|
+
} else {
|
|
911
|
+
const configDirExistsNow = existsSync5(resolvePath5(projDir, "config"));
|
|
912
|
+
if (configDirExistsNow && mdlExisted && !args.dryRun) {
|
|
913
|
+
await chooseGenConfig(projDir, mdlPath);
|
|
889
914
|
console.log();
|
|
890
|
-
} else {
|
|
891
|
-
if (!args.dryRun) {
|
|
892
|
-
await chooseGenConfig(projDir, mdlPath);
|
|
893
|
-
console.log();
|
|
894
|
-
}
|
|
895
915
|
}
|
|
896
916
|
}
|
|
897
917
|
if (genFormat === "c") {
|
|
@@ -909,9 +929,9 @@ ${bgCyan(black(" Next steps "))}
|
|
|
909
929
|
const relProjDir = relative3(process.cwd(), projDir);
|
|
910
930
|
const devCmd = pkgManager === "npm" ? "npm run dev" : `${pkgManager} dev`;
|
|
911
931
|
if (relProjDir !== "") {
|
|
912
|
-
console.log(`You can now ${
|
|
932
|
+
console.log(`You can now ${bold8(cyan5("cd"))} into the ${bold8(cyan5(relProjDir))} project directory.`);
|
|
913
933
|
}
|
|
914
|
-
console.log(`Run ${
|
|
934
|
+
console.log(`Run ${bold8(cyan5(devCmd))} to start the local dev server. ${bold8(cyan5("CTRL-C"))} to close.`);
|
|
915
935
|
console.log("");
|
|
916
936
|
}
|
|
917
937
|
export {
|