markform 0.1.20 → 0.1.22

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.
Files changed (58) hide show
  1. package/README.md +44 -12
  2. package/dist/ai-sdk.d.mts +1 -1
  3. package/dist/ai-sdk.mjs +2 -2
  4. package/dist/{apply-DIvm1b1s.mjs → apply-C7mO7VkZ.mjs} +158 -95
  5. package/dist/apply-C7mO7VkZ.mjs.map +1 -0
  6. package/dist/bin.mjs +1 -1
  7. package/dist/{cli-FFMoEhFS.mjs → cli-C8F9yDsv.mjs} +102 -1225
  8. package/dist/cli-C8F9yDsv.mjs.map +1 -0
  9. package/dist/cli.mjs +1 -1
  10. package/dist/{coreTypes-CkxML8g2.d.mts → coreTypes-BlsJkU1w.d.mts} +28 -2
  11. package/dist/{coreTypes-CPKXf2dc.mjs → coreTypes-CTLr-NGd.mjs} +24 -3
  12. package/dist/coreTypes-CTLr-NGd.mjs.map +1 -0
  13. package/dist/fillRecord-DTl5lnK0.d.mts +345 -0
  14. package/dist/fillRecordRenderer-CruJrLkj.mjs +1256 -0
  15. package/dist/fillRecordRenderer-CruJrLkj.mjs.map +1 -0
  16. package/dist/index.d.mts +22 -342
  17. package/dist/index.mjs +5 -5
  18. package/dist/render.d.mts +74 -0
  19. package/dist/render.mjs +4 -0
  20. package/dist/{session-CK0x28RO.mjs → session-BCcltrLA.mjs} +2 -2
  21. package/dist/{session-CK0x28RO.mjs.map → session-BCcltrLA.mjs.map} +1 -1
  22. package/dist/{session-ZHBi3LVQ.mjs → session-VeSkVrck.mjs} +1 -1
  23. package/dist/{shared-DwdyWmvE.mjs → shared-CsdT2T7k.mjs} +1 -1
  24. package/dist/{shared-DwdyWmvE.mjs.map → shared-CsdT2T7k.mjs.map} +1 -1
  25. package/dist/{shared-BTR35aMz.mjs → shared-fb0nkzQi.mjs} +1 -1
  26. package/dist/{src-wR7GoftB.mjs → src-CbRnGzMK.mjs} +205 -138
  27. package/dist/src-CbRnGzMK.mjs.map +1 -0
  28. package/dist/urlFormat-lls7CsEP.mjs +71 -0
  29. package/dist/urlFormat-lls7CsEP.mjs.map +1 -0
  30. package/docs/markform-apis.md +53 -0
  31. package/examples/movie-research/movie-deep-research-mock-filled.form.md +320 -343
  32. package/examples/movie-research/movie-deep-research.form.md +273 -308
  33. package/examples/movie-research/movie-research-demo.form.md +27 -41
  34. package/examples/parallel/parallel-research.form.md +33 -29
  35. package/examples/parallel/parallel-research.mock.filled.form.md +88 -0
  36. package/examples/rejection-test/rejection-test-mock-filled.form.md +21 -16
  37. package/examples/rejection-test/rejection-test-mock-filled.schema.json +1 -1
  38. package/examples/rejection-test/rejection-test.form.md +17 -15
  39. package/examples/rejection-test/rejection-test.session.yaml +88 -60
  40. package/examples/simple/simple-mock-filled.form.md +113 -126
  41. package/examples/simple/simple-mock-filled.schema.json +2 -3
  42. package/examples/simple/simple-skipped-filled.form.md +112 -129
  43. package/examples/simple/simple-skipped-filled.report.md +8 -8
  44. package/examples/simple/simple-skipped-filled.schema.json +2 -3
  45. package/examples/simple/simple-tags-syntax.form.md +32 -0
  46. package/examples/simple/simple-with-skips.session.yaml +663 -627
  47. package/examples/simple/simple.form.md +97 -113
  48. package/examples/simple/simple.schema.json +2 -3
  49. package/examples/simple/simple.session.yaml +663 -627
  50. package/examples/startup-deep-research/startup-deep-research.form.md +191 -235
  51. package/examples/startup-research/startup-research-mock-filled.form.md +128 -147
  52. package/examples/startup-research/startup-research.form.md +90 -129
  53. package/examples/twitter-thread/twitter-thread.form.md +373 -0
  54. package/package.json +5 -1
  55. package/dist/apply-DIvm1b1s.mjs.map +0 -1
  56. package/dist/cli-FFMoEhFS.mjs.map +0 -1
  57. package/dist/coreTypes-CPKXf2dc.mjs.map +0 -1
  58. package/dist/src-wR7GoftB.mjs.map +0 -1
@@ -0,0 +1,71 @@
1
+
2
+ //#region src/utils/urlFormat.ts
3
+ /**
4
+ * Create a friendly abbreviated display name for a URL.
5
+ * - Drops "www." prefix from domain
6
+ * - Adds first portion of path (up to maxPathChars) if present
7
+ * - Adds ellipsis (…) if path is truncated
8
+ *
9
+ * @param url - The URL to abbreviate
10
+ * @param maxPathChars - Maximum characters to include from the path (default: 12)
11
+ * @returns Friendly abbreviated URL (e.g., "example.com/docs/api…")
12
+ */
13
+ function friendlyUrlAbbrev(url, maxPathChars = 12) {
14
+ try {
15
+ const parsed = new URL(url);
16
+ let hostname = parsed.hostname;
17
+ if (hostname.startsWith("www.")) hostname = hostname.slice(4);
18
+ const path = parsed.pathname.slice(1);
19
+ if (!path) return hostname;
20
+ if (path.length <= maxPathChars) return `${hostname}/${path}`;
21
+ return `${hostname}/${path.slice(0, maxPathChars)}…`;
22
+ } catch {
23
+ let result = url;
24
+ result = result.replace(/^https?:\/\//, "");
25
+ result = result.replace(/^www\./, "");
26
+ const maxLen = 30;
27
+ if (result.length > maxLen) return result.slice(0, maxLen) + "…";
28
+ return result;
29
+ }
30
+ }
31
+ /**
32
+ * Format a URL as a markdown link with a friendly abbreviated display text.
33
+ * The full URL is preserved as the link target.
34
+ *
35
+ * @param url - The URL to format
36
+ * @returns Markdown link in format [friendly-abbrev](url)
37
+ */
38
+ function formatUrlAsMarkdownLink(url) {
39
+ return `[${friendlyUrlAbbrev(url)}](${url})`;
40
+ }
41
+ /**
42
+ * Format bare URLs in text as HTML links with abbreviated display text.
43
+ * Also handles markdown-style links [text](url) for consistency.
44
+ *
45
+ * Processing order:
46
+ * 1. Escape all HTML to prevent XSS
47
+ * 2. Convert markdown links [text](url) to <a> tags
48
+ * 3. Convert bare URLs (not already in links) to <a> tags with abbreviated display
49
+ *
50
+ * @param text - The raw text containing URLs (will be HTML-escaped)
51
+ * @param escapeHtml - Function to escape HTML entities
52
+ * @returns HTML-safe text with URLs converted to <a> tags
53
+ */
54
+ function formatBareUrlsAsHtmlLinks(text, escapeHtml) {
55
+ let result = escapeHtml(text);
56
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, linkText, url) => {
57
+ const cleanUrl = url.replace(/&amp;/g, "&");
58
+ return `<a href="${escapeHtml(cleanUrl)}" target="_blank" class="url-link" data-url="${escapeHtml(cleanUrl)}">${linkText}</a>`;
59
+ });
60
+ result = result.replace(/(?<!href="|data-url="|">)(?:https?:\/\/|www\.)[^\s<>"]+(?<![.,;:!?'")])/g, (url) => {
61
+ const cleanUrl = url.replace(/&amp;/g, "&");
62
+ const fullUrl = cleanUrl.startsWith("www.") ? `https://${cleanUrl}` : cleanUrl;
63
+ const display = friendlyUrlAbbrev(fullUrl);
64
+ return `<a href="${escapeHtml(fullUrl)}" target="_blank" class="url-link" data-url="${escapeHtml(fullUrl)}">${escapeHtml(display)}</a>`;
65
+ });
66
+ return result;
67
+ }
68
+
69
+ //#endregion
70
+ export { formatUrlAsMarkdownLink as n, friendlyUrlAbbrev as r, formatBareUrlsAsHtmlLinks as t };
71
+ //# sourceMappingURL=urlFormat-lls7CsEP.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urlFormat-lls7CsEP.mjs","names":[],"sources":["../src/utils/urlFormat.ts"],"sourcesContent":["/**\n * URL formatting utilities for display and markdown output.\n */\n\n/**\n * Extract the domain (hostname) from a URL.\n * Returns the original string if parsing fails.\n *\n * @param url - The URL to extract the domain from\n * @returns The domain (e.g., \"example.com\") or the original string if invalid\n */\nexport function extractDomain(url: string): string {\n try {\n const parsed = new URL(url);\n return parsed.hostname;\n } catch {\n // If URL parsing fails, try to extract domain-like pattern\n const match = /^(?:https?:\\/\\/)?(?:www\\.)?([^/\\s]+)/i.exec(url);\n if (match?.[1]) {\n return match[1];\n }\n // Return original if we can't extract a domain\n return url;\n }\n}\n\n/**\n * Create a friendly abbreviated display name for a URL.\n * - Drops \"www.\" prefix from domain\n * - Adds first portion of path (up to maxPathChars) if present\n * - Adds ellipsis (…) if path is truncated\n *\n * @param url - The URL to abbreviate\n * @param maxPathChars - Maximum characters to include from the path (default: 12)\n * @returns Friendly abbreviated URL (e.g., \"example.com/docs/api…\")\n */\nexport function friendlyUrlAbbrev(url: string, maxPathChars = 12): string {\n try {\n const parsed = new URL(url);\n // Remove www. prefix from hostname\n let hostname = parsed.hostname;\n if (hostname.startsWith('www.')) {\n hostname = hostname.slice(4);\n }\n\n // Get path without leading slash, excluding query string and hash\n const path = parsed.pathname.slice(1);\n if (!path) {\n return hostname;\n }\n\n // Include path up to maxPathChars\n if (path.length <= maxPathChars) {\n return `${hostname}/${path}`;\n }\n\n // Truncate path and add ellipsis\n return `${hostname}/${path.slice(0, maxPathChars)}…`;\n } catch {\n // If URL parsing fails, try basic cleanup\n let result = url;\n // Remove protocol\n result = result.replace(/^https?:\\/\\//, '');\n // Remove www.\n result = result.replace(/^www\\./, '');\n // Truncate if too long\n const maxLen = 30;\n if (result.length > maxLen) {\n return result.slice(0, maxLen) + '…';\n }\n return result;\n }\n}\n\n/**\n * Format a URL as a markdown link with a friendly abbreviated display text.\n * The full URL is preserved as the link target.\n *\n * @param url - The URL to format\n * @returns Markdown link in format [friendly-abbrev](url)\n */\nexport function formatUrlAsMarkdownLink(url: string): string {\n const display = friendlyUrlAbbrev(url);\n return `[${display}](${url})`;\n}\n\n/**\n * Check if a string looks like a URL.\n *\n * @param str - The string to check\n * @returns true if the string appears to be a URL\n */\nexport function isUrl(str: string): boolean {\n // Check for common URL patterns\n if (str.startsWith('http://') || str.startsWith('https://')) {\n return true;\n }\n // Check for www. prefix\n if (str.startsWith('www.')) {\n return true;\n }\n return false;\n}\n\n/**\n * Format bare URLs in text as HTML links with abbreviated display text.\n * Also handles markdown-style links [text](url) for consistency.\n *\n * Processing order:\n * 1. Escape all HTML to prevent XSS\n * 2. Convert markdown links [text](url) to <a> tags\n * 3. Convert bare URLs (not already in links) to <a> tags with abbreviated display\n *\n * @param text - The raw text containing URLs (will be HTML-escaped)\n * @param escapeHtml - Function to escape HTML entities\n * @returns HTML-safe text with URLs converted to <a> tags\n */\nexport function formatBareUrlsAsHtmlLinks(text: string, escapeHtml: (s: string) => string): string {\n // SECURITY: Escape the entire text first to prevent XSS\n let result = escapeHtml(text);\n\n // Convert markdown links [text](url) to <a> tags\n // After escaping, we need to unescape &amp; back to & for URLs\n result = result.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_match, linkText: string, url: string) => {\n const cleanUrl = url.replace(/&amp;/g, '&');\n return `<a href=\"${escapeHtml(cleanUrl)}\" target=\"_blank\" class=\"url-link\" data-url=\"${escapeHtml(cleanUrl)}\">${linkText}</a>`;\n });\n\n // Convert bare URLs to <a> tags with abbreviated display\n // Uses negative lookbehind to skip URLs that are:\n // - Inside href=\"\" or data-url=\"\" attributes\n // - Inside anchor tag content (preceded by \">)\n // Pattern matches http://, https://, www. URLs\n result = result.replace(\n /(?<!href=\"|data-url=\"|\">)(?:https?:\\/\\/|www\\.)[^\\s<>\"]+(?<![.,;:!?'\")])/g,\n (url: string) => {\n // Unescape &amp; back to & for the actual URL\n const cleanUrl = url.replace(/&amp;/g, '&');\n // Normalize www. URLs to have https://\n const fullUrl = cleanUrl.startsWith('www.') ? `https://${cleanUrl}` : cleanUrl;\n const display = friendlyUrlAbbrev(fullUrl);\n return `<a href=\"${escapeHtml(fullUrl)}\" target=\"_blank\" class=\"url-link\" data-url=\"${escapeHtml(fullUrl)}\">${escapeHtml(display)}</a>`;\n },\n );\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;;AAoCA,SAAgB,kBAAkB,KAAa,eAAe,IAAY;AACxE,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,IAAI;EAE3B,IAAI,WAAW,OAAO;AACtB,MAAI,SAAS,WAAW,OAAO,CAC7B,YAAW,SAAS,MAAM,EAAE;EAI9B,MAAM,OAAO,OAAO,SAAS,MAAM,EAAE;AACrC,MAAI,CAAC,KACH,QAAO;AAIT,MAAI,KAAK,UAAU,aACjB,QAAO,GAAG,SAAS,GAAG;AAIxB,SAAO,GAAG,SAAS,GAAG,KAAK,MAAM,GAAG,aAAa,CAAC;SAC5C;EAEN,IAAI,SAAS;AAEb,WAAS,OAAO,QAAQ,gBAAgB,GAAG;AAE3C,WAAS,OAAO,QAAQ,UAAU,GAAG;EAErC,MAAM,SAAS;AACf,MAAI,OAAO,SAAS,OAClB,QAAO,OAAO,MAAM,GAAG,OAAO,GAAG;AAEnC,SAAO;;;;;;;;;;AAWX,SAAgB,wBAAwB,KAAqB;AAE3D,QAAO,IADS,kBAAkB,IAAI,CACnB,IAAI,IAAI;;;;;;;;;;;;;;;AAkC7B,SAAgB,0BAA0B,MAAc,YAA2C;CAEjG,IAAI,SAAS,WAAW,KAAK;AAI7B,UAAS,OAAO,QAAQ,6BAA6B,QAAQ,UAAkB,QAAgB;EAC7F,MAAM,WAAW,IAAI,QAAQ,UAAU,IAAI;AAC3C,SAAO,YAAY,WAAW,SAAS,CAAC,+CAA+C,WAAW,SAAS,CAAC,IAAI,SAAS;GACzH;AAOF,UAAS,OAAO,QACd,6EACC,QAAgB;EAEf,MAAM,WAAW,IAAI,QAAQ,UAAU,IAAI;EAE3C,MAAM,UAAU,SAAS,WAAW,OAAO,GAAG,WAAW,aAAa;EACtE,MAAM,UAAU,kBAAkB,QAAQ;AAC1C,SAAO,YAAY,WAAW,QAAQ,CAAC,+CAA+C,WAAW,QAAQ,CAAC,IAAI,WAAW,QAAQ,CAAC;GAErI;AAED,QAAO"}
@@ -546,6 +546,59 @@ interface InjectHeaderIdsOptions {
546
546
  }
547
547
  ```
548
548
 
549
+ ## Rendering API
550
+
551
+ Import from the render subpath for HTML rendering functions that produce the same output
552
+ as `markform serve`:
553
+
554
+ ```typescript
555
+ import {
556
+ renderViewContent,
557
+ renderSourceContent,
558
+ renderMarkdownContent,
559
+ renderYamlContent,
560
+ renderJsonContent,
561
+ renderFillRecordContent,
562
+ FILL_RECORD_STYLES,
563
+ FILL_RECORD_SCRIPTS,
564
+ escapeHtml,
565
+ formatDuration,
566
+ formatTokens,
567
+ } from 'markform/render';
568
+ ```
569
+
570
+ These functions produce HTML fragments (not full pages), so consumers can embed them in
571
+ their own page shell with their own layout, CSS reset, and surrounding UI.
572
+
573
+ ### Content Renderers
574
+
575
+ | Function | Input | Description |
576
+ | --- | --- | --- |
577
+ | `renderViewContent(form)` | `ParsedForm` | Render a form as a read-only HTML view |
578
+ | `renderSourceContent(content)` | `string` | Render Jinja-style form source with syntax highlighting |
579
+ | `renderMarkdownContent(content)` | `string` | Render markdown as HTML |
580
+ | `renderYamlContent(content)` | `string` | Render YAML with syntax highlighting |
581
+ | `renderJsonContent(content)` | `string` | Render JSON with syntax highlighting |
582
+ | `renderFillRecordContent(record)` | `FillRecord` | Render a fill record as an interactive dashboard |
583
+
584
+ ### CSS and JavaScript Constants
585
+
586
+ | Export | Description |
587
+ | --- | --- |
588
+ | `FILL_RECORD_STYLES` | `<style>` block with CSS for the fill record dashboard |
589
+ | `FILL_RECORD_SCRIPTS` | JavaScript providing `frShowTip()`, `frHideTip()`, `frCopyYaml()` for fill record interactivity |
590
+
591
+ Include `FILL_RECORD_STYLES` in your page `<head>` and `FILL_RECORD_SCRIPTS` in a
592
+ `<script>` tag when using `renderFillRecordContent()`.
593
+
594
+ ### Utility Functions
595
+
596
+ | Function | Description |
597
+ | --- | --- |
598
+ | `escapeHtml(str)` | Escape HTML special characters |
599
+ | `formatDuration(ms)` | Format milliseconds as human-readable duration (e.g., `"1m 5s"`) |
600
+ | `formatTokens(count)` | Format token counts with k suffix (e.g., `"1.5k"`) |
601
+
549
602
  ## Type Exports
550
603
 
551
604
  All Zod schemas and TypeScript types are exported from the main package: