@loadmap/cli 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as main } from "./src-0Gq92LO7.js";
2
+ import { n as main } from "./src-uR5aJH2I.js";
3
3
  // src/bin.ts
4
4
  main(process.argv.slice(2)).then((code) => process.exit(code), (err) => {
5
5
  console.error(err instanceof Error ? err.message : err);
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { t as USAGE, o as check, a as fmt, s as github, n as main, r as parseRecord, i as record } from "./src-0Gq92LO7.js";
1
+ export { t as USAGE, o as check, a as fmt, s as github, n as main, r as parseRecord, i as record } from "./src-uR5aJH2I.js";
@@ -588,6 +588,21 @@ function defineModel(def) {
588
588
  firstLimit: first
589
589
  };
590
590
  };
591
+ const resolveStages = (ctx, shed) => {
592
+ const stages = {};
593
+ for (const s of stageIds) {
594
+ const st = resolveStage(s, def.stages[s], ctx, flowIds, thresholds.full);
595
+ stages[s] = st.kind === "pass" || st.kind === "limit" || st.kind === "cache" ? {
596
+ ...st,
597
+ shed: shed(s)
598
+ } : st;
599
+ }
600
+ for (const st of Object.values(stages)) if (st.kind === "fanout") for (const b of Object.values(st.to).flat()) {
601
+ const to = stages[b.stage];
602
+ if (!to || to.kind === "queue" || to.kind === "workers" || to.kind === "fanout") throw new Error(`loadmap: fan-out "${st.id}" branches to "${b.stage}", which is not a sink, store or pass stage`);
603
+ }
604
+ return stages;
605
+ };
591
606
  const evaluate = (partial) => {
592
607
  const values = {
593
608
  ...defaults(),
@@ -632,18 +647,7 @@ function defineModel(def) {
632
647
  const full = edges("fullRange");
633
648
  const flows = {};
634
649
  for (const f of flowIds) flows[f] = ctx.flows[f];
635
- const stages = {};
636
- for (const s of stageIds) {
637
- const st = resolveStage(s, def.stages[s], ctx, flowIds, thresholds.full);
638
- stages[s] = st.kind === "pass" || st.kind === "limit" || st.kind === "cache" ? {
639
- ...st,
640
- shed: shed(s)
641
- } : st;
642
- }
643
- for (const st of Object.values(stages)) if (st.kind === "fanout") for (const b of Object.values(st.to).flat()) {
644
- const to = stages[b.stage];
645
- if (!to || to.kind === "queue" || to.kind === "workers" || to.kind === "fanout") throw new Error(`loadmap: fan-out "${st.id}" branches to "${b.stage}", which is not a sink, store or pass stage`);
646
- }
650
+ const stages = resolveStages(ctx, shed);
647
651
  const overload = {};
648
652
  for (const f of flowIds) overload[f] = overloadOf(f);
649
653
  const at = {};
@@ -710,6 +714,18 @@ function defineModel(def) {
710
714
  return d ? isEnabled(d, values) : false;
711
715
  },
712
716
  evaluate,
717
+ stagesAt: (partial) => {
718
+ const values = {
719
+ ...defaults(),
720
+ ...partial
721
+ };
722
+ const { ctx, shed } = context(def, values);
723
+ return {
724
+ values,
725
+ ctx,
726
+ stages: resolveStages(ctx, shed)
727
+ };
728
+ },
713
729
  utilization: (partial, bound) => {
714
730
  const util = context(def, {
715
731
  ...defaults(),
@@ -1260,6 +1276,8 @@ function defineView(model, def) {
1260
1276
  const nodes = def.nodes;
1261
1277
  for (const e of def.edges) for (const end of [e.from, e.to]) if (!(end in nodes)) throw new Error(`loadmap: edge to unknown node "${end}"`);
1262
1278
  for (const [f, fv] of Object.entries(def.flows)) if (!(fv.from in nodes)) throw new Error(`loadmap: flow "${f}" starts at unknown node "${fv.from}"`);
1279
+ const tiers = def.tiers ?? {};
1280
+ for (const [id, n] of Object.entries(nodes)) if (n.tier != null && !Object.hasOwn(tiers, n.tier)) throw new Error(`loadmap: node "${id}" stands in unknown tier "${n.tier}"`);
1263
1281
  const shows = (n, s) => Array.isArray(n.stage) ? n.stage.includes(s) : n.stage === s;
1264
1282
  for (const s of model.stageIds) if (!Object.values(nodes).some((n) => shows(n, s))) throw new Error(`loadmap: no node shows stage "${s}"`);
1265
1283
  return {
@@ -1486,6 +1504,11 @@ const SUB = {
1486
1504
  scope: "ctx",
1487
1505
  doc: "The second line of the box."
1488
1506
  };
1507
+ const TIER = {
1508
+ value: "tier",
1509
+ scope: "const",
1510
+ doc: "The tier the box stands in; without one, that of the boxes that feed it."
1511
+ };
1489
1512
  const OVERLOAD_WHEN = {
1490
1513
  value: "boolean",
1491
1514
  scope: "ctx",
@@ -1579,6 +1602,7 @@ const SCHEMA = {
1579
1602
  "node",
1580
1603
  "cluster",
1581
1604
  "pool",
1605
+ "tier",
1582
1606
  "thresholds"
1583
1607
  ],
1584
1608
  edges: "edges"
@@ -2021,6 +2045,20 @@ const SCHEMA = {
2021
2045
  props: COMPONENT_PROPS,
2022
2046
  children: []
2023
2047
  },
2048
+ tier: {
2049
+ doc: "A band across the flow (edge, app, data) drawn behind its boxes. Tiers run in the order they are declared.",
2050
+ example: "tier data \"Data\"",
2051
+ args: [{
2052
+ name: "id",
2053
+ kind: "id"
2054
+ }, {
2055
+ name: "label",
2056
+ kind: "text",
2057
+ optional: true
2058
+ }],
2059
+ props: {},
2060
+ children: []
2061
+ },
2024
2062
  node: {
2025
2063
  doc: "A box. It may run a stage (pass, store, sink, fanout) and own a component (demand and capacity lines).",
2026
2064
  example: "node gateway \"API gateway\" { pass; demand: flows.orders; capacity: estimated(20000, \"req/s\") }",
@@ -2033,6 +2071,7 @@ const SCHEMA = {
2033
2071
  values: ["box", "cylinder"],
2034
2072
  doc: "box (the default) or cylinder."
2035
2073
  },
2074
+ tier: TIER,
2036
2075
  ...COMPONENT_PROPS
2037
2076
  },
2038
2077
  children: [
@@ -2063,6 +2102,7 @@ const SCHEMA = {
2063
2102
  scope: "i",
2064
2103
  doc: "Each member's label, from its index i: `broker ${i}`."
2065
2104
  },
2105
+ tier: TIER,
2066
2106
  ...COMPONENT_PROPS
2067
2107
  },
2068
2108
  children: ["queue", "component"]
@@ -2078,6 +2118,7 @@ const SCHEMA = {
2078
2118
  scope: "i",
2079
2119
  doc: "Each pod's label, from its index i: `pod ${i}`."
2080
2120
  },
2121
+ tier: TIER,
2081
2122
  ...COMPONENT_PROPS
2082
2123
  },
2083
2124
  children: ["workers", "component"]
@@ -3771,10 +3812,30 @@ var Compiler = class {
3771
3812
  }
3772
3813
  const searchMax = this.constProp(root, "searchMax");
3773
3814
  if (searchMax != null) model.searchMax = searchMax;
3815
+ const tiers = {};
3816
+ const tierNames = /* @__PURE__ */ new Map();
3817
+ for (const b of byKind("tier")) {
3818
+ if (!b.args.id) continue;
3819
+ this.declare("tier", b.args.id.name, b.args.id, b, tierNames);
3820
+ tiers[b.args.id.name] = { label: this.text(b.args.label) ?? b.args.id.name };
3821
+ }
3774
3822
  const nodes = {};
3775
- for (const box of boxes) nodes[box.id] = this.node(box);
3823
+ for (const box of boxes) {
3824
+ nodes[box.id] = this.node(box);
3825
+ const tier = this.named(box.block, "tier", [...tierNames.keys()], "tier");
3826
+ if (tier) nodes[box.id].tier = tier;
3827
+ }
3776
3828
  const edges = [];
3777
3829
  for (const e of root.edges) edges.push(...this.edges(e, boxById));
3830
+ const tierOf = (id) => {
3831
+ const t = nodes[id]?.tier;
3832
+ return t == null ? void 0 : Object.keys(tiers).indexOf(t);
3833
+ };
3834
+ for (const e of root.edges) e.chain.forEach((to, i) => {
3835
+ const from = e.chain[i - 1];
3836
+ const [a, b] = from ? [tierOf(from.name), tierOf(to.name)] : [];
3837
+ if (from && a != null && b != null && a > b) this.report.warning(to, `${from.name} -> ${to.name} runs back from the tier "${nodes[from.name].tier}" to "${nodes[to.name].tier}"`);
3838
+ });
3778
3839
  if (!flows.length) this.report.error({
3779
3840
  from: 0,
3780
3841
  to: 0
@@ -3796,11 +3857,13 @@ var Compiler = class {
3796
3857
  if (typeof v === "string") options.assumptions.push(v);
3797
3858
  }
3798
3859
  if (this.report.failed) return void 0;
3799
- return this.build(model, {
3860
+ const view = {
3800
3861
  nodes,
3801
3862
  edges,
3802
- flows: flowViews
3803
- }, options, byKind("preset"), byKind("scenario"));
3863
+ flows: flowViews,
3864
+ ...Object.keys(tiers).length ? { tiers } : {}
3865
+ };
3866
+ return this.build(model, view, options, byKind("preset"), byKind("scenario"));
3804
3867
  }
3805
3868
  /** Hands the parts to core and layout, then runs the model once per preset and scenario so formula errors show now. */
3806
3869
  build(modelDef, viewDef, options, presets, scenarios) {