@sdeverywhere/build 0.3.3 → 0.3.5

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 CHANGED
@@ -121,6 +121,26 @@ function resolveUserConfig(userConfig, mode, sdeDir, sdeCmdPath) {
121
121
  } else {
122
122
  watchPaths = modelFiles;
123
123
  }
124
+ const rawGenFormat = userConfig.genFormat || "js";
125
+ let genFormat;
126
+ switch (rawGenFormat) {
127
+ case "js":
128
+ genFormat = "js";
129
+ break;
130
+ case "c":
131
+ genFormat = "c";
132
+ break;
133
+ default:
134
+ throw new Error(`The configured genFormat value is invalid; must be either 'js' or 'c'`);
135
+ }
136
+ let outListingFile;
137
+ if (userConfig.outListingFile) {
138
+ if ((0, import_path.isAbsolute)(userConfig.outListingFile)) {
139
+ outListingFile = userConfig.outListingFile;
140
+ } else {
141
+ outListingFile = (0, import_path.resolve)(rootDir, userConfig.outListingFile);
142
+ }
143
+ }
124
144
  return {
125
145
  mode,
126
146
  rootDir,
@@ -128,6 +148,8 @@ function resolveUserConfig(userConfig, mode, sdeDir, sdeCmdPath) {
128
148
  modelFiles,
129
149
  modelInputPaths,
130
150
  watchPaths,
151
+ genFormat,
152
+ outListingFile,
131
153
  sdeDir,
132
154
  sdeCmdPath
133
155
  };
@@ -545,18 +567,33 @@ async function generateModel(context, plugins) {
545
567
  }
546
568
  }
547
569
  for (const plugin of plugins) {
548
- if (plugin.preGenerateC) {
549
- await plugin.preGenerateC(context);
570
+ if (plugin.preGenerateCode) {
571
+ await plugin.preGenerateCode(context, config.genFormat);
550
572
  }
551
573
  }
552
- await generateC(context, config.sdeDir, sdeCmdPath, prepDir);
574
+ await generateCode(context, config.sdeDir, sdeCmdPath, prepDir);
575
+ const generatedCodeFile = `processed.${config.genFormat}`;
576
+ const generatedCodePath = (0, import_path3.join)(prepDir, "build", generatedCodeFile);
553
577
  for (const plugin of plugins) {
554
- if (plugin.postGenerateC) {
555
- const cPath = (0, import_path3.join)(prepDir, "build", "processed.c");
556
- let cContent = await (0, import_promises.readFile)(cPath, "utf8");
557
- cContent = await plugin.postGenerateC(context, cContent);
558
- await (0, import_promises.writeFile)(cPath, cContent);
559
- }
578
+ if (plugin.postGenerateCode) {
579
+ let generatedCodeContent = await (0, import_promises.readFile)(generatedCodePath, "utf8");
580
+ generatedCodeContent = await plugin.postGenerateCode(context, config.genFormat, generatedCodeContent);
581
+ await (0, import_promises.writeFile)(generatedCodePath, generatedCodeContent);
582
+ }
583
+ }
584
+ if (config.genFormat === "js") {
585
+ const outputJsFile = "generated-model.js";
586
+ const stagedOutputJsPath = context.prepareStagedFile("model", outputJsFile, prepDir, outputJsFile);
587
+ await (0, import_promises.copyFile)(generatedCodePath, stagedOutputJsPath);
588
+ }
589
+ if (config.outListingFile) {
590
+ const srcListingJsonPath = (0, import_path3.join)(prepDir, "build", "processed.json");
591
+ const stagedDir = "model";
592
+ const stagedFile = "listing.json";
593
+ const dstDir = (0, import_path3.dirname)(config.outListingFile);
594
+ const dstFile = (0, import_path3.basename)(config.outListingFile);
595
+ const stagedListingJsonPath = context.prepareStagedFile(stagedDir, stagedFile, dstDir, dstFile);
596
+ await (0, import_promises.copyFile)(srcListingJsonPath, stagedListingJsonPath);
560
597
  }
561
598
  const t1 = performance.now();
562
599
  const elapsed = ((t1 - t0) / 1e3).toFixed(1);
@@ -567,7 +604,14 @@ async function preprocessMdl(context, sdeCmdPath, prepDir, modelFile) {
567
604
  await (0, import_promises.copyFile)(modelFile, (0, import_path3.join)(prepDir, "processed.mdl"));
568
605
  const command = sdeCmdPath;
569
606
  const args = ["generate", "--preprocess", "processed.mdl"];
570
- await context.spawnChild(prepDir, command, args);
607
+ const ppOutput = await context.spawnChild(prepDir, command, args, {
608
+ // The default error message from `spawnChild` is not very informative, so the
609
+ // following allows us to throw our own error
610
+ ignoreError: true
611
+ });
612
+ if (ppOutput.exitCode !== 0) {
613
+ throw new Error(`Failed to preprocess mdl file: 'sde generate' command failed (code=${ppOutput.exitCode})`);
614
+ }
571
615
  await (0, import_promises.copyFile)((0, import_path3.join)(prepDir, "build", "processed.mdl"), (0, import_path3.join)(prepDir, "processed.mdl"));
572
616
  }
573
617
  async function flattenMdls(context, sdeCmdPath, prepDir, modelFiles) {
@@ -600,31 +644,44 @@ async function flattenMdls(context, sdeCmdPath, prepDir, modelFiles) {
600
644
  log("error", ` ${line}`);
601
645
  }
602
646
  }
603
- throw new Error(`Flatten command failed (code=${output.exitCode})`);
647
+ throw new Error(`Failed to flatten mdl files: 'sde flatten' command failed (code=${output.exitCode})`);
604
648
  } else if (output.exitCode !== 0) {
605
- throw new Error(`Flatten command failed (code=${output.exitCode})`);
649
+ throw new Error(`Failed to flatten mdl files: 'sde flatten' command failed (code=${output.exitCode})`);
606
650
  }
607
651
  await (0, import_promises.copyFile)((0, import_path3.join)(prepDir, "build", "processed.mdl"), (0, import_path3.join)(prepDir, "processed.mdl"));
608
652
  }
609
- async function generateC(context, sdeDir, sdeCmdPath, prepDir) {
610
- log("verbose", " Generating C code");
653
+ async function generateCode(context, sdeDir, sdeCmdPath, prepDir) {
654
+ const genFormat = context.config.genFormat;
655
+ const genFormatName = genFormat.toUpperCase();
656
+ log("verbose", ` Generating ${genFormatName} code`);
611
657
  const command = sdeCmdPath;
612
- const gencArgs = ["generate", "--genc", "--list", "--spec", "spec.json", "processed"];
613
- await context.spawnChild(prepDir, command, gencArgs, {
658
+ const outFormat = `--outformat=${genFormat}`;
659
+ const genCmdArgs = ["generate", outFormat, "--list", "--spec", "spec.json", "processed"];
660
+ const genCmdOutput = await context.spawnChild(prepDir, command, genCmdArgs, {
614
661
  // By default, ignore lines that start with "WARNING: Data for" since these are often harmless
615
662
  // TODO: Don't filter by default, but make it configurable
616
663
  // ignoredMessageFilter: 'WARNING: Data for'
664
+ // The default error message from `spawnChild` is not very informative, so the
665
+ // following allows us to throw our own error
666
+ ignoreError: true
617
667
  });
618
- const buildDir = (0, import_path3.join)(prepDir, "build");
619
- const sdeCDir = (0, import_path3.join)(sdeDir, "src", "c");
620
- const files = await (0, import_promises.readdir)(sdeCDir);
621
- const copyOps = [];
622
- for (const file of files) {
623
- if (file.endsWith(".c") || file.endsWith(".h")) {
624
- copyOps.push((0, import_promises.copyFile)((0, import_path3.join)(sdeCDir, file), (0, import_path3.join)(buildDir, file)));
668
+ if (genCmdOutput.exitCode !== 0) {
669
+ throw new Error(
670
+ `Failed to generate ${genFormatName} code: 'sde generate' command failed (code=${genCmdOutput.exitCode})`
671
+ );
672
+ }
673
+ if (genFormat === "c") {
674
+ const buildDir = (0, import_path3.join)(prepDir, "build");
675
+ const sdeCDir = (0, import_path3.join)(sdeDir, "src", "c");
676
+ const files = await (0, import_promises.readdir)(sdeCDir);
677
+ const copyOps = [];
678
+ for (const file of files) {
679
+ if (file.endsWith(".c") || file.endsWith(".h")) {
680
+ copyOps.push((0, import_promises.copyFile)((0, import_path3.join)(sdeCDir, file), (0, import_path3.join)(buildDir, file)));
681
+ }
625
682
  }
683
+ await Promise.all(copyOps);
626
684
  }
627
- await Promise.all(copyOps);
628
685
  }
629
686
 
630
687
  // src/build/impl/hash-files.ts
@@ -659,45 +716,44 @@ async function computeInputFilesHash(config) {
659
716
  async function buildOnce(config, userConfig, plugins, options) {
660
717
  const stagedFiles = new StagedFiles(config.prepDir);
661
718
  const context = new BuildContext(config, stagedFiles, options.abortSignal);
662
- let modelSpec;
719
+ const modelHashPath = (0, import_path5.join)(config.prepDir, "model-hash.txt");
720
+ let succeeded = true;
663
721
  try {
664
- modelSpec = await userConfig.modelSpec(context);
665
- if (modelSpec === void 0) {
722
+ const userModelSpec = await userConfig.modelSpec(context);
723
+ if (userModelSpec === void 0) {
666
724
  return (0, import_neverthrow2.err)(new Error("The model spec must be defined"));
667
725
  }
668
- } catch (e) {
669
- return (0, import_neverthrow2.err)(e);
670
- }
671
- for (const plugin of plugins) {
672
- if (plugin.preGenerate) {
673
- plugin.preGenerate(context, modelSpec);
726
+ const modelSpec = resolveModelSpec(userModelSpec);
727
+ for (const plugin of plugins) {
728
+ if (plugin.preGenerate) {
729
+ await plugin.preGenerate(context, modelSpec);
730
+ }
731
+ }
732
+ const specJson = {
733
+ inputVarNames: modelSpec.inputVarNames,
734
+ outputVarNames: modelSpec.outputVarNames,
735
+ externalDatfiles: modelSpec.datFiles,
736
+ bundleListing: modelSpec.bundleListing,
737
+ customLookups: modelSpec.customLookups,
738
+ customOutputs: modelSpec.customOutputs,
739
+ ...modelSpec.options
740
+ };
741
+ const specPath = (0, import_path5.join)(config.prepDir, "spec.json");
742
+ await (0, import_promises2.writeFile)(specPath, JSON.stringify(specJson, null, 2));
743
+ let previousModelHash;
744
+ if ((0, import_fs4.existsSync)(modelHashPath)) {
745
+ previousModelHash = (0, import_fs4.readFileSync)(modelHashPath, "utf8");
746
+ } else {
747
+ previousModelHash = "NONE";
748
+ }
749
+ const inputFilesHash = await computeInputFilesHash(config);
750
+ let needModelGen;
751
+ if (options.forceModelGen === true) {
752
+ needModelGen = true;
753
+ } else {
754
+ const hashMismatch = inputFilesHash !== previousModelHash;
755
+ needModelGen = hashMismatch;
674
756
  }
675
- }
676
- const specJson = {
677
- inputVarNames: modelSpec.inputs.map((input) => input.varName),
678
- outputVarNames: modelSpec.outputs.map((output) => output.varName),
679
- externalDatfiles: modelSpec.datFiles,
680
- ...modelSpec.options
681
- };
682
- const specPath = (0, import_path5.join)(config.prepDir, "spec.json");
683
- await (0, import_promises2.writeFile)(specPath, JSON.stringify(specJson, null, 2));
684
- const modelHashPath = (0, import_path5.join)(config.prepDir, "model-hash.txt");
685
- let previousModelHash;
686
- if ((0, import_fs4.existsSync)(modelHashPath)) {
687
- previousModelHash = (0, import_fs4.readFileSync)(modelHashPath, "utf8");
688
- } else {
689
- previousModelHash = "NONE";
690
- }
691
- const inputFilesHash = await computeInputFilesHash(config);
692
- let needModelGen;
693
- if (options.forceModelGen === true) {
694
- needModelGen = true;
695
- } else {
696
- const hashMismatch = inputFilesHash !== previousModelHash;
697
- needModelGen = hashMismatch;
698
- }
699
- let succeeded = true;
700
- try {
701
757
  if (needModelGen) {
702
758
  await generateModel(context, plugins);
703
759
  (0, import_fs4.writeFileSync)(modelHashPath, inputFilesHash);
@@ -733,6 +789,69 @@ async function buildOnce(config, userConfig, plugins, options) {
733
789
  }
734
790
  return (0, import_neverthrow2.ok)(succeeded);
735
791
  }
792
+ function resolveModelSpec(modelSpec) {
793
+ let inputVarNames;
794
+ let inputSpecs;
795
+ if (modelSpec.inputs.length > 0) {
796
+ const item = modelSpec.inputs[0];
797
+ if (typeof item === "string") {
798
+ inputVarNames = modelSpec.inputs;
799
+ inputSpecs = inputVarNames.map((varName) => {
800
+ return {
801
+ varName
802
+ };
803
+ });
804
+ } else {
805
+ inputSpecs = modelSpec.inputs;
806
+ inputVarNames = inputSpecs.map((spec) => spec.varName);
807
+ }
808
+ } else {
809
+ inputVarNames = [];
810
+ inputSpecs = [];
811
+ }
812
+ let outputVarNames;
813
+ let outputSpecs;
814
+ if (modelSpec.outputs.length > 0) {
815
+ const item = modelSpec.outputs[0];
816
+ if (typeof item === "string") {
817
+ outputVarNames = modelSpec.outputs;
818
+ outputSpecs = outputVarNames.map((varName) => {
819
+ return {
820
+ varName
821
+ };
822
+ });
823
+ } else {
824
+ outputSpecs = modelSpec.outputs;
825
+ outputVarNames = outputSpecs.map((spec) => spec.varName);
826
+ }
827
+ } else {
828
+ outputVarNames = [];
829
+ outputSpecs = [];
830
+ }
831
+ let customLookups;
832
+ if (modelSpec.customLookups !== void 0) {
833
+ customLookups = modelSpec.customLookups;
834
+ } else {
835
+ customLookups = false;
836
+ }
837
+ let customOutputs;
838
+ if (modelSpec.customOutputs !== void 0) {
839
+ customOutputs = modelSpec.customOutputs;
840
+ } else {
841
+ customOutputs = false;
842
+ }
843
+ return {
844
+ inputVarNames,
845
+ inputs: inputSpecs,
846
+ outputVarNames,
847
+ outputs: outputSpecs,
848
+ datFiles: modelSpec.datFiles || [],
849
+ bundleListing: modelSpec.bundleListing === true,
850
+ customLookups,
851
+ customOutputs,
852
+ options: modelSpec.options
853
+ };
854
+ }
736
855
 
737
856
  // src/build/impl/watch.ts
738
857
  var import_path6 = require("path");
@@ -812,28 +931,27 @@ async function build(mode, options) {
812
931
  const messagesPath = (0, import_path7.join)(resolvedConfig.prepDir, "messages.html");
813
932
  const overlayEnabled2 = mode === "development";
814
933
  setOverlayFile(messagesPath, overlayEnabled2);
815
- const plugins = userConfig.plugins || [];
816
- for (const plugin of plugins) {
817
- if (plugin.init) {
818
- await plugin.init(resolvedConfig);
819
- }
820
- }
821
934
  try {
822
- const plugins2 = userConfig.plugins || [];
935
+ const plugins = userConfig.plugins || [];
936
+ for (const plugin of plugins) {
937
+ if (plugin.init) {
938
+ await plugin.init(resolvedConfig);
939
+ }
940
+ }
823
941
  if (mode === "development") {
824
- const buildResult = await buildOnce(resolvedConfig, userConfig, plugins2, {});
942
+ const buildResult = await buildOnce(resolvedConfig, userConfig, plugins, {});
825
943
  if (buildResult.isErr()) {
826
944
  return (0, import_neverthrow3.err)(buildResult.error);
827
945
  }
828
- for (const plugin of plugins2) {
946
+ for (const plugin of plugins) {
829
947
  if (plugin.watch) {
830
948
  await plugin.watch(resolvedConfig);
831
949
  }
832
950
  }
833
- watch(resolvedConfig, userConfig, plugins2);
951
+ watch(resolvedConfig, userConfig, plugins);
834
952
  return (0, import_neverthrow3.ok)({});
835
953
  } else {
836
- const buildResult = await buildOnce(resolvedConfig, userConfig, plugins2, {});
954
+ const buildResult = await buildOnce(resolvedConfig, userConfig, plugins, {});
837
955
  if (buildResult.isErr()) {
838
956
  return (0, import_neverthrow3.err)(buildResult.error);
839
957
  }