@sdeverywhere/plugin-config 0.2.13 → 0.2.14

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,922 +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
- configProcessor: () => configProcessor
33
- });
34
- module.exports = __toCommonJS(index_exports);
35
-
36
- // ../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.28_typescript@5.2.2_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
37
- var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
38
- var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
39
-
40
- // src/processor.ts
41
- var import_fs3 = require("fs");
42
- var import_path3 = require("path");
43
-
44
- // src/context.ts
45
- var import_fs = require("fs");
46
- var import_path = require("path");
47
- var import_sync = require("csv-parse/sync");
48
-
49
- // src/strings.ts
50
- var import_sanitize_html = __toESM(require("sanitize-html"), 1);
51
- var Strings = class {
52
- constructor() {
53
- this.records = /* @__PURE__ */ new Map();
54
- }
55
- add(key, str, layout2, context, grouping, appendedStringKeys) {
56
- checkInvisibleCharacters(str || "");
57
- if (!key) {
58
- throw new Error(`Must provide a key for the string: ${str}`);
59
- }
60
- const validKey = /^[0-9a-z_]+$/.test(key);
61
- if (!validKey) {
62
- throw new Error(`String key contains undesirable characters: ${key}`);
63
- }
64
- if (!layout2) {
65
- throw new Error(`Must provide a layout (e.g., 'layout1' or 'not-translated')`);
66
- }
67
- if (!context) {
68
- throw new Error(`Must provide a context string: key=${key}, string=${str}`);
69
- }
70
- if (context === "Core") {
71
- context = void 0;
72
- }
73
- if (!grouping) {
74
- grouping = "primary";
75
- }
76
- if (str) {
77
- str = str.trim();
78
- str = htmlToUtf8(str);
79
- }
80
- if (!str) {
81
- return "";
82
- }
83
- if (this.records.has(key)) {
84
- const prefix = key.substring(0, key.indexOf("__"));
85
- switch (prefix) {
86
- case "graph_dataset_label":
87
- case "graph_xaxis_label":
88
- case "graph_yaxis_label":
89
- case "input_group_title":
90
- case "input_range":
91
- case "input_units":
92
- break;
93
- default:
94
- throw new Error(`More than one string with key=${key}`);
95
- }
96
- }
97
- this.records.set(key, {
98
- key,
99
- str,
100
- layout: layout2,
101
- context,
102
- grouping,
103
- appendedStringKeys
104
- });
105
- return key;
106
- }
107
- /**
108
- * Write a `<lang>.js` file containing translated strings for each supported language.
109
- *
110
- * @param context The build context.
111
- * @param dstDir The `strings` directory in the core package.
112
- * @param xlatLangs The set of languages that are configured for translation.
113
- */
114
- writeJsFiles(context, dstDir) {
115
- writeLangJsFiles(
116
- context,
117
- dstDir,
118
- this.records
119
- /*, xlatLangs*/
120
- );
121
- }
122
- };
123
- function getSortedRecords(records) {
124
- return Array.from(records.values()).sort((a, b) => {
125
- return a.key > b.key ? 1 : b.key > a.key ? -1 : 0;
126
- });
127
- }
128
- function checkInvisibleCharacters(s) {
129
- if (s.includes("\xA0")) {
130
- const e = s.replace(/\u00a0/g, "HERE");
131
- throw new Error(
132
- `String contains one or more non-breaking space characters (to fix, replace "HERE" with a normal space):
133
- ${e}`
134
- );
135
- }
136
- }
137
- function utf8SubscriptToHtml(key, s) {
138
- if (key.includes("graph_yaxis_label")) {
139
- s = s.replace(/₂/gi, "2");
140
- s = s.replace(/₃/gi, "3");
141
- s = s.replace(/₄/gi, "4");
142
- s = s.replace(/₆/gi, "6");
143
- return s;
144
- }
145
- s = s.replace(/₂/gi, "<sub>2</sub>");
146
- s = s.replace(/₃/gi, "<sub>3</sub>");
147
- s = s.replace(/₄/gi, "<sub>4</sub>");
148
- s = s.replace(/₆/gi, "<sub>6</sub>");
149
- s = s.replace(/<\/sub> /gi, "</sub>&nbsp;");
150
- return s;
151
- }
152
- function htmlSubscriptAndSuperscriptToUtf8(s) {
153
- s = s.replace(/<sub>(\d)<\/sub>/gi, (_match, p1) => String.fromCharCode(8320 + Number(p1)));
154
- s = s.replace(/<sup>6<\/sup>/gi, "\u2076");
155
- s = s.replace(/<sup>9<\/sup>/gi, "\u2079");
156
- return s;
157
- }
158
- function htmlToUtf8(orig) {
159
- let s = orig;
160
- s = htmlSubscriptAndSuperscriptToUtf8(s);
161
- let clean = (0, import_sanitize_html.default)(s, {
162
- allowedTags: ["a", "b", "br", "i", "em", "li", "p", "strong", "sub", "sup", "ul"],
163
- allowedAttributes: {
164
- a: ["href", "target", "rel"]
165
- }
166
- });
167
- clean = clean.replace(/\u00a0/gi, "&nbsp;");
168
- return clean;
169
- }
170
- function genStringKey(prefix, s) {
171
- checkInvisibleCharacters(s);
172
- let key = s.toLowerCase();
173
- key = key.replace(/ – /g, "_");
174
- key = key.replace(/ \/ /g, "_per_");
175
- key = key.replace(/ /g, "_");
176
- key = key.replace("\u2082", "2");
177
- key = key.replace("<sub>2</sub>", "2");
178
- key = key.replace(/\$\//g, "dollars_per_");
179
- key = key.replace(/%\//g, "pct_per_");
180
- key = key.replace(/\//g, "_per_");
181
- key = key.replace(/º/g, "degrees_");
182
- key = key.replace(/\*/g, "_");
183
- key = key.replace(/%/g, "pct");
184
- key = key.replace(/\$/g, "dollars");
185
- key = key.replace(/&/g, "and");
186
- key = key.replace(/\//g, "per");
187
- key = key.replace(/:/g, "");
188
- key = key.replace(/\./g, "");
189
- key = key.replace(/-/g, "_");
190
- key = key.replace(/—/g, "_");
191
- key = key.replace(/–/g, "_");
192
- key = key.replace(/,/g, "");
193
- key = key.replace(/\(/g, "");
194
- key = key.replace(/\)/g, "");
195
- key = key.replace(/\\n/g, "");
196
- key = key.replace(/<br>/g, "_");
197
- return `${prefix}__${key}`;
198
- }
199
- function writeLangJsFiles(context, dstDir, records) {
200
- const xlatMap = /* @__PURE__ */ new Map();
201
- const sortedRecords = getSortedRecords(records);
202
- const enStrings = /* @__PURE__ */ new Map();
203
- for (const record of sortedRecords) {
204
- const s = record.str;
205
- enStrings.set(record.key, utf8SubscriptToHtml(record.key, s));
206
- }
207
- xlatMap.set("en", enStrings);
208
- for (const lang of xlatMap.keys()) {
209
- const stringsForLang = xlatMap.get(lang);
210
- const stringsObj = Object.fromEntries(stringsForLang);
211
- const json = JSON.stringify(stringsObj, null, 2);
212
- context.writeStagedFile("strings", dstDir, `${lang}.js`, `export default ${json}`);
213
- }
214
- }
215
-
216
- // src/context.ts
217
- var ConfigContext = class {
218
- constructor(buildContext, configDir, strings, colorMap, modelOptions) {
219
- this.buildContext = buildContext;
220
- this.configDir = configDir;
221
- this.strings = strings;
222
- this.colorMap = colorMap;
223
- this.modelOptions = modelOptions;
224
- this.inputSpecs = /* @__PURE__ */ new Map();
225
- this.outputVarNames = /* @__PURE__ */ new Map();
226
- this.staticVarNames = /* @__PURE__ */ new Map();
227
- }
228
- /**
229
- * Read a CSV file of the given name from the config directory.
230
- *
231
- * @param name The base name of the CSV file.
232
- */
233
- readConfigCsvFile(name) {
234
- return readConfigCsvFile(this.configDir, name);
235
- }
236
- /**
237
- * Log a message to the console and/or the in-browser overlay panel.
238
- *
239
- * @param level The log level (verbose, info, error).
240
- * @param msg The message.
241
- */
242
- log(level, msg) {
243
- this.buildContext.log(level, msg);
244
- }
245
- /**
246
- * Format a (subscripted or non-subscripted) model variable name into a canonical
247
- * identifier (with special characters converted to underscore, and subscript/dimension
248
- * parts separated by commas).
249
- *
250
- * @param name The name of the variable in the source model, e.g., `Variable name[DimA, B2]`.
251
- * @returns The canonical identifier for the given name, e.g., `_variable_name[_dima,_b2]`.
252
- */
253
- canonicalVarId(name) {
254
- return this.buildContext.canonicalVarId(name);
255
- }
256
- /**
257
- * Write a file to the staged directory.
258
- *
259
- * This file will be copied (along with other staged files) into the destination
260
- * directory only after the build process has completed. Copying all staged files
261
- * at once helps improve the local development experience by making it so that
262
- * live reloading tools only need to refresh once instead of every time a build
263
- * file is written.
264
- *
265
- * @param srcDir The directory underneath the configured `staged` directory where
266
- * the file will be written (this must be a relative path).
267
- * @param dstDir The absolute path to the destination directory where the staged
268
- * file will be copied when the build has completed.
269
- * @param filename The name of the file.
270
- * @param content The file content.
271
- */
272
- writeStagedFile(srcDir, dstDir, filename, content) {
273
- this.buildContext.writeStagedFile(srcDir, dstDir, filename, content);
274
- }
275
- addInputVariable(inputId, inputVarName, defaultValue, minValue, maxValue) {
276
- const varId = this.buildContext.canonicalVarId(inputVarName);
277
- if (this.inputSpecs.get(varId)) {
278
- console.error(`ERROR: Input variable ${inputVarName} was already added`);
279
- }
280
- this.inputSpecs.set(varId, {
281
- inputId,
282
- varName: inputVarName,
283
- defaultValue,
284
- minValue,
285
- maxValue
286
- });
287
- }
288
- addOutputVariable(outputVarName) {
289
- const varId = this.buildContext.canonicalVarId(outputVarName);
290
- this.outputVarNames.set(varId, outputVarName);
291
- }
292
- addStaticVariable(sourceName, varName) {
293
- const sourceVarNames = this.staticVarNames.get(sourceName);
294
- if (sourceVarNames) {
295
- sourceVarNames.add(varName);
296
- } else {
297
- const varNames = /* @__PURE__ */ new Set();
298
- varNames.add(varName);
299
- this.staticVarNames.set(sourceName, varNames);
300
- }
301
- }
302
- getHexColorForId(colorId) {
303
- return this.colorMap.get(colorId);
304
- }
305
- getOrderedInputs() {
306
- return Array.from(this.inputSpecs.values());
307
- }
308
- getOrderedOutputs() {
309
- const alphabetical = (a, b) => a > b ? 1 : b > a ? -1 : 0;
310
- const varNames = Array.from(this.outputVarNames.values()).sort(alphabetical);
311
- return varNames.map((varName) => {
312
- return {
313
- varName
314
- };
315
- });
316
- }
317
- writeStringsFiles(dstDir) {
318
- this.strings.writeJsFiles(
319
- this.buildContext,
320
- dstDir
321
- /*, xlatLangs*/
322
- );
323
- }
324
- };
325
- function createConfigContext(buildContext, configDir) {
326
- const modelCsv = readConfigCsvFile(configDir, "model")[0];
327
- const graphDefaultMinTime = Number(modelCsv["graph default min time"]);
328
- const graphDefaultMaxTime = Number(modelCsv["graph default max time"]);
329
- const datFilesString = modelCsv["model dat files"];
330
- const origDatFiles = datFilesString.length > 0 ? datFilesString.split(";") : [];
331
- const prepDir = buildContext.config.prepDir;
332
- const projDir = buildContext.config.rootDir;
333
- const datFiles = origDatFiles.map((f) => (0, import_path.join)((0, import_path.relative)(prepDir, projDir), f));
334
- const bundleListing = modelCsv["bundle listing"] === "true";
335
- const customConstants = modelCsv["custom constants"] === "true";
336
- const customLookups = modelCsv["custom lookups"] === "true";
337
- const customOutputs = modelCsv["custom outputs"] === "true";
338
- const modelOptions = {
339
- graphDefaultMinTime,
340
- graphDefaultMaxTime,
341
- datFiles,
342
- bundleListing,
343
- customConstants,
344
- customLookups,
345
- customOutputs
346
- };
347
- const strings = readStringsCsv(configDir);
348
- const colorsCsv = readConfigCsvFile(configDir, "colors");
349
- const colors = /* @__PURE__ */ new Map();
350
- for (const row of colorsCsv) {
351
- const colorId = row["id"];
352
- const hexColor = row["hex code"];
353
- colors.set(colorId, hexColor);
354
- }
355
- return new ConfigContext(buildContext, configDir, strings, colors, modelOptions);
356
- }
357
- function configFilePath(configDir, name, ext) {
358
- return (0, import_path.join)(configDir, `${name}.${ext}`);
359
- }
360
- function readCsvFile(path) {
361
- const data = (0, import_fs.readFileSync)(path, "utf8");
362
- return (0, import_sync.parse)(data, {
363
- columns: true,
364
- trim: true,
365
- skip_empty_lines: true,
366
- skip_records_with_empty_values: true
367
- });
368
- }
369
- function readConfigCsvFile(configDir, name) {
370
- return readCsvFile(configFilePath(configDir, name, "csv"));
371
- }
372
- function readStringsCsv(configDir) {
373
- const strings = new Strings();
374
- const layout2 = "default";
375
- const context = "Core";
376
- const rows = readConfigCsvFile(configDir, "strings");
377
- for (const row of rows) {
378
- const key = row["id"];
379
- let str = row["string"];
380
- str = str ? str.trim() : "";
381
- if (str) {
382
- strings.add(key, str, layout2, context);
383
- }
384
- }
385
- return strings;
386
- }
387
-
388
- // src/gen-model-spec.ts
389
- function writeModelSpec(context, dstDir) {
390
- const inputVarIds = context.getOrderedInputs().map((i) => context.canonicalVarId(i.varName));
391
- const outputVarIds = context.getOrderedOutputs().map((o) => context.canonicalVarId(o.varName));
392
- let tsContent = "";
393
- function emit(s) {
394
- tsContent += s + "\n";
395
- }
396
- emit("// This file is generated by `@sdeverywhere/plugin-config`; do not edit manually!");
397
- emit(`export const inputVarIds: string[] = ${JSON.stringify(inputVarIds, null, 2)}`);
398
- emit(`export const outputVarIds: string[] = ${JSON.stringify(outputVarIds, null, 2)}`);
399
- context.writeStagedFile("model", dstDir, "model-spec.ts", tsContent);
400
- }
401
-
402
- // src/gen-config-specs.ts
403
- var import_fs2 = require("fs");
404
- var import_path2 = require("path");
405
- var import_url = require("url");
406
-
407
- // src/read-config.ts
408
- function optionalString(stringValue) {
409
- if (stringValue !== void 0 && stringValue.length > 0) {
410
- return stringValue;
411
- } else {
412
- return void 0;
413
- }
414
- }
415
- function optionalNumber(stringValue) {
416
- if (stringValue !== void 0 && stringValue.length > 0) {
417
- return Number(stringValue);
418
- } else {
419
- return void 0;
420
- }
421
- }
422
-
423
- // src/gen-graphs.ts
424
- function generateGraphSpecs(context) {
425
- const graphsCsv = context.readConfigCsvFile("graphs");
426
- const graphSpecs = /* @__PURE__ */ new Map();
427
- for (const row of graphsCsv) {
428
- const spec = graphSpecFromCsv(row, context);
429
- if (spec) {
430
- graphSpecs.set(spec.id, spec);
431
- }
432
- }
433
- return graphSpecs;
434
- }
435
- function graphSpecFromCsv(g, context) {
436
- const strings = context.strings;
437
- const layout2 = "default";
438
- function requiredString(key2) {
439
- const value = g[key2];
440
- if (value === void 0 || typeof value !== "string" || value.trim().length === 0) {
441
- throw new Error(`Must specify '${key2}' for graph ${g.id}`);
442
- }
443
- return value;
444
- }
445
- const graphIdParts = requiredString("id").split(";");
446
- const graphId = graphIdParts[0];
447
- const graphIdBaseParts = graphId.split("-");
448
- const graphBaseId = graphIdBaseParts[0];
449
- const title = requiredString("graph title");
450
- const menuTitle = optionalString(g["menu title"]);
451
- const miniTitle = optionalString(g["mini title"]);
452
- const parentMenu = optionalString(g["parent menu"]);
453
- const description = optionalString(g["description"]);
454
- const kindString = optionalString(g["kind"]);
455
- if (!parentMenu) {
456
- context.log("info", `Skipping graph ${graphId} (${title})`);
457
- return void 0;
458
- }
459
- const key = (kind2) => `graph_${graphBaseId.padStart(3, "0")}_${kind2}`;
460
- const strCtxt = (kind2) => {
461
- const parent = htmlToUtf8(parentMenu).replace("&amp;", "&");
462
- const displayTitle = htmlToUtf8(menuTitle || title).replace("&amp;", "&");
463
- return `Graph ${kind2}: ${parent} > ${displayTitle}`;
464
- };
465
- const titleKey = strings.add(key("title"), title, layout2, strCtxt("Title"));
466
- let menuTitleKey;
467
- if (menuTitle) {
468
- menuTitleKey = strings.add(key("menu_title"), menuTitle, layout2, strCtxt("Menu Item"));
469
- }
470
- let miniTitleKey;
471
- if (miniTitle) {
472
- miniTitleKey = strings.add(key("mini_title"), miniTitle, layout2, strCtxt("Title (for Mini View)"));
473
- }
474
- let descriptionKey;
475
- if (description) {
476
- descriptionKey = strings.add(key("description"), description, layout2, strCtxt("Description"), "graph-descriptions");
477
- }
478
- const kind = kindString;
479
- const sideString = optionalString(g["side"]);
480
- const side = sideString;
481
- const unitsString = optionalString(g["units"]);
482
- const altIdString = optionalString(g["alternate"]);
483
- let unitSystem;
484
- let alternates;
485
- if (unitsString && altIdString) {
486
- if (unitsString === "metric") {
487
- unitSystem = "metric";
488
- alternates = [
489
- {
490
- id: altIdString,
491
- unitSystem: "us"
492
- }
493
- ];
494
- } else if (unitsString === "us") {
495
- unitSystem = "us";
496
- alternates = [
497
- {
498
- id: altIdString,
499
- unitSystem: "metric"
500
- }
501
- ];
502
- }
503
- }
504
- const modelOptions = context.modelOptions;
505
- const xMin = optionalNumber(g["x axis min"]) || modelOptions.graphDefaultMinTime;
506
- const xMax = optionalNumber(g["x axis max"]) || modelOptions.graphDefaultMaxTime;
507
- const xAxisLabel = optionalString(g["x axis label"]);
508
- let xAxisLabelKey;
509
- if (xAxisLabel) {
510
- xAxisLabelKey = strings.add(genStringKey("graph_xaxis_label", xAxisLabel), xAxisLabel, layout2, "Graph X-Axis Label");
511
- }
512
- const yMin = optionalNumber(g["y axis min"]) || 0;
513
- const yMax = optionalNumber(g["y axis max"]);
514
- const ySoftMax = optionalNumber(g["y axis soft max"]);
515
- const yFormat = optionalString(g["y axis format"]) || ".0f";
516
- const yAxisLabel = optionalString(g["y axis label"]);
517
- let yAxisLabelKey;
518
- if (yAxisLabel) {
519
- yAxisLabelKey = strings.add(genStringKey("graph_yaxis_label", yAxisLabel), yAxisLabel, layout2, "Graph Y-Axis Label");
520
- }
521
- const datasets = [];
522
- function addDataset(index, overrides) {
523
- const plotKey = (name) => `plot ${index} ${name}`;
524
- const varName = g[plotKey("variable")];
525
- if (!varName) {
526
- return;
527
- }
528
- const varId = context.canonicalVarId(varName);
529
- const externalSourceName = overrides?.sourceName || optionalString(g[plotKey("source")]);
530
- const datasetLabel = optionalString(g[plotKey("label")]);
531
- let labelKey;
532
- if (datasetLabel) {
533
- labelKey = strings.add(
534
- genStringKey("graph_dataset_label", datasetLabel),
535
- datasetLabel,
536
- layout2,
537
- "Graph Dataset Label"
538
- );
539
- }
540
- const colorId = overrides?.colorId || requiredString(plotKey("color"));
541
- const hexColor = context.getHexColorForId(colorId);
542
- if (!hexColor) {
543
- throw new Error(`Graph ${graphId} references an unknown color ${colorId}`);
544
- }
545
- const lineStyleAndModString = optionalString(g[plotKey("style")]) || "line";
546
- const lineStyleParts = lineStyleAndModString.split(";");
547
- const lineStyleString = lineStyleParts[0];
548
- const lineStyleModifierString = lineStyleParts.length > 1 ? lineStyleParts[1] : void 0;
549
- const lineStyle = lineStyleString;
550
- let lineStyleModifiers;
551
- if (lineStyleModifierString) {
552
- lineStyleModifiers = [lineStyleModifierString];
553
- }
554
- if (externalSourceName === void 0 || externalSourceName.startsWith("Scenario") || externalSourceName === "Ref") {
555
- context.addOutputVariable(varName);
556
- } else {
557
- context.addStaticVariable(externalSourceName, varName);
558
- }
559
- const datasetSpec = {
560
- varId,
561
- varName,
562
- externalSourceName,
563
- labelKey,
564
- color: hexColor,
565
- lineStyle,
566
- lineStyleModifiers
567
- };
568
- datasets.push(datasetSpec);
569
- }
570
- for (let i = 1; i <= 11; i++) {
571
- addDataset(i);
572
- }
573
- const legendItems = datasets.filter((dataset) => dataset.labelKey?.length > 0).map((dataset) => {
574
- return {
575
- color: dataset.color,
576
- labelKey: dataset.labelKey
577
- };
578
- });
579
- const graphSpec = {
580
- id: graphId,
581
- kind,
582
- titleKey,
583
- miniTitleKey,
584
- menuTitleKey,
585
- descriptionKey,
586
- side,
587
- unitSystem,
588
- alternates,
589
- xMin,
590
- xMax,
591
- xAxisLabelKey,
592
- yMin,
593
- yMax,
594
- ySoftMax,
595
- yAxisLabelKey,
596
- yFormat,
597
- datasets,
598
- legendItems
599
- };
600
- return graphSpec;
601
- }
602
-
603
- // src/gen-inputs.ts
604
- var layout = "default";
605
- function generateInputsConfig(context) {
606
- const inputsCsv = context.readConfigCsvFile("inputs");
607
- const inputSpecs = /* @__PURE__ */ new Map();
608
- for (const row of inputsCsv) {
609
- const spec = inputSpecFromCsv(row, context);
610
- if (spec) {
611
- inputSpecs.set(spec.id, spec);
612
- }
613
- }
614
- return inputSpecs;
615
- }
616
- function inputSpecFromCsv(r, context) {
617
- const strings = context.strings;
618
- function requiredString(key2) {
619
- const value = r[key2];
620
- if (value === void 0 || typeof value !== "string" || value.trim().length === 0) {
621
- throw new Error(`Must specify '${key2}' for input ${r.id}`);
622
- }
623
- return value;
624
- }
625
- function requiredNumber(key2) {
626
- const stringValue = requiredString(key2);
627
- const numValue = Number(stringValue);
628
- if (numValue === void 0) {
629
- throw new Error(`Must specify numeric '${key2}' for input ${r.id}`);
630
- }
631
- return numValue;
632
- }
633
- const inputIdParts = requiredString("id").split(";");
634
- const inputId = inputIdParts[0];
635
- const viewId = optionalString(r["viewid"]);
636
- const label = optionalString(r["label"]) || "";
637
- const inputType = requiredString("input type");
638
- if (!viewId) {
639
- context.log("info", `Skipping input ${inputId} (${label})`);
640
- return void 0;
641
- }
642
- const description = optionalString(r["description"]);
643
- const key = (kind) => `input_${inputId.padStart(3, "0")}_${kind}`;
644
- const groupTitle = optionalString(r["group name"]);
645
- if (!groupTitle) {
646
- throw new Error(`Must specify 'group name' for input ${inputId}`);
647
- }
648
- const groupTitleKey = genStringKey("input_group_title", groupTitle);
649
- strings.add(groupTitleKey, groupTitle, layout, "Input Group Title");
650
- let typeLabel;
651
- switch (inputType) {
652
- case "slider":
653
- typeLabel = "Slider";
654
- break;
655
- case "switch":
656
- typeLabel = "Switch";
657
- break;
658
- case "checkbox":
659
- typeLabel = "Checkbox";
660
- break;
661
- case "checkbox group":
662
- typeLabel = "Checkbox Group";
663
- break;
664
- default:
665
- throw new Error(`Unexpected input type ${inputType}`);
666
- }
667
- const strCtxt = (kind) => {
668
- const labelText = htmlToUtf8(label).replace("&amp;", "&");
669
- return `${typeLabel} ${kind}: ${groupTitle} > ${labelText}`;
670
- };
671
- const labelKey = strings.add(key("label"), label, layout, strCtxt("Label"));
672
- const listingLabel = optionalString(r["listing label"]);
673
- let listingLabelKey;
674
- if (listingLabel) {
675
- listingLabelKey = strings.add(key("action_label"), listingLabel, layout, strCtxt("Action Label"));
676
- }
677
- let descriptionKey;
678
- if (description) {
679
- descriptionKey = strings.add(key("description"), description, layout, strCtxt("Description"), "input-descriptions");
680
- }
681
- function sliderSpecFromCsv() {
682
- const varName = requiredString("varname");
683
- const varId = context.canonicalVarId(varName);
684
- const defaultValue = requiredNumber("slider/switch default");
685
- const minValue = requiredNumber("slider min");
686
- const maxValue = requiredNumber("slider max");
687
- const step = requiredNumber("slider step");
688
- const reversed = optionalString(r["reversed"]) === "yes";
689
- if (defaultValue < minValue || defaultValue > maxValue) {
690
- let e = `Default value for slider ${inputId} is out of range: `;
691
- e += `default=${defaultValue} min=${minValue} max=${maxValue}`;
692
- throw new Error(e);
693
- }
694
- context.addInputVariable(inputId, varName, defaultValue, minValue, maxValue);
695
- const format = optionalString(r["format"]) || ".0f";
696
- const units = optionalString(r["units"]);
697
- let unitsKey;
698
- if (units) {
699
- unitsKey = strings.add(genStringKey("input_units", units), units, layout, "Slider Units");
700
- }
701
- const rangeInfo = getSliderRangeInfo(r, maxValue, context);
702
- const rangeLabelKeys = rangeInfo.labelKeys;
703
- const rangeDividers = rangeInfo.dividers;
704
- return {
705
- kind: "slider",
706
- id: inputId,
707
- varId,
708
- varName,
709
- defaultValue,
710
- minValue,
711
- maxValue,
712
- step,
713
- reversed,
714
- labelKey,
715
- listingLabelKey,
716
- descriptionKey,
717
- unitsKey,
718
- rangeLabelKeys,
719
- rangeDividers,
720
- format
721
- };
722
- }
723
- function switchSpecFromCsv() {
724
- const varName = requiredString("varname");
725
- const varId = context.canonicalVarId(varName);
726
- const onValue = requiredNumber("enabled value");
727
- const offValue = requiredNumber("disabled value");
728
- const defaultValue = requiredNumber("slider/switch default");
729
- if (defaultValue !== onValue && defaultValue !== offValue) {
730
- throw new Error(
731
- `Invalid default value for switch ${inputId}: off=${offValue} on=${onValue} default=${defaultValue}`
732
- );
733
- }
734
- const minValue = offValue;
735
- const maxValue = onValue;
736
- context.addInputVariable(inputId, varName, defaultValue, minValue, maxValue);
737
- const controlledInputIds = requiredString("controlled input ids");
738
- const controlledParts = controlledInputIds.split("|");
739
- const rowsActiveWhenOff = controlledParts[0].split(";").filter((id) => id.trim().length > 0);
740
- const rowsActiveWhenOn = controlledParts[1].split(";").filter((id) => id.trim().length > 0);
741
- return {
742
- kind: "switch",
743
- id: inputId,
744
- varId,
745
- varName,
746
- labelKey,
747
- listingLabelKey,
748
- descriptionKey,
749
- defaultValue,
750
- offValue,
751
- onValue,
752
- slidersActiveWhenOff: rowsActiveWhenOff,
753
- slidersActiveWhenOn: rowsActiveWhenOn
754
- };
755
- }
756
- let inputSpec;
757
- switch (inputType) {
758
- case "slider": {
759
- inputSpec = sliderSpecFromCsv();
760
- break;
761
- }
762
- case "switch":
763
- case "checkbox": {
764
- inputSpec = switchSpecFromCsv();
765
- break;
766
- }
767
- case "checkbox group":
768
- break;
769
- default:
770
- throw new Error(`Unexpected input type ${inputType}`);
771
- }
772
- return inputSpec;
773
- }
774
- function getSliderRangeInfo(r, maxValue, context) {
775
- const strings = context.strings;
776
- const labelKeys = [];
777
- const dividers = [];
778
- let rangeNum = 1;
779
- while (rangeNum <= 5) {
780
- const label = optionalString(r[`range ${rangeNum} label`]);
781
- if (!label) {
782
- break;
783
- }
784
- const labelKey = strings.add(genStringKey("input_range", label), label, layout, "Slider Range Label");
785
- if (!labelKey) {
786
- break;
787
- }
788
- labelKeys.push(labelKey);
789
- rangeNum++;
790
- }
791
- const numRanges = rangeNum - 1;
792
- for (rangeNum = 2; rangeNum <= numRanges; rangeNum++) {
793
- let divider = optionalNumber(r[`range ${rangeNum} start`]);
794
- if (divider === void 0) {
795
- divider = maxValue;
796
- }
797
- dividers.push(divider);
798
- }
799
- return {
800
- labelKeys,
801
- dividers
802
- };
803
- }
804
-
805
- // src/gen-config-specs.ts
806
- var __dirname = (0, import_path2.dirname)((0, import_url.fileURLToPath)(importMetaUrl));
807
- function generateConfigSpecs(context) {
808
- context.log("verbose", " Reading graph specs");
809
- const graphSpecs = generateGraphSpecs(context);
810
- context.log("verbose", " Reading input specs");
811
- const inputSpecs = generateInputsConfig(context);
812
- context.log("verbose", " Reading extra output variables");
813
- const extraOutputsCsv = context.readConfigCsvFile("outputs");
814
- for (const row of extraOutputsCsv) {
815
- const varName = row["variable name"];
816
- if (varName) {
817
- context.addOutputVariable(varName);
818
- }
819
- }
820
- return {
821
- graphSpecs,
822
- inputSpecs
823
- };
824
- }
825
- function writeConfigSpecs(context, config, dstDir) {
826
- let tsContent = "";
827
- function emit(s) {
828
- tsContent += s + "\n";
829
- }
830
- emit("// This file is generated by `@sdeverywhere/plugin-config`; do not edit manually!");
831
- emit("");
832
- emit(`import type { GraphSpec, InputSpec } from './spec-types'`);
833
- function emitArray(type, values) {
834
- const varName = type.charAt(0).toLowerCase() + type.slice(1) + "s";
835
- const array = Array.from(values);
836
- const json = JSON.stringify(array, null, 2);
837
- emit("");
838
- emit(`export const ${varName}: ${type}[] = ${json}`);
839
- }
840
- emitArray("GraphSpec", config.graphSpecs.values());
841
- emitArray("InputSpec", config.inputSpecs.values());
842
- context.writeStagedFile("config", dstDir, "config-specs.ts", tsContent);
843
- }
844
- function writeSpecTypes(context, dstDir) {
845
- const tsFile = "spec-types.ts";
846
- const tsPath = (0, import_path2.resolve)(__dirname, tsFile);
847
- const tsContent = (0, import_fs2.readFileSync)(tsPath, "utf8");
848
- context.writeStagedFile("config", dstDir, tsFile, tsContent);
849
- }
850
-
851
- // src/processor.ts
852
- function configProcessor(options) {
853
- return (buildContext) => {
854
- return processModelConfig(buildContext, options);
855
- };
856
- }
857
- async function processModelConfig(buildContext, options) {
858
- const t0 = performance.now();
859
- if (!(0, import_fs3.existsSync)(options.config)) {
860
- throw new Error(`The provided config dir '${options.config}' does not exist`);
861
- }
862
- let outModelSpecsDir;
863
- if (options.out) {
864
- if (typeof options.out === "string") {
865
- outModelSpecsDir = (0, import_path3.join)(options.out, "src", "model", "generated");
866
- } else {
867
- outModelSpecsDir = options.out.modelSpecsDir;
868
- }
869
- }
870
- let outConfigSpecsDir;
871
- if (options.out) {
872
- if (typeof options.out === "string") {
873
- outConfigSpecsDir = (0, import_path3.join)(options.out, "src", "config", "generated");
874
- } else {
875
- outConfigSpecsDir = options.out.configSpecsDir;
876
- }
877
- }
878
- let outStringsDir;
879
- if (options.out) {
880
- if (typeof options.out === "string") {
881
- outStringsDir = (0, import_path3.join)(options.out, "strings");
882
- } else {
883
- outStringsDir = options.out.stringsDir;
884
- }
885
- }
886
- const context = createConfigContext(buildContext, options.config);
887
- const modelOptions = context.modelOptions;
888
- context.log("info", "Generating files...");
889
- const configSpecs = generateConfigSpecs(context);
890
- if (outConfigSpecsDir) {
891
- context.log("verbose", " Writing config specs");
892
- writeConfigSpecs(context, configSpecs, outConfigSpecsDir);
893
- writeSpecTypes(context, outConfigSpecsDir);
894
- }
895
- if (outModelSpecsDir) {
896
- context.log("verbose", " Writing model specs");
897
- writeModelSpec(context, outModelSpecsDir);
898
- }
899
- if (outStringsDir) {
900
- context.log("verbose", " Writing strings");
901
- context.writeStringsFiles(outStringsDir);
902
- }
903
- const t1 = performance.now();
904
- const elapsed = ((t1 - t0) / 1e3).toFixed(1);
905
- context.log("info", `Done generating files (${elapsed}s)`);
906
- return {
907
- // Include any additional properties that cannot be derived from the config files
908
- ...options.spec,
909
- inputs: context.getOrderedInputs(),
910
- outputs: context.getOrderedOutputs(),
911
- datFiles: modelOptions.datFiles,
912
- bundleListing: modelOptions.bundleListing,
913
- customConstants: modelOptions.customConstants,
914
- customLookups: modelOptions.customLookups,
915
- customOutputs: modelOptions.customOutputs
916
- };
917
- }
918
- // Annotate the CommonJS export names for ESM import in node:
919
- 0 && (module.exports = {
920
- configProcessor
921
- });
922
- //# sourceMappingURL=index.cjs.map