@the-package-labs/idocs-core 0.5.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/browser.js CHANGED
@@ -6,8 +6,8 @@ import {
6
6
  createIconResolver,
7
7
  normalizeRoot,
8
8
  route
9
- } from "./chunk-Q2NHZ6TV.js";
10
- import "./chunk-ZYFFV7Y7.js";
9
+ } from "./chunk-MUGDM3EQ.js";
10
+ import "./chunk-H77C3DSX.js";
11
11
  export {
12
12
  KNOWN_KEYS,
13
13
  RootSchema,
@@ -0,0 +1,817 @@
1
+ // src/defaults.ts
2
+ var BUILTIN_KINDS = {
3
+ client: { icon: "lucide:monitor", family: "slate" },
4
+ user: { icon: "lucide:user", family: "slate" },
5
+ ui: { icon: "lucide:layout-dashboard", family: "slate" },
6
+ external: { icon: "lucide:cloud", family: "slate" },
7
+ service: { icon: "lucide:server", family: "blue" },
8
+ gateway: { icon: "lucide:route", family: "blue" },
9
+ worker: { icon: "lucide:cog", family: "blue" },
10
+ container: { icon: "lucide:container", family: "blue" },
11
+ function: { icon: "lucide:square-function", family: "blue" },
12
+ database: { icon: "lucide:database", family: "green" },
13
+ cache: { icon: "lucide:zap", family: "green" },
14
+ storage: { icon: "lucide:hard-drive", family: "green" },
15
+ queue: { icon: "lucide:list-ordered", family: "amber" },
16
+ agent: { icon: "lucide:bot", family: "violet" },
17
+ network: { icon: "lucide:network", family: "violet" },
18
+ vm: { icon: "lucide:box", family: "violet" },
19
+ auth: { icon: "lucide:key-round", family: "teal" },
20
+ monitor: { icon: "lucide:activity", family: "teal" },
21
+ entity: { icon: "lucide:table-2", family: "blue" }
22
+ };
23
+ var BUILTIN_EDGE_KINDS = {
24
+ http: { label: "HTTP request / response", color: "ink", width: 1.5 },
25
+ channel: { label: "Persistent channel (websocket, gRPC)", color: "accent", width: 2.4 },
26
+ tunnel: { label: "Overlay tunnel", color: "tunnel", width: 5 },
27
+ queue: { label: "Queue / broker", color: "ok", width: 2, dash: "2 4" },
28
+ ws: { label: "WebSocket", color: "ink", width: 1.6, dash: "7 4" },
29
+ data: { label: "Data access", color: "muted", width: 1.3 },
30
+ relation: { label: "Relation between entities", color: "muted", width: 1.4 }
31
+ };
32
+ var STEP_KIND_COLORS = {
33
+ request: "accent",
34
+ response: "ok",
35
+ error: "bad",
36
+ lookup: "muted",
37
+ event: "warn"
38
+ };
39
+ var DEFAULT_NODE_WIDTH = 178;
40
+ var DEFAULT_ENTITY_WIDTH = 280;
41
+
42
+ // src/geometry.ts
43
+ function polylineLength(points) {
44
+ let total = 0;
45
+ for (let i = 1; i < points.length; i++) total += dist(points[i - 1], points[i]);
46
+ return total;
47
+ }
48
+ function dist(a, b) {
49
+ return Math.hypot(b.x - a.x, b.y - a.y);
50
+ }
51
+ function pointAt(points, d) {
52
+ if (points.length === 0) return { x: 0, y: 0 };
53
+ let left = Math.max(0, d);
54
+ for (let i = 1; i < points.length; i++) {
55
+ const a = points[i - 1];
56
+ const b = points[i];
57
+ const len = dist(a, b);
58
+ if (left <= len || i === points.length - 1) {
59
+ const t = len === 0 ? 0 : Math.min(1, left / len);
60
+ return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
61
+ }
62
+ left -= len;
63
+ }
64
+ return points[points.length - 1];
65
+ }
66
+ function roundedPath(points, radius = 8) {
67
+ if (points.length === 0) return "";
68
+ const first = points[0];
69
+ let d = `M${r(first.x)} ${r(first.y)}`;
70
+ for (let i = 1; i < points.length - 1; i++) {
71
+ const prev = points[i - 1];
72
+ const cur = points[i];
73
+ const next = points[i + 1];
74
+ const inLen = dist(prev, cur);
75
+ const outLen = dist(cur, next);
76
+ const rad = Math.min(radius, inLen / 2, outLen / 2);
77
+ if (rad < 0.5) {
78
+ d += `L${r(cur.x)} ${r(cur.y)}`;
79
+ continue;
80
+ }
81
+ const a = {
82
+ x: cur.x + (prev.x - cur.x) / inLen * rad,
83
+ y: cur.y + (prev.y - cur.y) / inLen * rad
84
+ };
85
+ const b = {
86
+ x: cur.x + (next.x - cur.x) / outLen * rad,
87
+ y: cur.y + (next.y - cur.y) / outLen * rad
88
+ };
89
+ d += `L${r(a.x)} ${r(a.y)}Q${r(cur.x)} ${r(cur.y)} ${r(b.x)} ${r(b.y)}`;
90
+ }
91
+ if (points.length > 1) {
92
+ const last = points[points.length - 1];
93
+ d += `L${r(last.x)} ${r(last.y)}`;
94
+ }
95
+ return d;
96
+ }
97
+ function r(n) {
98
+ return Math.round(n * 10) / 10;
99
+ }
100
+ function letterKey(index) {
101
+ let n = index;
102
+ let out = "";
103
+ do {
104
+ out = String.fromCharCode(65 + n % 26) + out;
105
+ n = Math.floor(n / 26) - 1;
106
+ } while (n >= 0);
107
+ return out;
108
+ }
109
+
110
+ // src/highlight.ts
111
+ var FAMILIES = {
112
+ shell: [
113
+ "sh",
114
+ "bash",
115
+ "zsh",
116
+ "shell",
117
+ "console",
118
+ "shellsession",
119
+ "fish",
120
+ "powershell",
121
+ "pwsh",
122
+ "ps1"
123
+ ],
124
+ yaml: ["yaml", "yml"],
125
+ json: ["json", "jsonc", "json5"],
126
+ http: ["http"],
127
+ ini: ["ini", "toml", "properties"],
128
+ env: ["env", "dotenv"],
129
+ clike: [
130
+ ...["js", "javascript", "jsx", "mjs", "cjs", "ts", "typescript", "tsx", "java", "c", "cpp"],
131
+ ...["c++", "cs", "csharp", "go", "rust", "rs", "swift", "kotlin", "scala", "php", "dart"],
132
+ ...["css", "scss", "less"]
133
+ ],
134
+ hash: [
135
+ ...["py", "python", "rb", "ruby", "perl", "r", "make", "makefile", "dockerfile", "nginx"],
136
+ ...["conf", "hcl", "terraform", "tf", "graphql"]
137
+ ],
138
+ sql: ["sql"]
139
+ };
140
+ var FAMILY_OF = new Map(
141
+ Object.entries(FAMILIES).flatMap(
142
+ ([f, langs]) => langs.map((l) => [l, f])
143
+ )
144
+ );
145
+ var LABELS = {
146
+ sh: "Shell",
147
+ shell: "Shell",
148
+ bash: "Bash",
149
+ zsh: "Zsh",
150
+ fish: "Fish",
151
+ console: "Console",
152
+ shellsession: "Console",
153
+ powershell: "PowerShell",
154
+ pwsh: "PowerShell",
155
+ ps1: "PowerShell",
156
+ bat: "Batch",
157
+ cmd: "Batch",
158
+ yaml: "YAML",
159
+ yml: "YAML",
160
+ json: "JSON",
161
+ jsonc: "JSON",
162
+ json5: "JSON5",
163
+ http: "HTTP",
164
+ env: ".env",
165
+ dotenv: ".env",
166
+ ini: "INI",
167
+ toml: "TOML",
168
+ properties: "Properties",
169
+ text: "Text",
170
+ txt: "Text",
171
+ plain: "Text",
172
+ js: "JavaScript",
173
+ javascript: "JavaScript",
174
+ jsx: "JSX",
175
+ ts: "TypeScript",
176
+ typescript: "TypeScript",
177
+ tsx: "TSX",
178
+ py: "Python",
179
+ python: "Python",
180
+ rb: "Ruby",
181
+ ruby: "Ruby",
182
+ go: "Go",
183
+ rs: "Rust",
184
+ rust: "Rust",
185
+ cs: "C#",
186
+ csharp: "C#",
187
+ cpp: "C++",
188
+ html: "HTML",
189
+ xml: "XML",
190
+ css: "CSS",
191
+ scss: "SCSS",
192
+ sql: "SQL",
193
+ md: "Markdown",
194
+ mdx: "MDX",
195
+ markdown: "Markdown",
196
+ diff: "Diff",
197
+ dockerfile: "Dockerfile",
198
+ graphql: "GraphQL",
199
+ tf: "Terraform",
200
+ terraform: "Terraform",
201
+ hcl: "HCL",
202
+ php: "PHP",
203
+ java: "Java",
204
+ c: "C"
205
+ };
206
+ function languageLabel(lang) {
207
+ const l = (lang ?? "").toLowerCase();
208
+ if (!l) return "Text";
209
+ return LABELS[l] ?? l.charAt(0).toUpperCase() + l.slice(1);
210
+ }
211
+ var Painter = class {
212
+ tokens = [];
213
+ put(text, cls) {
214
+ if (!text) return;
215
+ const last = this.tokens[this.tokens.length - 1];
216
+ if (last && last.cls === cls) last.text += text;
217
+ else this.tokens.push(cls ? { text, cls } : { text });
218
+ }
219
+ };
220
+ function highlight(lang, text) {
221
+ const family = FAMILY_OF.get((lang ?? "").toLowerCase());
222
+ if (!family || !text) return text ? [{ text }] : [];
223
+ const p = new Painter();
224
+ switch (family) {
225
+ case "shell":
226
+ shell(text, p);
227
+ break;
228
+ case "yaml":
229
+ yaml(text, p);
230
+ break;
231
+ case "json":
232
+ json(text, p);
233
+ break;
234
+ case "http":
235
+ http(text, p);
236
+ break;
237
+ case "ini":
238
+ case "env":
239
+ ini(text, p);
240
+ break;
241
+ default:
242
+ generic(text, p, family);
243
+ }
244
+ return p.tokens;
245
+ }
246
+ var THEN_COMMAND = /* @__PURE__ */ new Set([
247
+ ...["sudo", "env", "time", "exec", "xargs", "nohup", "command", "if", "then", "else", "elif"],
248
+ ...["do", "while", "until", "!", "{"]
249
+ ]);
250
+ var SHELL_WORD = /^[^\s|&;<>()'"$`\\]+/;
251
+ var ASSIGN = /^[A-Za-z_][A-Za-z0-9_]*=/;
252
+ var NUMBER = /^[+-]?\d+(\.\d+)?$/;
253
+ function shell(text, p) {
254
+ let i = 0;
255
+ let command = true;
256
+ let continued = false;
257
+ const n = text.length;
258
+ const quoted = (at) => {
259
+ const q = text[at];
260
+ let j = at + 1;
261
+ let chunk = q;
262
+ while (j < n && text[j] !== q) {
263
+ if (q !== "'" && text[j] === "\\" && j + 1 < n) {
264
+ chunk += text.slice(j, j + 2);
265
+ j += 2;
266
+ continue;
267
+ }
268
+ if (q === '"' && text[j] === "$") {
269
+ const v = text.slice(j).match(/^\$(?:\{[^}\n]*\}|[A-Za-z_][A-Za-z0-9_]*|[0-9@*?#!$-])/);
270
+ if (v) {
271
+ p.put(chunk, "string");
272
+ p.put(v[0], "variable");
273
+ chunk = "";
274
+ j += v[0].length;
275
+ continue;
276
+ }
277
+ }
278
+ chunk += text[j];
279
+ j++;
280
+ }
281
+ if (j < n) chunk += q;
282
+ p.put(chunk, "string");
283
+ return Math.min(j + 1, n);
284
+ };
285
+ const value = (at) => {
286
+ const c = text[at];
287
+ if (c === '"' || c === "'" || c === "`") return quoted(at);
288
+ if (c === "$") {
289
+ const v = text.slice(at).match(/^\$(?:\{[^}\n]*\}|[A-Za-z_][A-Za-z0-9_]*|[0-9@*?#!$-])/);
290
+ if (v) {
291
+ p.put(v[0], "variable");
292
+ return at + v[0].length;
293
+ }
294
+ }
295
+ const w = text.slice(at).match(SHELL_WORD);
296
+ if (w) {
297
+ p.put(w[0], NUMBER.test(w[0]) ? "number" : void 0);
298
+ return at + w[0].length;
299
+ }
300
+ return at;
301
+ };
302
+ while (i < n) {
303
+ const c = text[i];
304
+ if (c === "\n") {
305
+ p.put(c);
306
+ i++;
307
+ if (!continued) command = true;
308
+ continued = false;
309
+ continue;
310
+ }
311
+ if (c === " " || c === " " || c === "\r") {
312
+ const ws = text.slice(i).match(/^[ \t\r]+/)?.[0];
313
+ p.put(ws);
314
+ i += ws.length;
315
+ continue;
316
+ }
317
+ if (c === "\\" && (text[i + 1] === "\n" || text[i + 1] === "\r" && text[i + 2] === "\n")) {
318
+ p.put(c, "operator");
319
+ i++;
320
+ continued = true;
321
+ continue;
322
+ }
323
+ if (c === "#" && (i === 0 || /[\s;|&(]/.test(text[i - 1]))) {
324
+ const end = text.indexOf("\n", i);
325
+ const stop = end === -1 ? n : end;
326
+ p.put(text.slice(i, stop), "comment");
327
+ i = stop;
328
+ continue;
329
+ }
330
+ if (c === '"' || c === "'" || c === "`") {
331
+ i = quoted(i);
332
+ command = false;
333
+ continue;
334
+ }
335
+ if (c === "$") {
336
+ if (text[i + 1] === "(") {
337
+ p.put("$(", "operator");
338
+ i += 2;
339
+ command = true;
340
+ continue;
341
+ }
342
+ const at = i;
343
+ i = value(i);
344
+ if (i === at) {
345
+ p.put(c);
346
+ i++;
347
+ }
348
+ command = false;
349
+ continue;
350
+ }
351
+ if ("|&;<>()".includes(c)) {
352
+ const op = text.slice(i).match(/^(?:\|\||&&|>>|<<|[|&;<>()])/)?.[0];
353
+ p.put(op, "operator");
354
+ i += op.length;
355
+ const fd = text.slice(i).match(/^&\d/);
356
+ if (fd && (op === ">" || op === "<")) {
357
+ p.put(fd[0], "operator");
358
+ i += fd[0].length;
359
+ }
360
+ if ("|&;(".includes(c)) command = true;
361
+ continue;
362
+ }
363
+ const word = text.slice(i).match(SHELL_WORD)?.[0];
364
+ if (!word) {
365
+ p.put(c);
366
+ i++;
367
+ continue;
368
+ }
369
+ if (ASSIGN.test(word)) {
370
+ const eq = word.indexOf("=");
371
+ p.put(word.slice(0, eq), "variable");
372
+ p.put("=", "operator");
373
+ i += eq + 1;
374
+ i = value(i);
375
+ continue;
376
+ }
377
+ if (word.startsWith("-") && word.length > 1 && !NUMBER.test(word)) {
378
+ const eq = word.indexOf("=");
379
+ if (eq > 0) {
380
+ p.put(word.slice(0, eq), "flag");
381
+ p.put("=", "operator");
382
+ i += eq + 1;
383
+ i = value(i);
384
+ } else {
385
+ p.put(word, "flag");
386
+ i += word.length;
387
+ }
388
+ continue;
389
+ }
390
+ if (command) {
391
+ p.put(word, "keyword");
392
+ command = THEN_COMMAND.has(word);
393
+ } else {
394
+ p.put(word, NUMBER.test(word) ? "number" : void 0);
395
+ }
396
+ i += word.length;
397
+ }
398
+ }
399
+ var LITERAL = /^(?:true|false|null|yes|no|on|off|~)$/i;
400
+ var SCALAR_NUMBER = /^[+-]?(?:0x[\da-f]+|\d[\d_]*(?:\.\d+)?(?:e[+-]?\d+)?)$/i;
401
+ function scalars(p, s, yaml2) {
402
+ let i = 0;
403
+ let block = false;
404
+ while (i < s.length) {
405
+ const c = s[i];
406
+ if (/\s/.test(c)) {
407
+ const ws = s.slice(i).match(/^\s+/)?.[0];
408
+ p.put(ws);
409
+ i += ws.length;
410
+ } else if ((c === "#" || !yaml2 && c === ";") && (i === 0 || /\s/.test(s[i - 1]))) {
411
+ p.put(s.slice(i), "comment");
412
+ break;
413
+ } else if (c === '"' || c === "'") {
414
+ let j = i + 1;
415
+ while (j < s.length && s[j] !== c) j += c === '"' && s[j] === "\\" ? 2 : 1;
416
+ p.put(s.slice(i, j + 1), "string");
417
+ i = j + 1;
418
+ } else if ("[]{},".includes(c)) {
419
+ p.put(c, "operator");
420
+ i++;
421
+ } else if (yaml2 && /^[|>][+-]?\d*\s*(?:#.*)?$/.test(s.slice(i)) && !s.slice(0, i).trim()) {
422
+ const ind = s.slice(i).match(/^[|>][+-]?\d*/)?.[0];
423
+ p.put(ind, "operator");
424
+ i += ind.length;
425
+ block = true;
426
+ } else if (yaml2 && (c === "&" || c === "*")) {
427
+ const w = s.slice(i).match(/^[^\s[\]{},]+/)?.[0];
428
+ p.put(w, "variable");
429
+ i += w.length;
430
+ } else if (yaml2 && c === "!") {
431
+ const w = s.slice(i).match(/^[^\s[\]{},]+/)?.[0];
432
+ p.put(w, "keyword");
433
+ i += w.length;
434
+ } else {
435
+ const w = s.slice(i).match(/^[^\s[\]{},]+/)?.[0] ?? c;
436
+ p.put(w, SCALAR_NUMBER.test(w) ? "number" : LITERAL.test(w) ? "literal" : void 0);
437
+ i += w.length;
438
+ }
439
+ }
440
+ return block;
441
+ }
442
+ var YAML_KEY = /^("(?:[^"\\]|\\.)*"|'[^']*'|[^\s#'"[\]{},&*!|>%@`][^#]*?)(\s*):(?=\s|$)/;
443
+ function yaml(text, p) {
444
+ let block = -1;
445
+ const lines = text.split("\n");
446
+ lines.forEach((line, idx) => {
447
+ const nl = idx < lines.length - 1 ? "\n" : "";
448
+ const body = line.trimStart();
449
+ const indent = line.length - body.length;
450
+ if (block >= 0) {
451
+ if (!body.trim() || indent > block) {
452
+ p.put(line, body.trim() ? "string" : void 0);
453
+ p.put(nl);
454
+ return;
455
+ }
456
+ block = -1;
457
+ }
458
+ p.put(line.slice(0, indent));
459
+ if (!body) {
460
+ p.put(nl);
461
+ return;
462
+ }
463
+ if (body.startsWith("#")) {
464
+ p.put(body, "comment");
465
+ p.put(nl);
466
+ return;
467
+ }
468
+ let rest = body;
469
+ let at = indent;
470
+ if (/^(?:---|\.\.\.)(?:\s|$)/.test(rest)) {
471
+ p.put(rest.slice(0, 3), "operator");
472
+ rest = rest.slice(3);
473
+ }
474
+ for (let dash = rest.match(/^-(\s+|$)/); dash; dash = rest.match(/^-(\s+|$)/)) {
475
+ p.put("-", "operator");
476
+ p.put(dash[1]);
477
+ at += dash[0].length;
478
+ rest = rest.slice(dash[0].length);
479
+ }
480
+ const key = rest.match(YAML_KEY);
481
+ if (key) {
482
+ p.put(key[1], "key");
483
+ p.put(key[2]);
484
+ p.put(":", "operator");
485
+ rest = rest.slice(key[0].length);
486
+ }
487
+ if (scalars(p, rest, true)) block = key ? at : indent;
488
+ p.put(nl);
489
+ });
490
+ }
491
+ function ini(text, p) {
492
+ const lines = text.split("\n");
493
+ lines.forEach((line, idx) => {
494
+ const nl = idx < lines.length - 1 ? "\n" : "";
495
+ const body = line.trimStart();
496
+ const indent = line.slice(0, line.length - body.length);
497
+ p.put(indent);
498
+ if (/^[#;]/.test(body)) {
499
+ p.put(body, "comment");
500
+ } else if (/^\[.*\]\s*$/.test(body)) {
501
+ p.put(body, "section");
502
+ } else {
503
+ const kv = body.match(/^(export\s+)?([^=#;\s][^=]*?)(\s*)=(\s*)(.*)$/);
504
+ if (kv) {
505
+ if (kv[1]) p.put(kv[1], "keyword");
506
+ p.put(kv[2], "key");
507
+ p.put(kv[3]);
508
+ p.put("=", "operator");
509
+ p.put(kv[4]);
510
+ scalars(p, kv[5], false);
511
+ } else {
512
+ p.put(body);
513
+ }
514
+ }
515
+ p.put(nl);
516
+ });
517
+ }
518
+ function json(text, p) {
519
+ let i = 0;
520
+ const n = text.length;
521
+ while (i < n) {
522
+ const c = text[i];
523
+ if (c === '"') {
524
+ let j = i + 1;
525
+ while (j < n && text[j] !== '"' && text[j] !== "\n") j += text[j] === "\\" ? 2 : 1;
526
+ const end = Math.min(text[j] === '"' ? j + 1 : j, n);
527
+ const isKey = /^\s*:/.test(text.slice(end));
528
+ p.put(text.slice(i, end), isKey ? "key" : "string");
529
+ i = end;
530
+ } else if (c === "/" && text[i + 1] === "/") {
531
+ const e = text.indexOf("\n", i);
532
+ const stop = e === -1 ? n : e;
533
+ p.put(text.slice(i, stop), "comment");
534
+ i = stop;
535
+ } else if (c === "/" && text[i + 1] === "*") {
536
+ const e = text.indexOf("*/", i + 2);
537
+ const stop = e === -1 ? n : e + 2;
538
+ p.put(text.slice(i, stop), "comment");
539
+ i = stop;
540
+ } else if ("{}[],:".includes(c)) {
541
+ p.put(c, "operator");
542
+ i++;
543
+ } else {
544
+ const num = text.slice(i).match(/^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/)?.[0];
545
+ const word = text.slice(i).match(/^[A-Za-z_]\w*/)?.[0];
546
+ if (num) {
547
+ p.put(num, "number");
548
+ i += num.length;
549
+ } else if (word) {
550
+ p.put(word, /^(?:true|false|null)$/.test(word) ? "literal" : void 0);
551
+ i += word.length;
552
+ } else {
553
+ p.put(c);
554
+ i++;
555
+ }
556
+ }
557
+ }
558
+ }
559
+ var METHODS = /^(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS|TRACE|CONNECT)(\s+)(\S+)(?:(\s+)(HTTP\/[\d.]+))?(.*)$/;
560
+ var STATUS = /^(HTTP\/[\d.]+)(\s+)(\d{3})(.*)$/;
561
+ function http(text, p) {
562
+ const lines = text.split("\n");
563
+ let state = "start";
564
+ for (let idx = 0; idx < lines.length; idx++) {
565
+ const line = lines[idx];
566
+ const nl = idx < lines.length - 1 ? "\n" : "";
567
+ if (state === "body") {
568
+ const rest = lines.slice(idx).join("\n");
569
+ if (/^\s*[{[]/.test(rest)) json(rest, p);
570
+ else p.put(rest);
571
+ return;
572
+ }
573
+ if (!line.trim()) {
574
+ state = "body";
575
+ p.put(line + nl);
576
+ continue;
577
+ }
578
+ const req = state === "start" ? line.match(METHODS) : null;
579
+ const res = state === "start" && !req ? line.match(STATUS) : null;
580
+ const header = line.match(/^([A-Za-z][\w-]*)(\s*)(:)(.*)$/);
581
+ if (req) {
582
+ p.put(req[1], "keyword");
583
+ p.put(req[2]);
584
+ p.put(req[3]);
585
+ p.put(req[4] ?? "");
586
+ p.put(req[5] ?? "", "literal");
587
+ p.put(req[6]);
588
+ } else if (res) {
589
+ p.put(res[1], "literal");
590
+ p.put(res[2]);
591
+ p.put(res[3], "number");
592
+ p.put(res[4]);
593
+ } else if (header) {
594
+ p.put(header[1], "key");
595
+ p.put(header[2]);
596
+ p.put(":", "operator");
597
+ p.put(header[4]);
598
+ } else {
599
+ p.put(line);
600
+ }
601
+ state = "headers";
602
+ p.put(nl);
603
+ }
604
+ }
605
+ var NUM_AT = /^(?:0x[\da-f]+|\d[\d_]*(?:\.\d+)?(?:e[+-]?\d+)?)/i;
606
+ var IDENT = /^[A-Za-z_$][\w$]*/;
607
+ function generic(text, p, family) {
608
+ let i = 0;
609
+ const n = text.length;
610
+ while (i < n) {
611
+ const c = text[i];
612
+ const prev = text[i - 1] ?? "";
613
+ const lineComment = family === "clike" && c === "/" && text[i + 1] === "/" && prev !== ":" || family === "hash" && c === "#" && (i === 0 || /\s/.test(prev)) || family === "sql" && c === "-" && text[i + 1] === "-";
614
+ if (lineComment) {
615
+ const e = text.indexOf("\n", i);
616
+ const stop = e === -1 ? n : e;
617
+ p.put(text.slice(i, stop), "comment");
618
+ i = stop;
619
+ } else if (family !== "hash" && c === "/" && text[i + 1] === "*") {
620
+ const e = text.indexOf("*/", i + 2);
621
+ const stop = e === -1 ? n : e + 2;
622
+ p.put(text.slice(i, stop), "comment");
623
+ i = stop;
624
+ } else if (c === '"' || c === "'" || c === "`") {
625
+ const triple = family === "hash" && c !== "`" && text.startsWith(c.repeat(3), i);
626
+ let j = i + (triple ? 3 : 1);
627
+ let closed = false;
628
+ while (j < n) {
629
+ if (text[j] === "\\") {
630
+ j += 2;
631
+ } else if (triple ? text.startsWith(c.repeat(3), j) : text[j] === c) {
632
+ closed = true;
633
+ break;
634
+ } else if (c !== "`" && !triple && text[j] === "\n") {
635
+ break;
636
+ } else {
637
+ j++;
638
+ }
639
+ }
640
+ const stop = Math.min(closed ? j + (triple ? 3 : 1) : j, n);
641
+ p.put(text.slice(i, stop), "string");
642
+ i = stop;
643
+ } else if (/[A-Za-z_$]/.test(c)) {
644
+ const id = text.slice(i).match(IDENT)?.[0];
645
+ p.put(id);
646
+ i += id.length;
647
+ } else if (/\d/.test(c) && !/[\w$]/.test(prev)) {
648
+ const num = text.slice(i).match(NUM_AT)?.[0];
649
+ p.put(num, "number");
650
+ i += num.length;
651
+ } else {
652
+ p.put(c);
653
+ i++;
654
+ }
655
+ }
656
+ }
657
+ var HOLE = "\uE000";
658
+ function highlightSegments(lang, segments) {
659
+ const vars = segments.filter(
660
+ (s) => s.kind === "var"
661
+ );
662
+ const text = segments.map((s) => s.kind === "text" ? s.text.replaceAll(HOLE, "\uFFFD") : HOLE).join("");
663
+ const out = [];
664
+ let next = 0;
665
+ for (const t of highlight(lang, text)) {
666
+ t.text.split(HOLE).forEach((part, i) => {
667
+ if (i > 0) out.push({ kind: "var", segment: vars[next++] });
668
+ if (part)
669
+ out.push(t.cls ? { kind: "text", text: part, cls: t.cls } : { kind: "text", text: part });
670
+ });
671
+ }
672
+ return out;
673
+ }
674
+
675
+ // src/placeholders.ts
676
+ var TOKEN = /\\([{<][A-Za-z_][\w-]*[}>])|(?<![${])\{([A-Za-z_][\w-]*)\}(?!\})|(?<!<)<([A-Za-z_][\w-]*)>/g;
677
+ function varKey(name) {
678
+ return name.toLowerCase().replace(/-/g, "_");
679
+ }
680
+ var SECRET = /(^|_)(pat|token|jwt|secret|password|passwd|pwd|apikey|key|credentials?)s?($|_)/;
681
+ function isSecretKey(key) {
682
+ return SECRET.test(key);
683
+ }
684
+ function splitPlaceholders(text) {
685
+ const out = [];
686
+ const push = (s) => {
687
+ if (!s) return;
688
+ const last = out[out.length - 1];
689
+ if (last?.kind === "text") last.text += s;
690
+ else out.push({ kind: "text", text: s });
691
+ };
692
+ let at = 0;
693
+ for (const m of text.matchAll(TOKEN)) {
694
+ push(text.slice(at, m.index));
695
+ at = m.index + m[0].length;
696
+ if (m[1] !== void 0) {
697
+ push(m[1]);
698
+ continue;
699
+ }
700
+ const name = m[2] ?? m[3];
701
+ out.push({ kind: "var", raw: m[0], name, key: varKey(name) });
702
+ }
703
+ push(text.slice(at));
704
+ return out;
705
+ }
706
+ function placeholdersOf(segments) {
707
+ const seen = /* @__PURE__ */ new Map();
708
+ for (const s of segments) {
709
+ if (s.kind === "var" && !seen.has(s.key)) {
710
+ seen.set(s.key, { key: s.key, name: s.name, raw: s.raw, secret: isSecretKey(s.key) });
711
+ }
712
+ }
713
+ return [...seen.values()];
714
+ }
715
+ function valueFor(values, key) {
716
+ const v = Object.hasOwn(values, key) ? values[key] : void 0;
717
+ return typeof v === "string" && v !== "" ? v : void 0;
718
+ }
719
+ function fillSegments(segments, values) {
720
+ return segments.map((s) => s.kind === "text" ? s.text : valueFor(values, s.key) ?? s.raw).join("");
721
+ }
722
+ function fillPlaceholders(text, values) {
723
+ return fillSegments(splitPlaceholders(text), values);
724
+ }
725
+ function unsetPlaceholders(segments, values) {
726
+ return placeholdersOf(segments).filter((p) => valueFor(values, p.key) === void 0);
727
+ }
728
+ var MASK = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
729
+ function shownPlaceholder(segment, values) {
730
+ const v = valueFor(values, segment.key);
731
+ if (v === void 0) return { text: segment.raw, state: "unset" };
732
+ return isSecretKey(segment.key) ? { text: MASK, state: "secret" } : { text: v, state: "set" };
733
+ }
734
+ var COMMAND_LANGUAGES = /* @__PURE__ */ new Set([
735
+ "",
736
+ "sh",
737
+ "bash",
738
+ "shell",
739
+ "zsh",
740
+ "fish",
741
+ "console",
742
+ "shellsession",
743
+ "powershell",
744
+ "pwsh",
745
+ "ps1",
746
+ "bat",
747
+ "cmd",
748
+ "text",
749
+ "txt",
750
+ "plain",
751
+ "env",
752
+ "dotenv",
753
+ "ini",
754
+ "toml",
755
+ "yaml",
756
+ "yml",
757
+ "http"
758
+ ]);
759
+ function takesPlaceholders(lang, meta) {
760
+ const words = (meta ?? "").split(/\s+/);
761
+ if (words.includes("novars")) return false;
762
+ if (words.includes("vars")) return true;
763
+ return COMMAND_LANGUAGES.has((lang ?? "").toLowerCase());
764
+ }
765
+
766
+ // src/suggest.ts
767
+ function didYouMean(word, options) {
768
+ let best;
769
+ let bestDist = Math.max(2, Math.floor(word.length / 3)) + 1;
770
+ for (const o of options) {
771
+ const d = levenshtein(word.toLowerCase(), o.toLowerCase());
772
+ if (d < bestDist) {
773
+ best = o;
774
+ bestDist = d;
775
+ }
776
+ }
777
+ return best ? `Did you mean "${best}"?` : void 0;
778
+ }
779
+ function levenshtein(a, b) {
780
+ const row = Array.from({ length: b.length + 1 }, (_, i) => i);
781
+ for (let i = 1; i <= a.length; i++) {
782
+ let prev = row[0];
783
+ row[0] = i;
784
+ for (let j = 1; j <= b.length; j++) {
785
+ const tmp = row[j];
786
+ row[j] = Math.min(row[j] + 1, row[j - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
787
+ prev = tmp;
788
+ }
789
+ }
790
+ return row[b.length];
791
+ }
792
+
793
+ export {
794
+ BUILTIN_KINDS,
795
+ BUILTIN_EDGE_KINDS,
796
+ STEP_KIND_COLORS,
797
+ DEFAULT_NODE_WIDTH,
798
+ DEFAULT_ENTITY_WIDTH,
799
+ polylineLength,
800
+ dist,
801
+ pointAt,
802
+ roundedPath,
803
+ letterKey,
804
+ languageLabel,
805
+ highlight,
806
+ highlightSegments,
807
+ didYouMean,
808
+ varKey,
809
+ isSecretKey,
810
+ splitPlaceholders,
811
+ placeholdersOf,
812
+ fillSegments,
813
+ fillPlaceholders,
814
+ unsetPlaceholders,
815
+ shownPlaceholder,
816
+ takesPlaceholders
817
+ };
@@ -3,8 +3,12 @@ import {
3
3
  BUILTIN_KINDS,
4
4
  DEFAULT_ENTITY_WIDTH,
5
5
  didYouMean,
6
- letterKey
7
- } from "./chunk-ZYFFV7Y7.js";
6
+ highlightSegments,
7
+ languageLabel,
8
+ letterKey,
9
+ splitPlaceholders,
10
+ takesPlaceholders
11
+ } from "./chunk-H77C3DSX.js";
8
12
 
9
13
  // src/icon-resolver.ts
10
14
  import { getIconData, iconToSVG } from "@iconify/utils";
@@ -104,7 +108,62 @@ import remarkGfm from "remark-gfm";
104
108
  import remarkParse from "remark-parse";
105
109
  import remarkRehype from "remark-rehype";
106
110
  import { unified } from "unified";
107
- var processor = unified().use(remarkParse).use(remarkGfm).use(remarkRehype).use(rehypeStringify);
111
+ var isElement = (n, tag) => n.type === "element" && (tag === void 0 || n.tagName === tag);
112
+ var classesOf = (el2) => {
113
+ const c = el2.properties.className;
114
+ return Array.isArray(c) ? c.map(String) : typeof c === "string" ? c.split(/\s+/) : [];
115
+ };
116
+ var titleOf = (meta) => {
117
+ const m = meta?.match(/\btitle=(?:"([^"]*)"|'([^']*)')/);
118
+ return m?.[1] ?? m?.[2];
119
+ };
120
+ var el = (tagName, properties, children = []) => ({ type: "element", tagName, properties, children });
121
+ function commandBlocks() {
122
+ const wrap = (pre) => {
123
+ const code = pre.children.find((c) => isElement(c, "code"));
124
+ if (!code || !isElement(code)) return pre;
125
+ const lang = classesOf(code).find((c) => c.startsWith("language-"))?.slice("language-".length);
126
+ const title = titleOf(code.data?.meta);
127
+ if (code.children.every((c) => c.type === "text")) {
128
+ const text = code.children.map((c) => c.value).join("");
129
+ const segments = takesPlaceholders(lang, code.data?.meta) ? splitPlaceholders(text) : [{ kind: "text", text }];
130
+ code.children = highlightSegments(lang, segments).map((piece) => {
131
+ if (piece.kind === "var") {
132
+ const { key, raw } = piece.segment;
133
+ return el("span", { className: ["idocs-ph"], dataKey: key, dataRaw: raw }, [
134
+ { type: "text", value: raw }
135
+ ]);
136
+ }
137
+ return piece.cls ? el("span", { className: [`hl-${piece.cls}`] }, [{ type: "text", value: piece.text }]) : { type: "text", value: piece.text };
138
+ });
139
+ }
140
+ return el(
141
+ "div",
142
+ { className: ["idocs-cmd"], dataIdocsCmd: "", ...lang ? { dataLang: lang } : {} },
143
+ [
144
+ el("div", { className: ["idocs-cmd-head"] }, [
145
+ el("span", { className: ["idocs-cmd-lang"] }, [
146
+ { type: "text", value: languageLabel(lang) }
147
+ ]),
148
+ ...title ? [el("span", { className: ["idocs-cmd-title"] }, [{ type: "text", value: title }])] : [],
149
+ el("div", { className: ["idocs-cmd-bar"] })
150
+ ]),
151
+ pre,
152
+ el("div", { className: ["idocs-cmd-panel"] })
153
+ ]
154
+ );
155
+ };
156
+ const walk = (node) => {
157
+ if (!("children" in node) || !node.children) return;
158
+ node.children = node.children.map((c) => {
159
+ if (isElement(c, "pre")) return wrap(c);
160
+ walk(c);
161
+ return c;
162
+ });
163
+ };
164
+ return (tree) => walk(tree);
165
+ }
166
+ var processor = unified().use(remarkParse).use(remarkGfm).use(remarkRehype).use(commandBlocks).use(rehypeStringify);
108
167
  function renderMarkdown(md) {
109
168
  const body = stripFrontmatter(md).trim();
110
169
  if (!body) return "";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  didYouMean
3
- } from "./chunk-ZYFFV7Y7.js";
3
+ } from "./chunk-H77C3DSX.js";
4
4
 
5
5
  // src/nesting.ts
6
6
  function nestedDiagrams(all, name) {
@@ -0,0 +1,21 @@
1
+ import type { PlaceholderSegment } from './placeholders';
2
+ export type TokenClass = 'comment' | 'string' | 'keyword' | 'flag' | 'number' | 'variable' | 'key' | 'literal' | 'operator' | 'section';
3
+ export interface Token {
4
+ text: string;
5
+ cls?: TokenClass;
6
+ }
7
+ /** The name of a language as a block's header shows it. Blocks with none are text. */
8
+ export declare function languageLabel(lang: string | undefined): string;
9
+ export declare function highlight(lang: string | undefined, text: string): Token[];
10
+ export type Piece = {
11
+ kind: 'text';
12
+ text: string;
13
+ cls?: TokenClass;
14
+ } | {
15
+ kind: 'var';
16
+ segment: Extract<PlaceholderSegment, {
17
+ kind: 'var';
18
+ }>;
19
+ };
20
+ /** A block's text as pieces to draw: coloured runs, with each placeholder where it was. */
21
+ export declare function highlightSegments(lang: string | undefined, segments: PlaceholderSegment[]): Piece[];
package/dist/index.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  export * from './defaults';
2
2
  export * from './geometry';
3
+ export * from './highlight';
3
4
  export * from './layout';
4
5
  export * from './nested-layout';
5
6
  export * from './nesting';
6
7
  export * from './outline';
7
8
  export * from './phases';
9
+ export * from './placeholders';
8
10
  export * from './route';
9
11
  export * from './scrubber';
10
12
  export * from './start';
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  attachNested,
3
3
  linkDiagrams,
4
4
  nestedDiagrams
5
- } from "./chunk-P2X2XSBM.js";
5
+ } from "./chunk-RJUH342Z.js";
6
6
  import {
7
7
  BUILTIN_EDGE_KINDS,
8
8
  BUILTIN_KINDS,
@@ -10,11 +10,23 @@ import {
10
10
  DEFAULT_NODE_WIDTH,
11
11
  STEP_KIND_COLORS,
12
12
  dist,
13
+ fillPlaceholders,
14
+ fillSegments,
15
+ highlight,
16
+ highlightSegments,
17
+ isSecretKey,
18
+ languageLabel,
13
19
  letterKey,
20
+ placeholdersOf,
14
21
  pointAt,
15
22
  polylineLength,
16
- roundedPath
17
- } from "./chunk-ZYFFV7Y7.js";
23
+ roundedPath,
24
+ shownPlaceholder,
25
+ splitPlaceholders,
26
+ takesPlaceholders,
27
+ unsetPlaceholders,
28
+ varKey
29
+ } from "./chunk-H77C3DSX.js";
18
30
 
19
31
  // src/layout.ts
20
32
  import ELK from "elkjs/lib/elk.bundled.js";
@@ -1575,9 +1587,15 @@ export {
1575
1587
  defaultExpanded,
1576
1588
  defaultMode,
1577
1589
  dist,
1590
+ fillPlaceholders,
1591
+ fillSegments,
1578
1592
  frameAt,
1579
1593
  hasPhases,
1594
+ highlight,
1595
+ highlightSegments,
1596
+ isSecretKey,
1580
1597
  labelWidth,
1598
+ languageLabel,
1581
1599
  layoutNested,
1582
1600
  layoutView,
1583
1601
  letterKey,
@@ -1589,6 +1607,7 @@ export {
1589
1607
  packGrid,
1590
1608
  pathJoin,
1591
1609
  phaseSpans,
1610
+ placeholdersOf,
1592
1611
  pointAt,
1593
1612
  polylineLength,
1594
1613
  positionAt,
@@ -1597,11 +1616,16 @@ export {
1597
1616
  routeEdges,
1598
1617
  runBounds,
1599
1618
  scopeSvgIds,
1619
+ shownPlaceholder,
1600
1620
  slotAt,
1601
1621
  slotOfStep,
1622
+ splitPlaceholders,
1602
1623
  startOf,
1603
1624
  stepAt,
1604
1625
  stepEnd,
1605
1626
  stepStart,
1606
- timeAt
1627
+ takesPlaceholders,
1628
+ timeAt,
1629
+ unsetPlaceholders,
1630
+ varKey
1607
1631
  };
package/dist/node.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  attachNested,
3
3
  linkDiagrams,
4
4
  nestedDiagrams
5
- } from "./chunk-P2X2XSBM.js";
5
+ } from "./chunk-RJUH342Z.js";
6
6
  import {
7
7
  FamilySchema,
8
8
  KNOWN_KEYS,
@@ -11,8 +11,8 @@ import {
11
11
  compileDiagram,
12
12
  createIconResolver,
13
13
  renderMarkdown
14
- } from "./chunk-Q2NHZ6TV.js";
15
- import "./chunk-ZYFFV7Y7.js";
14
+ } from "./chunk-MUGDM3EQ.js";
15
+ import "./chunk-H77C3DSX.js";
16
16
 
17
17
  // src/node.ts
18
18
  import { existsSync, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
@@ -0,0 +1,40 @@
1
+ export type PlaceholderSegment = {
2
+ kind: 'text';
3
+ text: string;
4
+ } | {
5
+ kind: 'var';
6
+ /** As written, braces or angle brackets included: `{yourname}`. */
7
+ raw: string;
8
+ /** As written, without them: `yourname`. */
9
+ name: string;
10
+ /** What `{Token}`, `<token>` and `<TOKEN>` share, so one value fills them all. */
11
+ key: string;
12
+ };
13
+ export interface Placeholder {
14
+ key: string;
15
+ /** The first spelling in the text. */
16
+ name: string;
17
+ raw: string;
18
+ /** A token or a password: kept in memory, never stored, masked on the page. */
19
+ secret: boolean;
20
+ }
21
+ export declare function varKey(name: string): string;
22
+ export declare function isSecretKey(key: string): boolean;
23
+ export declare function splitPlaceholders(text: string): PlaceholderSegment[];
24
+ /** Each distinct placeholder once, in the order the text first uses it. */
25
+ export declare function placeholdersOf(segments: PlaceholderSegment[]): Placeholder[];
26
+ /** The text to copy: values where the reader set them, the placeholder as written where not. */
27
+ export declare function fillSegments(segments: PlaceholderSegment[], values: Record<string, string>): string;
28
+ export declare function fillPlaceholders(text: string, values: Record<string, string>): string;
29
+ /** Placeholders in `segments` the reader has not set. */
30
+ export declare function unsetPlaceholders(segments: PlaceholderSegment[], values: Record<string, string>): Placeholder[];
31
+ export interface Shown {
32
+ text: string;
33
+ state: 'unset' | 'set' | 'secret';
34
+ }
35
+ /** What the page shows in place of a placeholder: the value, a mask for a secret, or the placeholder. */
36
+ export declare function shownPlaceholder(segment: Extract<PlaceholderSegment, {
37
+ kind: 'var';
38
+ }>, values: Record<string, string>): Shown;
39
+ /** Whether a code block takes placeholders: by language, and `vars` / `novars` in the fence info decide otherwise. */
40
+ export declare function takesPlaceholders(lang: string | undefined, meta: string | undefined): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@the-package-labs/idocs-core",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -1,149 +0,0 @@
1
- // src/defaults.ts
2
- var BUILTIN_KINDS = {
3
- client: { icon: "lucide:monitor", family: "slate" },
4
- user: { icon: "lucide:user", family: "slate" },
5
- ui: { icon: "lucide:layout-dashboard", family: "slate" },
6
- external: { icon: "lucide:cloud", family: "slate" },
7
- service: { icon: "lucide:server", family: "blue" },
8
- gateway: { icon: "lucide:route", family: "blue" },
9
- worker: { icon: "lucide:cog", family: "blue" },
10
- container: { icon: "lucide:container", family: "blue" },
11
- function: { icon: "lucide:square-function", family: "blue" },
12
- database: { icon: "lucide:database", family: "green" },
13
- cache: { icon: "lucide:zap", family: "green" },
14
- storage: { icon: "lucide:hard-drive", family: "green" },
15
- queue: { icon: "lucide:list-ordered", family: "amber" },
16
- agent: { icon: "lucide:bot", family: "violet" },
17
- network: { icon: "lucide:network", family: "violet" },
18
- vm: { icon: "lucide:box", family: "violet" },
19
- auth: { icon: "lucide:key-round", family: "teal" },
20
- monitor: { icon: "lucide:activity", family: "teal" },
21
- entity: { icon: "lucide:table-2", family: "blue" }
22
- };
23
- var BUILTIN_EDGE_KINDS = {
24
- http: { label: "HTTP request / response", color: "ink", width: 1.5 },
25
- channel: { label: "Persistent channel (websocket, gRPC)", color: "accent", width: 2.4 },
26
- tunnel: { label: "Overlay tunnel", color: "tunnel", width: 5 },
27
- queue: { label: "Queue / broker", color: "ok", width: 2, dash: "2 4" },
28
- ws: { label: "WebSocket", color: "ink", width: 1.6, dash: "7 4" },
29
- data: { label: "Data access", color: "muted", width: 1.3 },
30
- relation: { label: "Relation between entities", color: "muted", width: 1.4 }
31
- };
32
- var STEP_KIND_COLORS = {
33
- request: "accent",
34
- response: "ok",
35
- error: "bad",
36
- lookup: "muted",
37
- event: "warn"
38
- };
39
- var DEFAULT_NODE_WIDTH = 178;
40
- var DEFAULT_ENTITY_WIDTH = 280;
41
-
42
- // src/geometry.ts
43
- function polylineLength(points) {
44
- let total = 0;
45
- for (let i = 1; i < points.length; i++) total += dist(points[i - 1], points[i]);
46
- return total;
47
- }
48
- function dist(a, b) {
49
- return Math.hypot(b.x - a.x, b.y - a.y);
50
- }
51
- function pointAt(points, d) {
52
- if (points.length === 0) return { x: 0, y: 0 };
53
- let left = Math.max(0, d);
54
- for (let i = 1; i < points.length; i++) {
55
- const a = points[i - 1];
56
- const b = points[i];
57
- const len = dist(a, b);
58
- if (left <= len || i === points.length - 1) {
59
- const t = len === 0 ? 0 : Math.min(1, left / len);
60
- return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
61
- }
62
- left -= len;
63
- }
64
- return points[points.length - 1];
65
- }
66
- function roundedPath(points, radius = 8) {
67
- if (points.length === 0) return "";
68
- const first = points[0];
69
- let d = `M${r(first.x)} ${r(first.y)}`;
70
- for (let i = 1; i < points.length - 1; i++) {
71
- const prev = points[i - 1];
72
- const cur = points[i];
73
- const next = points[i + 1];
74
- const inLen = dist(prev, cur);
75
- const outLen = dist(cur, next);
76
- const rad = Math.min(radius, inLen / 2, outLen / 2);
77
- if (rad < 0.5) {
78
- d += `L${r(cur.x)} ${r(cur.y)}`;
79
- continue;
80
- }
81
- const a = {
82
- x: cur.x + (prev.x - cur.x) / inLen * rad,
83
- y: cur.y + (prev.y - cur.y) / inLen * rad
84
- };
85
- const b = {
86
- x: cur.x + (next.x - cur.x) / outLen * rad,
87
- y: cur.y + (next.y - cur.y) / outLen * rad
88
- };
89
- d += `L${r(a.x)} ${r(a.y)}Q${r(cur.x)} ${r(cur.y)} ${r(b.x)} ${r(b.y)}`;
90
- }
91
- if (points.length > 1) {
92
- const last = points[points.length - 1];
93
- d += `L${r(last.x)} ${r(last.y)}`;
94
- }
95
- return d;
96
- }
97
- function r(n) {
98
- return Math.round(n * 10) / 10;
99
- }
100
- function letterKey(index) {
101
- let n = index;
102
- let out = "";
103
- do {
104
- out = String.fromCharCode(65 + n % 26) + out;
105
- n = Math.floor(n / 26) - 1;
106
- } while (n >= 0);
107
- return out;
108
- }
109
-
110
- // src/suggest.ts
111
- function didYouMean(word, options) {
112
- let best;
113
- let bestDist = Math.max(2, Math.floor(word.length / 3)) + 1;
114
- for (const o of options) {
115
- const d = levenshtein(word.toLowerCase(), o.toLowerCase());
116
- if (d < bestDist) {
117
- best = o;
118
- bestDist = d;
119
- }
120
- }
121
- return best ? `Did you mean "${best}"?` : void 0;
122
- }
123
- function levenshtein(a, b) {
124
- const row = Array.from({ length: b.length + 1 }, (_, i) => i);
125
- for (let i = 1; i <= a.length; i++) {
126
- let prev = row[0];
127
- row[0] = i;
128
- for (let j = 1; j <= b.length; j++) {
129
- const tmp = row[j];
130
- row[j] = Math.min(row[j] + 1, row[j - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
131
- prev = tmp;
132
- }
133
- }
134
- return row[b.length];
135
- }
136
-
137
- export {
138
- BUILTIN_KINDS,
139
- BUILTIN_EDGE_KINDS,
140
- STEP_KIND_COLORS,
141
- DEFAULT_NODE_WIDTH,
142
- DEFAULT_ENTITY_WIDTH,
143
- polylineLength,
144
- dist,
145
- pointAt,
146
- roundedPath,
147
- letterKey,
148
- didYouMean
149
- };