proschi 0.4.0 → 0.6.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/server.cjs CHANGED
@@ -25577,22 +25577,30 @@ function stripTrailingComment(text) {
25577
25577
  }
25578
25578
  return text;
25579
25579
  }
25580
- function bracketDepth(text) {
25581
- let depth = 0;
25582
- let inString = false;
25583
- for (let i = 0; i < text.length; i++) {
25584
- const ch = text[i];
25585
- if (inString) {
25586
- if (ch === "\\") i++;
25587
- else if (ch === '"') inString = false;
25588
- continue;
25580
+ var BracketCounter = class {
25581
+ depth = 0;
25582
+ inString = false;
25583
+ escaped = false;
25584
+ /** Adds `text` and returns the depth so far. */
25585
+ feed(text) {
25586
+ for (let i = 0; i < text.length; i++) {
25587
+ const ch = text[i];
25588
+ if (this.escaped) {
25589
+ this.escaped = false;
25590
+ continue;
25591
+ }
25592
+ if (this.inString) {
25593
+ if (ch === "\\") this.escaped = true;
25594
+ else if (ch === '"') this.inString = false;
25595
+ continue;
25596
+ }
25597
+ if (ch === '"') this.inString = true;
25598
+ else if (ch === "{" || ch === "[") this.depth++;
25599
+ else if (ch === "}" || ch === "]") this.depth--;
25589
25600
  }
25590
- if (ch === '"') inString = true;
25591
- else if (ch === "{" || ch === "[") depth++;
25592
- else if (ch === "}" || ch === "]") depth--;
25601
+ return this.depth;
25593
25602
  }
25594
- return depth;
25595
- }
25603
+ };
25596
25604
 
25597
25605
  // ../frontend/src/dsl/paths.ts
25598
25606
  var PARAM2 = /^\{[^{}/]+\}$/;
@@ -25775,6 +25783,7 @@ var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
25775
25783
  var DEFAULT_TECH = "Rectangle";
25776
25784
  var DEFAULT_GROUP_TECH = "Logical Group";
25777
25785
  var MAX_SCENARIOS = 32;
25786
+ var MAX_ALT_DEPTH = 16;
25778
25787
  var REPLICAS = /^x(\d+)$/;
25779
25788
  var PERCENTILES = { p50: 50, p90: 90, p95: 95, p99: 99, p999: 99.9 };
25780
25789
  var FIELD_FLAGS = ["key", "index", "unique", "optional"];
@@ -25802,8 +25811,12 @@ var Parser = class {
25802
25811
  file;
25803
25812
  stack = [];
25804
25813
  diagnostics = [];
25814
+ /** Warnings reported so far (see `warning`). */
25815
+ warned = /* @__PURE__ */ new Set();
25805
25816
  nodes = /* @__PURE__ */ new Map();
25806
25817
  edges = [];
25818
+ /** Connections so far per `from->to`, for the ids of repeated ones. */
25819
+ edgeCount = /* @__PURE__ */ new Map();
25807
25820
  useCases = [];
25808
25821
  references = [];
25809
25822
  imports = [];
@@ -25880,6 +25893,17 @@ var Parser = class {
25880
25893
  const loc = (t) => this.locOf(t, line);
25881
25894
  const top = this.top();
25882
25895
  if (top?.kind === "section") {
25896
+ if (top.skipped !== void 0) {
25897
+ const opens = tokens[tokens.length - 1].kind === "lbrace";
25898
+ if (first.kind !== "rbrace") top.nested = (top.nested ?? 0) + (opens ? 1 : 0);
25899
+ else if (top.nested) top.nested += opens ? 0 : -1;
25900
+ else {
25901
+ this.stack.pop();
25902
+ if (second?.kind === "ident" && second.value === "alt") this.parseAlt(tokens.slice(1), line);
25903
+ else if (second) this.error("Unexpected input after }", loc(second));
25904
+ }
25905
+ return index;
25906
+ }
25883
25907
  if (first.kind === "rbrace") {
25884
25908
  this.stack.pop();
25885
25909
  if (!top.discard) this.closeSection(top);
@@ -26104,6 +26128,12 @@ var Parser = class {
26104
26128
  return;
26105
26129
  }
26106
26130
  this.expectEnd(tokens, i + 1, line);
26131
+ if (this.stack.filter((f) => f.kind === "alt").length >= MAX_ALT_DEPTH) {
26132
+ const loc2 = this.locOf(keyword, line);
26133
+ this.error(`alt blocks can nest at most ${MAX_ALT_DEPTH} deep; this one is skipped`, loc2);
26134
+ this.stack.push({ kind: "section", section: "test", discard: true, skipped: `alt '${nameToken.value}'`, loc: loc2 });
26135
+ return;
26136
+ }
26107
26137
  const owner = top.body;
26108
26138
  let set = owner.openAlt;
26109
26139
  if (!set) {
@@ -26197,12 +26227,16 @@ var Parser = class {
26197
26227
  }
26198
26228
  let label = labelToken?.value ?? "";
26199
26229
  let lastLine = index;
26200
- if (bracketDepth(label) > 0) {
26201
- while (bracketDepth(label) > 0 && lastLine + 1 < this.lines.length) {
26230
+ const brackets = new BracketCounter();
26231
+ let depth = brackets.feed(label);
26232
+ if (depth > 0) {
26233
+ while (depth > 0 && lastLine + 1 < this.lines.length) {
26202
26234
  lastLine++;
26203
- label += "\n" + this.lines[lastLine];
26235
+ const more = "\n" + this.lines[lastLine];
26236
+ label += more;
26237
+ depth = brackets.feed(more);
26204
26238
  }
26205
- if (bracketDepth(label) > 0) this.error("Unclosed { or [ in payload", this.locOf(labelToken, line));
26239
+ if (depth > 0) this.error("Unclosed { or [ in payload", this.locOf(labelToken, line));
26206
26240
  label = label.trimEnd();
26207
26241
  }
26208
26242
  const loc = {
@@ -26237,7 +26271,8 @@ var Parser = class {
26237
26271
  this.error("'-x' marks a failed call and is only allowed in use case steps", this.locOf(arrowToken, line));
26238
26272
  } else {
26239
26273
  const base = `${from}->${to}`;
26240
- const count = this.edges.filter((e) => e.id === base || e.id.startsWith(`${base}#`)).length;
26274
+ const count = this.edgeCount.get(base) ?? 0;
26275
+ this.edgeCount.set(base, count + 1);
26241
26276
  this.edges.push({ id: count ? `${base}#${count + 1}` : base, source: from, target: to, label: unquote(label) || void 0, loc });
26242
26277
  }
26243
26278
  return lastLine;
@@ -27163,7 +27198,12 @@ var Parser = class {
27163
27198
  this.diagnostics.push({ severity: "error", message, ...loc });
27164
27199
  }
27165
27200
  warning(message, loc) {
27166
- if (this.diagnostics.some((d) => d.message === message && d.line === loc.line && d.col === loc.col && d.file === loc.file)) return;
27201
+ const key = `${loc.file ?? ""}
27202
+ ${loc.line}
27203
+ ${loc.col}
27204
+ ${message}`;
27205
+ if (this.warned.has(key)) return;
27206
+ this.warned.add(key);
27167
27207
  this.diagnostics.push({ severity: "warning", message, ...loc });
27168
27208
  }
27169
27209
  };
@@ -27196,6 +27236,7 @@ function isWord(token, word) {
27196
27236
  return token?.kind === "ident" && token.value === word;
27197
27237
  }
27198
27238
  function sectionName(frame) {
27239
+ if (frame.skipped) return frame.skipped;
27199
27240
  if (frame.entity) return `entity '${frame.entity.name}'`;
27200
27241
  if (frame.decision) return `decision '${frame.decision.title}'`;
27201
27242
  if (frame.test) return `test '${frame.test.name}'`;
@@ -27360,13 +27401,13 @@ function classify(lines) {
27360
27401
  }
27361
27402
  if (!inSection && first.kind === "ident" && second?.kind === "arrow" && third?.kind === "ident" && tokens.length <= 4 && (!fourth || fourth.kind === "label")) {
27362
27403
  const entry = { ...base, kind: "connection", from: first.value, arrow: second.value, to: third.value, label: fourth?.value, continuation: [] };
27363
- if (fourth && bracketDepth(fourth.value) > 0) {
27364
- const delta = depth * INDENT.length - width(leadingSpace(raw));
27365
- let label = fourth.value;
27366
- while (bracketDepth(label) > 0 && i + 1 < lines.length) {
27404
+ const brackets = new BracketCounter();
27405
+ if (fourth && brackets.feed(fourth.value) > 0) {
27406
+ const delta = indent(depth).length - width(leadingSpace(raw));
27407
+ while (i + 1 < lines.length) {
27367
27408
  const next = lines[++i];
27368
- label += "\n" + next;
27369
27409
  entry.continuation.push(reindent(next, delta));
27410
+ if (brackets.feed("\n" + next) <= 0) break;
27370
27411
  }
27371
27412
  while (entry.continuation[entry.continuation.length - 1] === "") entry.continuation.pop();
27372
27413
  }
@@ -27507,7 +27548,8 @@ var source = (raw, t) => {
27507
27548
  var withComment = (code, comment) => comment ? code + " " + comment : code;
27508
27549
  var leadingSpace = (line) => /^[ \t]*/.exec(line)[0];
27509
27550
  var width = (space) => [...space].reduce((n, ch) => n + (ch === " " ? INDENT.length : 1), 0);
27510
- var indent = (depth) => INDENT.repeat(depth);
27551
+ var MAX_INDENT = 32;
27552
+ var indent = (depth) => INDENT.repeat(Math.min(depth, MAX_INDENT));
27511
27553
  var len = (s) => [...s].length;
27512
27554
  var pad = (s, to) => s + " ".repeat(Math.max(0, to - len(s)));
27513
27555
 
@@ -28971,7 +29013,7 @@ function positionAt(text, offset) {
28971
29013
 
28972
29014
  // src/server.ts
28973
29015
  if (process.argv.includes("--version")) {
28974
- console.log(true ? "0.4.0" : "dev");
29016
+ console.log(true ? "0.6.0" : "dev");
28975
29017
  process.exit(0);
28976
29018
  }
28977
29019
  var connection = (0, import_node.createConnection)(import_node.ProposedFeatures.all);
@@ -29012,7 +29054,7 @@ connection.onInitialize(() => ({
29012
29054
  documentFormattingProvider: true,
29013
29055
  codeActionProvider: { codeActionKinds: [import_node.CodeActionKind.QuickFix] }
29014
29056
  },
29015
- serverInfo: { name: "proschi-language-server", version: true ? "0.4.0" : "dev" }
29057
+ serverInfo: { name: "proschi-language-server", version: true ? "0.6.0" : "dev" }
29016
29058
  }));
29017
29059
  function validate(document) {
29018
29060
  const analysis = analysisOf(document);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proschi",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Command-line checker and language server for Proschi architecture diagrams",
5
5
  "license": "MIT",
6
6
  "repository": {