@the-package-labs/idocs-core 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.
@@ -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
+ };