@farm.js/core 0.1.23 → 0.1.25
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/agent-runtime.d.mts +1 -1
- package/dist/agent-runtime.d.ts +1 -1
- package/dist/api/route-manager.cjs +4 -4
- package/dist/api/route-manager.d.mts +1 -1
- package/dist/api/route-manager.d.ts +1 -1
- package/dist/api/route-manager.mjs +3 -3
- package/dist/api/runtime.cjs +3 -3
- package/dist/api/runtime.mjs +2 -2
- package/dist/api.cjs +7 -7
- package/dist/api.d.mts +2 -2
- package/dist/api.d.ts +2 -2
- package/dist/api.mjs +6 -6
- package/dist/{app-BV-7wV5q.d.ts → app-BF-ctoxh.d.ts} +3 -3
- package/dist/{app-BZDWwwFa.d.mts → app-ZuWrAMc_.d.mts} +3 -3
- package/dist/app-markdown.cjs +4 -4
- package/dist/app-markdown.d.mts +2 -2
- package/dist/app-markdown.d.ts +2 -2
- package/dist/app-markdown.mjs +3 -3
- package/dist/{chunk-MVUREHPN.mjs → chunk-2BIJGZR3.mjs} +1 -1
- package/dist/chunk-2ITKVAIF.cjs +1077 -0
- package/dist/{chunk-47H7VENP.mjs → chunk-2KI3CL3N.mjs} +1 -1
- package/dist/{chunk-KNPRCKXK.cjs → chunk-3TQWUUNP.cjs} +9 -7
- package/dist/{chunk-GZ3ZPTQV.mjs → chunk-52SH7TKB.mjs} +2 -2
- package/dist/{chunk-BDJNP7AQ.mjs → chunk-5YYJ6Q2L.mjs} +10 -3
- package/dist/{chunk-OYDRPBBV.cjs → chunk-65P6OGYN.cjs} +73 -3
- package/dist/{chunk-JIKGGIOL.mjs → chunk-6D242YGO.mjs} +1 -1
- package/dist/{chunk-AH7HOAQ3.cjs → chunk-6K4SPQWL.cjs} +9 -4
- package/dist/{chunk-LYM7HY34.cjs → chunk-AXYTGLF3.cjs} +4 -4
- package/dist/{chunk-2QLBIPFT.cjs → chunk-B6ZCT36X.cjs} +4 -4
- package/dist/{chunk-IMBMOEWT.cjs → chunk-BD2U4ZL6.cjs} +8 -8
- package/dist/{chunk-2M435BUE.mjs → chunk-CEYUWDWA.mjs} +7 -5
- package/dist/{chunk-I5YBCWQ6.cjs → chunk-CFNOGDUS.cjs} +2 -2
- package/dist/{chunk-XI3GWPUS.cjs → chunk-CRQPYWLK.cjs} +14 -14
- package/dist/{chunk-ISTFC3MZ.cjs → chunk-E3RDL2DA.cjs} +48 -5
- package/dist/{chunk-QTBEAKCJ.cjs → chunk-H7CJRJ4L.cjs} +16 -16
- package/dist/{chunk-VPY755R2.mjs → chunk-N2Z4ZFDE.mjs} +25 -11
- package/dist/{chunk-DNLQMFER.cjs → chunk-O5DVPF3R.cjs} +26 -19
- package/dist/{chunk-WNUBR4CA.mjs → chunk-QGG336NI.mjs} +1 -1
- package/dist/{chunk-4DKZ6JR3.cjs → chunk-QYMRIVG6.cjs} +184 -130
- package/dist/{chunk-III667SJ.cjs → chunk-R7LCG3BT.cjs} +189 -175
- package/dist/{chunk-7BC6GAL7.mjs → chunk-RR6UGYUT.mjs} +44 -1
- package/dist/{chunk-LQIRVSBY.cjs → chunk-RYDW7GPR.cjs} +13 -13
- package/dist/{chunk-PGQBL5DN.mjs → chunk-T2OPSH6S.mjs} +72 -2
- package/dist/{chunk-5UX4C5QI.mjs → chunk-TKDY6AJP.mjs} +1 -1
- package/dist/{chunk-VXCA7RZP.cjs → chunk-TTVHACQV.cjs} +1 -1
- package/dist/{chunk-OFEY6KHO.mjs → chunk-U4MP7XTD.mjs} +504 -27
- package/dist/{chunk-YJJLXIIS.cjs → chunk-U74A3P2P.cjs} +7 -7
- package/dist/{chunk-72VJRKJD.mjs → chunk-VZWO3XVL.mjs} +2 -2
- package/dist/{chunk-7LU4IOXQ.mjs → chunk-WJYCI56T.mjs} +87 -33
- package/dist/{chunk-EHUZ2MKO.mjs → chunk-WOI2HOGA.mjs} +1 -1
- package/dist/{chunk-N255VYFP.mjs → chunk-XM4ZDVD7.mjs} +8 -3
- package/dist/{chunk-YGMK6ESJ.mjs → chunk-XME4TCLB.mjs} +2 -2
- package/dist/{client-plugins-B_XzCegf.d.mts → client-plugins-DPG0NeZN.d.mts} +41 -3
- package/dist/{client-plugins-CKsXQfXY.d.ts → client-plugins-Fgni-_25.d.ts} +41 -3
- package/dist/client-plugins.d.mts +1 -1
- package/dist/client-plugins.d.ts +1 -1
- package/dist/client.cjs +4 -4
- package/dist/client.d.mts +5 -5
- package/dist/client.d.ts +5 -5
- package/dist/client.mjs +3 -3
- package/dist/config.d.mts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/{devtools-UHRSZ7VA.cjs → devtools-6OA7FEF6.cjs} +4 -4
- package/dist/{devtools-OY4SNU3P.mjs → devtools-I7TBFOKD.mjs} +3 -3
- package/dist/docs.cjs +6 -6
- package/dist/docs.mjs +5 -5
- package/dist/index.cjs +24 -22
- package/dist/index.d.mts +13 -13
- package/dist/index.d.ts +13 -13
- package/dist/index.mjs +23 -21
- package/dist/integrations.d.mts +1 -1
- package/dist/integrations.d.ts +1 -1
- package/dist/internal/app-markdown-runtime.cjs +3 -3
- package/dist/internal/app-markdown-runtime.d.mts +1 -1
- package/dist/internal/app-markdown-runtime.d.ts +1 -1
- package/dist/internal/app-markdown-runtime.mjs +2 -2
- package/dist/internal/build-runtime.cjs +16 -16
- package/dist/internal/build-runtime.d.mts +3 -3
- package/dist/internal/build-runtime.d.ts +3 -3
- package/dist/internal/build-runtime.mjs +15 -15
- package/dist/internal/cli-runtime.cjs +5 -5
- package/dist/internal/cli-runtime.mjs +4 -4
- package/dist/internal/client-error-overlay.cjs +4 -4
- package/dist/internal/client-error-overlay.mjs +1 -1
- package/dist/internal/compression-runtime.d.mts +1 -1
- package/dist/internal/compression-runtime.d.ts +1 -1
- package/dist/internal/config-runtime.cjs +4 -4
- package/dist/internal/config-runtime.d.mts +2 -2
- package/dist/internal/config-runtime.d.ts +2 -2
- package/dist/internal/config-runtime.mjs +3 -3
- package/dist/internal/product-telemetry-runtime.cjs +2 -2
- package/dist/internal/product-telemetry-runtime.mjs +1 -1
- package/dist/internal/production-runtime.cjs +11 -5
- package/dist/internal/production-runtime.d.mts +30 -8
- package/dist/internal/production-runtime.d.ts +30 -8
- package/dist/internal/production-runtime.mjs +10 -4
- package/dist/markdown.cjs +4 -2
- package/dist/markdown.d.mts +63 -1
- package/dist/markdown.d.ts +63 -1
- package/dist/markdown.mjs +3 -1
- package/dist/{metadata-IQEblkZp.d.ts → metadata-CDnRHKVq.d.ts} +1 -1
- package/dist/{metadata-B08w4EYV.d.mts → metadata-D0EF7esB.d.mts} +1 -1
- package/dist/middleware.d.mts +3 -3
- package/dist/middleware.d.ts +3 -3
- package/dist/navigation.cjs +5 -5
- package/dist/navigation.d.mts +4 -4
- package/dist/navigation.d.ts +4 -4
- package/dist/navigation.mjs +4 -4
- package/dist/plugin.cjs +12 -12
- package/dist/plugin.d.mts +1 -1
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.mjs +11 -11
- package/dist/{production-runtime-DRSOkc-d.d.ts → production-runtime-DpCt0opU.d.ts} +1 -1
- package/dist/{production-runtime-C3bGFEaM.d.mts → production-runtime-x3W4wVqx.d.mts} +1 -1
- package/dist/query/client.cjs +6 -6
- package/dist/query/client.mjs +2 -2
- package/dist/{render-plan-CCFuMLNS.d.ts → render-plan-D5oFRVBV.d.ts} +1 -1
- package/dist/{render-plan-B6CKNl4e.d.mts → render-plan-tazUJalK.d.mts} +1 -1
- package/dist/renderer-client.cjs +5 -5
- package/dist/renderer-client.d.mts +3 -3
- package/dist/renderer-client.d.ts +3 -3
- package/dist/renderer-client.mjs +2 -2
- package/dist/{request-DgD1XsTx.d.mts → request-CXmQy5ks.d.mts} +1 -1
- package/dist/{request-Dn6VURbE.d.ts → request-CzZX0Aew.d.ts} +1 -1
- package/dist/request.d.mts +2 -2
- package/dist/request.d.ts +2 -2
- package/dist/{route-rendering-76A5I_kE.d.mts → route-rendering-B-qpe32B.d.mts} +1 -1
- package/dist/{route-rendering-LAmQEdyG.d.ts → route-rendering-Dw3C362T.d.ts} +1 -1
- package/dist/{router-BSOOGya2.d.ts → router-CLl3xHwl.d.ts} +1 -1
- package/dist/{router-CnrRSa9d.d.mts → router-CafM2jlw.d.mts} +1 -1
- package/dist/routes.d.mts +1 -1
- package/dist/routes.d.ts +1 -1
- package/dist/server-plugins.d.mts +2 -2
- package/dist/server-plugins.d.ts +2 -2
- package/dist/server.cjs +27 -27
- package/dist/server.d.mts +7 -7
- package/dist/server.d.ts +7 -7
- package/dist/server.mjs +12 -12
- package/dist/{spa-router-DnYhWCvI.d.mts → spa-router-6sJfsMlQ.d.mts} +2 -2
- package/dist/{spa-router-BMrSsG5b.d.ts → spa-router-DePr2aZ6.d.ts} +2 -2
- package/dist/testing.cjs +4 -4
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.mjs +3 -3
- package/dist/{utils-C3GguS-Q.d.ts → utils-BBKC3cf3.d.ts} +1 -1
- package/dist/{utils-ABkktwku.d.mts → utils-BPHr-1mP.d.mts} +1 -1
- package/dist/version.cjs +2 -2
- package/dist/version.mjs +1 -1
- package/dist/vite.cjs +12 -12
- package/dist/vite.d.mts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.mjs +11 -11
- package/package.json +1 -1
- package/dist/chunk-BBVSJVBZ.cjs +0 -600
- package/dist/{chunk-XP777LRD.mjs → chunk-GDUYXFIS.mjs} +3 -3
- package/dist/{chunk-4PNUXIVU.cjs → chunk-YAOX43YI.cjs} +3 -3
|
@@ -2,6 +2,146 @@ import {
|
|
|
2
2
|
__name
|
|
3
3
|
} from "./chunk-LPEX4YW6.mjs";
|
|
4
4
|
|
|
5
|
+
// src/markdown-view.ts
|
|
6
|
+
var FENCE = /^\s{0,3}(`{3,}|~{3,})/;
|
|
7
|
+
var ATX_HEADING = /^\s{0,3}(#{1,6})[ \t]+(.+?)[ \t]*#*[ \t]*$/;
|
|
8
|
+
function parseFarmMarkdownHeadings(markdown) {
|
|
9
|
+
const lines = markdown.split("\n");
|
|
10
|
+
const headings = [];
|
|
11
|
+
const used = /* @__PURE__ */ new Map();
|
|
12
|
+
let index = 0;
|
|
13
|
+
if (lines[0]?.trim() === "---") {
|
|
14
|
+
const close = lines.findIndex((line, lineIndex) => lineIndex > 0 && line.trim() === "---");
|
|
15
|
+
if (close > 0) index = close + 1;
|
|
16
|
+
}
|
|
17
|
+
let fence = null;
|
|
18
|
+
for (; index < lines.length; index++) {
|
|
19
|
+
const line = lines[index];
|
|
20
|
+
const fenceMatch = FENCE.exec(line);
|
|
21
|
+
if (fenceMatch) {
|
|
22
|
+
const marker = fenceMatch[1];
|
|
23
|
+
if (fence === null) fence = marker;
|
|
24
|
+
else if (marker[0] === fence[0] && marker.length >= fence.length) fence = null;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (fence !== null) continue;
|
|
28
|
+
const match = ATX_HEADING.exec(line);
|
|
29
|
+
if (!match) continue;
|
|
30
|
+
const text = match[2].trim();
|
|
31
|
+
const base = slugifyHeading(text) || "section";
|
|
32
|
+
const count = used.get(base) ?? 0;
|
|
33
|
+
used.set(base, count + 1);
|
|
34
|
+
headings.push({
|
|
35
|
+
id: count === 0 ? base : `${base}-${count}`,
|
|
36
|
+
level: match[1].length,
|
|
37
|
+
text,
|
|
38
|
+
start: index,
|
|
39
|
+
end: lines.length
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
for (let headingIndex = 0; headingIndex < headings.length; headingIndex++) {
|
|
43
|
+
const heading = headings[headingIndex];
|
|
44
|
+
const next = headings.slice(headingIndex + 1).find((candidate) => candidate.level <= heading.level);
|
|
45
|
+
if (next) heading.end = next.start;
|
|
46
|
+
}
|
|
47
|
+
return headings;
|
|
48
|
+
}
|
|
49
|
+
__name(parseFarmMarkdownHeadings, "parseFarmMarkdownHeadings");
|
|
50
|
+
function slugifyHeading(text) {
|
|
51
|
+
return text.replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[`*_~]/g, "").toLowerCase().replace(/[^\p{L}\p{N}\s-]/gu, "").trim().replace(/\s/g, "-");
|
|
52
|
+
}
|
|
53
|
+
__name(slugifyHeading, "slugifyHeading");
|
|
54
|
+
function estimateFarmMarkdownTokens(text) {
|
|
55
|
+
return Math.ceil(text.length / 4);
|
|
56
|
+
}
|
|
57
|
+
__name(estimateFarmMarkdownTokens, "estimateFarmMarkdownTokens");
|
|
58
|
+
function selectFarmMarkdownView(markdown, searchParams, markdownPath) {
|
|
59
|
+
const wantsOutline = searchParams.has("outline");
|
|
60
|
+
const sectionId = searchParams.get("section");
|
|
61
|
+
if (!wantsOutline && sectionId === null) return { status: 200, body: markdown };
|
|
62
|
+
const lines = markdown.split("\n");
|
|
63
|
+
const headings = parseFarmMarkdownHeadings(markdown);
|
|
64
|
+
const sectionText = /* @__PURE__ */ __name((heading) => lines.slice(heading.start, heading.end).join("\n").trim(), "sectionText");
|
|
65
|
+
if (sectionId !== null) {
|
|
66
|
+
const heading = headings.find((candidate) => candidate.id === sectionId);
|
|
67
|
+
if (heading) return { status: 200, body: `${sectionText(heading)}
|
|
68
|
+
` };
|
|
69
|
+
const available = headings.map((candidate) => `- \`${candidate.id}\``).join("\n");
|
|
70
|
+
return {
|
|
71
|
+
status: 404,
|
|
72
|
+
body: `# Section not found
|
|
73
|
+
|
|
74
|
+
\`${sectionId}\` is not a section of ${markdownPath}.
|
|
75
|
+
|
|
76
|
+
` + (available ? `Available sections:
|
|
77
|
+
|
|
78
|
+
${available}
|
|
79
|
+
` : "This page has no sections.\n")
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const minLevel = Math.min(...headings.map((heading) => heading.level));
|
|
83
|
+
const entries = headings.map((heading) => {
|
|
84
|
+
const indent = " ".repeat(heading.level - minLevel);
|
|
85
|
+
const tokens = estimateFarmMarkdownTokens(sectionText(heading));
|
|
86
|
+
return `${indent}- [${heading.text}](${markdownPath}?section=${encodeURIComponent(heading.id)}) ~${tokens} tokens`;
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
status: 200,
|
|
90
|
+
body: `# Outline of ${markdownPath}
|
|
91
|
+
|
|
92
|
+
About ${estimateFarmMarkdownTokens(markdown)} tokens in total. Request one section with \`?section=<id>\`.
|
|
93
|
+
|
|
94
|
+
` + (entries.length > 0 ? `${entries.join("\n")}
|
|
95
|
+
` : "This page has no headings.\n")
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
__name(selectFarmMarkdownView, "selectFarmMarkdownView");
|
|
99
|
+
function selectFarmPageActionsView(markdownPath, actions, headers) {
|
|
100
|
+
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
101
|
+
const page = markdownPath === "/index.md" ? "/" : markdownPath.replace(/\.md$/, "");
|
|
102
|
+
return {
|
|
103
|
+
status: 200,
|
|
104
|
+
body: `${JSON.stringify({ page, markdown: markdownPath, actions }, null, 2)}
|
|
105
|
+
`
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
__name(selectFarmPageActionsView, "selectFarmPageActionsView");
|
|
109
|
+
function createFarmMarkdownETag(body) {
|
|
110
|
+
let h1 = 3735928559;
|
|
111
|
+
let h2 = 1103547991;
|
|
112
|
+
for (let index = 0; index < body.length; index++) {
|
|
113
|
+
const code = body.charCodeAt(index);
|
|
114
|
+
h1 = Math.imul(h1 ^ code, 2654435761);
|
|
115
|
+
h2 = Math.imul(h2 ^ code, 1597334677);
|
|
116
|
+
}
|
|
117
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
|
|
118
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
119
|
+
const hash = (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
|
|
120
|
+
return `W/"${hash}-${body.length.toString(36)}"`;
|
|
121
|
+
}
|
|
122
|
+
__name(createFarmMarkdownETag, "createFarmMarkdownETag");
|
|
123
|
+
function ifNoneMatchIncludes(header, etag) {
|
|
124
|
+
if (!header) return false;
|
|
125
|
+
const opaque = etag.replace(/^W\//, "");
|
|
126
|
+
return header.split(",").map((token) => token.trim()).some((token) => token === "*" || token.replace(/^W\//, "") === opaque);
|
|
127
|
+
}
|
|
128
|
+
__name(ifNoneMatchIncludes, "ifNoneMatchIncludes");
|
|
129
|
+
function createFarmMarkdownViewResponse(options) {
|
|
130
|
+
const url = options.requestUrl ?? new URL(options.request.url);
|
|
131
|
+
const view = url.searchParams.has("actions") ? selectFarmPageActionsView(options.markdownPath, options.actions ?? [], options.headers) : selectFarmMarkdownView(options.markdown, url.searchParams, options.markdownPath);
|
|
132
|
+
const status = view.status === 200 ? options.status : view.status;
|
|
133
|
+
const etag = createFarmMarkdownETag(view.body);
|
|
134
|
+
options.headers.set("ETag", etag);
|
|
135
|
+
if (status === 200 && ifNoneMatchIncludes(options.request.headers.get("if-none-match"), etag)) {
|
|
136
|
+
return new Response(null, { status: 304, headers: options.headers });
|
|
137
|
+
}
|
|
138
|
+
return new Response(options.request.method === "HEAD" ? null : view.body, {
|
|
139
|
+
status,
|
|
140
|
+
headers: options.headers
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
__name(createFarmMarkdownViewResponse, "createFarmMarkdownViewResponse");
|
|
144
|
+
|
|
5
145
|
// src/markdown.ts
|
|
6
146
|
var FARM_MARKDOWN_CONTENT_TYPE = "text/markdown; charset=utf-8";
|
|
7
147
|
function farmRequestWantsMarkdown(pathname, accept) {
|
|
@@ -80,6 +220,7 @@ async function createMarkdownMirrorResponse(options) {
|
|
|
80
220
|
}
|
|
81
221
|
const pageUrl = new URL(options.request.url);
|
|
82
222
|
pageUrl.pathname = target.pathname;
|
|
223
|
+
for (const name of ["outline", "section", "actions"]) pageUrl.searchParams.delete(name);
|
|
83
224
|
const headers = new Headers(options.request.headers);
|
|
84
225
|
headers.set("accept", "text/html");
|
|
85
226
|
const pageResponse = await options.renderPage(
|
|
@@ -89,17 +230,25 @@ async function createMarkdownMirrorResponse(options) {
|
|
|
89
230
|
})
|
|
90
231
|
);
|
|
91
232
|
if (!isHtmlResponse(pageResponse)) {
|
|
92
|
-
return
|
|
233
|
+
return createMarkdownAccessResponse(
|
|
234
|
+
pageResponse,
|
|
235
|
+
target.pathname,
|
|
236
|
+
pageUrl,
|
|
237
|
+
options.request.method === "HEAD"
|
|
238
|
+
);
|
|
93
239
|
}
|
|
94
240
|
const html = await pageResponse.text();
|
|
241
|
+
const markdownPath = target.pathname === "/" ? "/index.md" : `${target.pathname}.md`;
|
|
242
|
+
const actions = extractFarmPageActions(html, pageUrl);
|
|
95
243
|
const markdown = htmlToMarkdown(html, {
|
|
96
244
|
title: target.route?.title,
|
|
97
245
|
includeMetadata: options.config?.includeMetadata ?? true,
|
|
98
|
-
sourcePath: target.pathname
|
|
246
|
+
sourcePath: target.pathname,
|
|
247
|
+
actionsPath: actions.length > 0 ? `${markdownPath}?actions` : void 0
|
|
99
248
|
});
|
|
100
249
|
const headersOut = new Headers({
|
|
101
250
|
"Content-Type": "text/markdown; charset=utf-8",
|
|
102
|
-
"Content-Location":
|
|
251
|
+
"Content-Location": markdownPath,
|
|
103
252
|
"X-Farm-Markdown-Route": target.pathname
|
|
104
253
|
});
|
|
105
254
|
if (!hasMarkdownExtension) {
|
|
@@ -115,12 +264,62 @@ async function createMarkdownMirrorResponse(options) {
|
|
|
115
264
|
"Cache-Control",
|
|
116
265
|
pageCacheControl && isPrivateCacheControl(pageCacheControl) ? pageCacheControl : createMarkdownCacheHeader(cache)
|
|
117
266
|
);
|
|
118
|
-
|
|
267
|
+
const robots = [pageResponse.headers.get("x-robots-tag"), readHtmlMetaContent(html, "robots")].filter((value) => Boolean(value?.trim())).join(", ");
|
|
268
|
+
if (robots) headersOut.set("X-Robots-Tag", robots);
|
|
269
|
+
const canonical = readHtmlCanonicalHref(html);
|
|
270
|
+
if (canonical) {
|
|
271
|
+
try {
|
|
272
|
+
headersOut.append("Link", `<${new URL(canonical, pageUrl).href}>; rel="canonical"`);
|
|
273
|
+
} catch {
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return createFarmMarkdownViewResponse({
|
|
277
|
+
request: options.request,
|
|
278
|
+
requestUrl,
|
|
279
|
+
markdown,
|
|
119
280
|
status: pageResponse.status,
|
|
120
|
-
headers: headersOut
|
|
281
|
+
headers: headersOut,
|
|
282
|
+
markdownPath,
|
|
283
|
+
actions
|
|
121
284
|
});
|
|
122
285
|
}
|
|
123
286
|
__name(createMarkdownMirrorResponse, "createMarkdownMirrorResponse");
|
|
287
|
+
function createMarkdownAccessResponse(pageResponse, pathname, pageUrl, head) {
|
|
288
|
+
const location = pageResponse.headers.get("location");
|
|
289
|
+
const redirect = pageResponse.status >= 300 && pageResponse.status < 400 && location;
|
|
290
|
+
if (!redirect && pageResponse.status !== 401 && pageResponse.status !== 403) return null;
|
|
291
|
+
const headers = new Headers({
|
|
292
|
+
"Content-Type": "text/markdown; charset=utf-8",
|
|
293
|
+
"Cache-Control": "no-store",
|
|
294
|
+
"X-Farm-Markdown-Route": pathname
|
|
295
|
+
});
|
|
296
|
+
let body;
|
|
297
|
+
if (redirect) {
|
|
298
|
+
let target;
|
|
299
|
+
try {
|
|
300
|
+
target = new URL(location, pageUrl).href;
|
|
301
|
+
} catch {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
headers.set("Location", location);
|
|
305
|
+
body = `# Redirected
|
|
306
|
+
|
|
307
|
+
\`${pathname}\` redirects to [${target}](${target}). The page may require signing in.
|
|
308
|
+
`;
|
|
309
|
+
} else {
|
|
310
|
+
const authenticate = pageResponse.headers.get("www-authenticate");
|
|
311
|
+
if (authenticate) headers.set("WWW-Authenticate", authenticate);
|
|
312
|
+
body = pageResponse.status === 401 ? `# Sign-in required
|
|
313
|
+
|
|
314
|
+
\`${pathname}\` requires signing in.
|
|
315
|
+
` : `# Access denied
|
|
316
|
+
|
|
317
|
+
This account cannot read \`${pathname}\`.
|
|
318
|
+
`;
|
|
319
|
+
}
|
|
320
|
+
return new Response(head ? null : body, { status: pageResponse.status, headers });
|
|
321
|
+
}
|
|
322
|
+
__name(createMarkdownAccessResponse, "createMarkdownAccessResponse");
|
|
124
323
|
function applyMarkdownNegotiationHeaders(response, options) {
|
|
125
324
|
if (!isHtmlResponse(response)) {
|
|
126
325
|
return response;
|
|
@@ -145,24 +344,17 @@ var BLOCK_TAGS = /<\/?(ul|ol|main|section|article|header|footer|nav|aside|div|fo
|
|
|
145
344
|
var BOX_TAGS = /<\/?(label|button|input|select|textarea|option|output|meter|progress|td|th)\b[^>]*>/gi;
|
|
146
345
|
function htmlToMarkdown(html, options = {}) {
|
|
147
346
|
const title = options.title ?? extractHtmlTitle(html);
|
|
148
|
-
|
|
149
|
-
let source = extractHtmlBody(
|
|
150
|
-
removeHiddenElements(
|
|
151
|
-
resolveStreamedBoundaries(
|
|
152
|
-
html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<noscript\b[^>]*>[\s\S]*?<\/noscript>/gi, ""),
|
|
153
|
-
streamed
|
|
154
|
-
).replace(/<!--[\s\S]*?-->/g, "")
|
|
155
|
-
)
|
|
156
|
-
);
|
|
347
|
+
let source = readHtmlContentRegion(html);
|
|
157
348
|
const codeBlocks = [];
|
|
158
|
-
const setAsideCodeBlock = /* @__PURE__ */ __name((
|
|
349
|
+
const setAsideCodeBlock = /* @__PURE__ */ __name((code, attributes) => {
|
|
159
350
|
const content = decodeHtml(stripTags(code)).trim();
|
|
160
351
|
const longestRun = (content.match(/`+/g) ?? []).reduce(
|
|
161
352
|
(longest, run) => Math.max(longest, run.length),
|
|
162
353
|
0
|
|
163
354
|
);
|
|
164
355
|
const fence = "`".repeat(Math.max(3, longestRun + 1));
|
|
165
|
-
|
|
356
|
+
const language = readCodeLanguage(attributes) ?? "";
|
|
357
|
+
codeBlocks.push(`${fence}${language}
|
|
166
358
|
${content}
|
|
167
359
|
${fence}`);
|
|
168
360
|
return `
|
|
@@ -172,10 +364,27 @@ ${CODE_BLOCK_MARK}${codeBlocks.length - 1}${CODE_BLOCK_MARK}
|
|
|
172
364
|
`;
|
|
173
365
|
}, "setAsideCodeBlock");
|
|
174
366
|
source = source.replace(
|
|
175
|
-
/<pre\b[^>]
|
|
176
|
-
setAsideCodeBlock
|
|
367
|
+
/<pre\b([^>]*)><code\b([^>]*)>([\s\S]*?)<\/code><\/pre>/gi,
|
|
368
|
+
(_, preAttributes, codeAttributes, code) => setAsideCodeBlock(code, [codeAttributes, preAttributes])
|
|
369
|
+
);
|
|
370
|
+
source = source.replace(
|
|
371
|
+
/<pre\b([^>]*)>([\s\S]*?)<\/pre>/gi,
|
|
372
|
+
(_, attributes, code) => setAsideCodeBlock(code, [attributes])
|
|
373
|
+
);
|
|
374
|
+
source = source.replace(
|
|
375
|
+
/<table\b[^>]*>([\s\S]*?)<\/table>/gi,
|
|
376
|
+
(table, content) => {
|
|
377
|
+
if (/<table\b/i.test(content) || content.includes(CODE_BLOCK_MARK)) return table;
|
|
378
|
+
const rows = toMarkdownTableRows(content);
|
|
379
|
+
if (!rows) return table;
|
|
380
|
+
codeBlocks.push(rows);
|
|
381
|
+
return `
|
|
382
|
+
|
|
383
|
+
${CODE_BLOCK_MARK}${codeBlocks.length - 1}${CODE_BLOCK_MARK}
|
|
384
|
+
|
|
385
|
+
`;
|
|
386
|
+
}
|
|
177
387
|
);
|
|
178
|
-
source = source.replace(/<pre\b[^>]*>([\s\S]*?)<\/pre>/gi, setAsideCodeBlock);
|
|
179
388
|
source = source.replace(/<h([1-6])\b[^>]*>([\s\S]*?)<\/h\1>/gi, (_, level, content) => {
|
|
180
389
|
return `
|
|
181
390
|
|
|
@@ -205,6 +414,21 @@ ${quote}
|
|
|
205
414
|
|
|
206
415
|
`;
|
|
207
416
|
});
|
|
417
|
+
source = source.replace(
|
|
418
|
+
/<ol\b([^>]*)>([\s\S]*?)<\/ol>/gi,
|
|
419
|
+
(list, attributes, content) => {
|
|
420
|
+
if (/<[ou]l\b/i.test(content)) return list;
|
|
421
|
+
const start = Number.parseInt(readHtmlAttribute(attributes, "start") ?? "1", 10);
|
|
422
|
+
let number = Number.isFinite(start) ? start : 1;
|
|
423
|
+
const items = content.replace(/<li\b[^>]*>([\s\S]*?)<\/li>/gi, (_, item) => {
|
|
424
|
+
return `
|
|
425
|
+
${number++}. ${toInlineMarkdown(item).trim()}`;
|
|
426
|
+
});
|
|
427
|
+
return `
|
|
428
|
+
${items}
|
|
429
|
+
`;
|
|
430
|
+
}
|
|
431
|
+
);
|
|
208
432
|
source = source.replace(/<li\b[^>]*>([\s\S]*?)<\/li>/gi, (_, content) => {
|
|
209
433
|
return `
|
|
210
434
|
- ${toInlineMarkdown(content).trim()}`;
|
|
@@ -219,6 +443,9 @@ ${quote}
|
|
|
219
443
|
if (options.sourcePath) {
|
|
220
444
|
metadata.push(`Source: ${options.sourcePath}`);
|
|
221
445
|
}
|
|
446
|
+
if (options.actionsPath) {
|
|
447
|
+
metadata.push(`Actions: ${options.actionsPath}`);
|
|
448
|
+
}
|
|
222
449
|
if (metadata.length) {
|
|
223
450
|
markdown = `${metadata.join("\n\n")}${markdown ? `
|
|
224
451
|
|
|
@@ -367,13 +594,28 @@ function extractHtmlTitle(html) {
|
|
|
367
594
|
return match ? decodeHtml(stripTags(match[1])).trim() : void 0;
|
|
368
595
|
}
|
|
369
596
|
__name(extractHtmlTitle, "extractHtmlTitle");
|
|
597
|
+
function readHtmlContentRegion(html) {
|
|
598
|
+
const streamed = readStreamedBoundaryInstructions(html);
|
|
599
|
+
return extractHtmlBody(
|
|
600
|
+
removeHiddenElements(
|
|
601
|
+
resolveStreamedBoundaries(
|
|
602
|
+
html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<noscript\b[^>]*>[\s\S]*?<\/noscript>/gi, ""),
|
|
603
|
+
streamed
|
|
604
|
+
).replace(/<!--[\s\S]*?-->/g, "")
|
|
605
|
+
)
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
__name(readHtmlContentRegion, "readHtmlContentRegion");
|
|
370
609
|
function extractHtmlBody(html) {
|
|
371
610
|
const rootMatch = html.match(
|
|
372
611
|
/<div\b[^>]*id=["']root["'][^>]*>([\s\S]*?)<\/div>\s*(?:<script|<\/body>|$)/i
|
|
373
612
|
);
|
|
374
613
|
const bodyMatch = html.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
|
|
375
614
|
const body = rootMatch ? rootMatch[1] : bodyMatch ? bodyMatch[1] : html;
|
|
376
|
-
|
|
615
|
+
const main = extractFirstElementContent(body, ["main"]);
|
|
616
|
+
if (main !== void 0) return main;
|
|
617
|
+
const articles = body.match(/<article\b/gi)?.length ?? 0;
|
|
618
|
+
return articles === 1 ? extractFirstElementContent(body, ["article"]) ?? body : body;
|
|
377
619
|
}
|
|
378
620
|
__name(extractHtmlBody, "extractHtmlBody");
|
|
379
621
|
function extractFirstElementContent(html, tagNames) {
|
|
@@ -386,16 +628,249 @@ function extractFirstElementContent(html, tagNames) {
|
|
|
386
628
|
return void 0;
|
|
387
629
|
}
|
|
388
630
|
__name(extractFirstElementContent, "extractFirstElementContent");
|
|
631
|
+
function readHtmlMetaContent(html, name) {
|
|
632
|
+
for (const match of html.matchAll(/<meta\b([^>]*)>/gi)) {
|
|
633
|
+
if (readHtmlAttribute(match[1], "name")?.toLowerCase() === name) {
|
|
634
|
+
return readHtmlAttribute(match[1], "content");
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return void 0;
|
|
638
|
+
}
|
|
639
|
+
__name(readHtmlMetaContent, "readHtmlMetaContent");
|
|
640
|
+
function readHtmlCanonicalHref(html) {
|
|
641
|
+
for (const match of html.matchAll(/<link\b([^>]*)>/gi)) {
|
|
642
|
+
const rel = readHtmlAttribute(match[1], "rel")?.toLowerCase().split(/\s+/);
|
|
643
|
+
if (rel?.includes("canonical")) return readHtmlAttribute(match[1], "href");
|
|
644
|
+
}
|
|
645
|
+
return void 0;
|
|
646
|
+
}
|
|
647
|
+
__name(readHtmlCanonicalHref, "readHtmlCanonicalHref");
|
|
648
|
+
var FORM_ENCTYPES = /* @__PURE__ */ new Set([
|
|
649
|
+
"application/x-www-form-urlencoded",
|
|
650
|
+
"multipart/form-data",
|
|
651
|
+
"text/plain"
|
|
652
|
+
]);
|
|
653
|
+
function extractFarmPageActions(html, pageUrl) {
|
|
654
|
+
if (!/<form\b/i.test(html)) return [];
|
|
655
|
+
const region = readHtmlContentRegion(html);
|
|
656
|
+
const labelsFor = /* @__PURE__ */ new Map();
|
|
657
|
+
for (const match of region.matchAll(/<label\b([^>]*)>([\s\S]*?)<\/label>/gi)) {
|
|
658
|
+
const target = readDecodedAttribute(match[1], "for");
|
|
659
|
+
if (target && !labelsFor.has(target)) labelsFor.set(target, readLabelText(match[2]));
|
|
660
|
+
}
|
|
661
|
+
const actions = [];
|
|
662
|
+
for (const form of region.matchAll(/<form\b([^>]*)>([\s\S]*?)<\/form>/gi)) {
|
|
663
|
+
const action = readPageForm(form[1], form[2], pageUrl, labelsFor);
|
|
664
|
+
if (action) actions.push(action);
|
|
665
|
+
}
|
|
666
|
+
return actions;
|
|
667
|
+
}
|
|
668
|
+
__name(extractFarmPageActions, "extractFarmPageActions");
|
|
669
|
+
function readPageForm(attributes, content, pageUrl, labelsFor) {
|
|
670
|
+
const method = readDecodedAttribute(attributes, "method")?.trim().toLowerCase();
|
|
671
|
+
if (method === "dialog") return void 0;
|
|
672
|
+
const target = resolveFormTarget(readDecodedAttribute(attributes, "action"), pageUrl);
|
|
673
|
+
const form = {
|
|
674
|
+
type: "form",
|
|
675
|
+
method: method === "post" ? "POST" : "GET",
|
|
676
|
+
fields: [],
|
|
677
|
+
submit: []
|
|
678
|
+
};
|
|
679
|
+
const name = readDecodedAttribute(attributes, "aria-label") ?? readDecodedAttribute(attributes, "name") ?? readDecodedAttribute(attributes, "id");
|
|
680
|
+
if (name?.trim()) form.name = name.trim();
|
|
681
|
+
if (target) form.action = target;
|
|
682
|
+
else form.requiresJavaScript = true;
|
|
683
|
+
if (form.method === "POST") {
|
|
684
|
+
const enctype = readDecodedAttribute(attributes, "enctype")?.trim().toLowerCase();
|
|
685
|
+
form.enctype = enctype && FORM_ENCTYPES.has(enctype) ? enctype : "application/x-www-form-urlencoded";
|
|
686
|
+
}
|
|
687
|
+
const wrappingLabels = [...content.matchAll(/<label\b[^>]*>([\s\S]*?)<\/label>/gi)].map(
|
|
688
|
+
(match) => ({
|
|
689
|
+
start: match.index,
|
|
690
|
+
end: match.index + match[0].length,
|
|
691
|
+
text: readLabelText(match[1])
|
|
692
|
+
})
|
|
693
|
+
);
|
|
694
|
+
const labelOf = /* @__PURE__ */ __name((controlAttributes, index) => {
|
|
695
|
+
const aria = readDecodedAttribute(controlAttributes, "aria-label")?.trim();
|
|
696
|
+
if (aria) return aria;
|
|
697
|
+
const id = readDecodedAttribute(controlAttributes, "id");
|
|
698
|
+
const forLabel = id ? labelsFor.get(id) : void 0;
|
|
699
|
+
if (forLabel) return forLabel;
|
|
700
|
+
const wrapping = wrappingLabels.find((label) => label.start < index && index < label.end);
|
|
701
|
+
return wrapping?.text || void 0;
|
|
702
|
+
}, "labelOf");
|
|
703
|
+
const groups = /* @__PURE__ */ new Map();
|
|
704
|
+
const controls = /<(input)\b([^>]*)>|<(select|textarea|button)\b([^>]*)>([\s\S]*?)<\/\3>/gi;
|
|
705
|
+
for (const match of content.matchAll(controls)) {
|
|
706
|
+
const tag = (match[1] ?? match[3]).toLowerCase();
|
|
707
|
+
const controlAttributes = match[2] ?? match[4];
|
|
708
|
+
const inner = match[5] ?? "";
|
|
709
|
+
if (hasHtmlAttribute(controlAttributes, "disabled")) continue;
|
|
710
|
+
const label = labelOf(controlAttributes, match.index);
|
|
711
|
+
const fieldName = readDecodedAttribute(controlAttributes, "name");
|
|
712
|
+
const typeAttribute = readDecodedAttribute(controlAttributes, "type")?.trim().toLowerCase();
|
|
713
|
+
const type = tag === "input" ? typeAttribute ?? "text" : tag === "button" ? typeAttribute ?? "submit" : tag;
|
|
714
|
+
if (tag === "button" && !["button", "reset"].includes(type) || tag === "input" && (type === "submit" || type === "image")) {
|
|
715
|
+
const submit = {
|
|
716
|
+
label: (tag === "button" ? readLabelText(inner) : "") || readDecodedAttribute(controlAttributes, "value") || readDecodedAttribute(controlAttributes, "alt") || label || "Submit"
|
|
717
|
+
};
|
|
718
|
+
if (fieldName) submit.name = fieldName;
|
|
719
|
+
const value = readDecodedAttribute(controlAttributes, "value");
|
|
720
|
+
if (fieldName && value !== void 0) submit.value = value;
|
|
721
|
+
const formAction = readDecodedAttribute(controlAttributes, "formaction");
|
|
722
|
+
if (formAction !== void 0) {
|
|
723
|
+
const resolved = resolveFormTarget(formAction, pageUrl);
|
|
724
|
+
if (resolved) submit.action = resolved;
|
|
725
|
+
}
|
|
726
|
+
const formMethod = readDecodedAttribute(controlAttributes, "formmethod")?.toLowerCase();
|
|
727
|
+
if (formMethod === "get" || formMethod === "post") submit.method = formMethod.toUpperCase();
|
|
728
|
+
form.submit.push(submit);
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
if (tag === "button" || type === "button" || type === "reset" || !fieldName) continue;
|
|
732
|
+
if (type === "hidden") {
|
|
733
|
+
const value = readDecodedAttribute(controlAttributes, "value") ?? "";
|
|
734
|
+
form.fields.push({ name: fieldName, type, value });
|
|
735
|
+
if (fieldName.startsWith("$ACTION_ID_")) {
|
|
736
|
+
form.serverAction ?? (form.serverAction = { id: fieldName.slice("$ACTION_ID_".length) });
|
|
737
|
+
} else if (/^\$ACTION_[^:]*:0$/.test(fieldName)) {
|
|
738
|
+
try {
|
|
739
|
+
const id = JSON.parse(value).id;
|
|
740
|
+
if (typeof id === "string") form.serverAction ?? (form.serverAction = { id });
|
|
741
|
+
} catch {
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
if (type === "radio" || type === "checkbox") {
|
|
747
|
+
const value = readDecodedAttribute(controlAttributes, "value") ?? "on";
|
|
748
|
+
const option = { value };
|
|
749
|
+
if (label) option.label = label;
|
|
750
|
+
if (hasHtmlAttribute(controlAttributes, "checked")) option.selected = true;
|
|
751
|
+
const group = groups.get(fieldName);
|
|
752
|
+
if (group) {
|
|
753
|
+
group.options.push(option);
|
|
754
|
+
if (hasHtmlAttribute(controlAttributes, "required")) group.required = true;
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
const field2 = { name: fieldName, type, options: [option] };
|
|
758
|
+
if (hasHtmlAttribute(controlAttributes, "required")) field2.required = true;
|
|
759
|
+
groups.set(fieldName, field2);
|
|
760
|
+
form.fields.push(field2);
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
const field = { name: fieldName, type };
|
|
764
|
+
if (label) field.label = label;
|
|
765
|
+
if (hasHtmlAttribute(controlAttributes, "required")) field.required = true;
|
|
766
|
+
if (hasHtmlAttribute(controlAttributes, "multiple")) field.multiple = true;
|
|
767
|
+
if (tag === "select") {
|
|
768
|
+
field.options = [...inner.matchAll(/<option\b([^>]*)>([\s\S]*?)(?=<\/option>|<option\b|$)/gi)].filter((option) => !hasHtmlAttribute(option[1], "disabled")).map((option) => {
|
|
769
|
+
const text = readLabelText(option[2]);
|
|
770
|
+
const entry = {
|
|
771
|
+
value: readDecodedAttribute(option[1], "value") ?? text
|
|
772
|
+
};
|
|
773
|
+
if (text && text !== entry.value) entry.label = text;
|
|
774
|
+
if (hasHtmlAttribute(option[1], "selected")) entry.selected = true;
|
|
775
|
+
return entry;
|
|
776
|
+
});
|
|
777
|
+
} else if (tag === "textarea") {
|
|
778
|
+
const value = decodeHtml(inner);
|
|
779
|
+
if (value) field.value = value;
|
|
780
|
+
} else {
|
|
781
|
+
const value = readDecodedAttribute(controlAttributes, "value");
|
|
782
|
+
if (value !== void 0 && type !== "password" && type !== "file") field.value = value;
|
|
783
|
+
}
|
|
784
|
+
for (const key of ["placeholder", "pattern", "min", "max", "step", "accept"]) {
|
|
785
|
+
const value = readDecodedAttribute(controlAttributes, key);
|
|
786
|
+
if (value !== void 0) field[key] = value;
|
|
787
|
+
}
|
|
788
|
+
for (const [attribute, key] of [
|
|
789
|
+
["minlength", "minLength"],
|
|
790
|
+
["maxlength", "maxLength"]
|
|
791
|
+
]) {
|
|
792
|
+
const value = Number.parseInt(readDecodedAttribute(controlAttributes, attribute) ?? "", 10);
|
|
793
|
+
if (Number.isFinite(value) && value >= 0) field[key] = value;
|
|
794
|
+
}
|
|
795
|
+
form.fields.push(field);
|
|
796
|
+
}
|
|
797
|
+
if (form.fields.length === 0 && form.submit.length === 0) return void 0;
|
|
798
|
+
if (form.submit.length === 0) form.submit.push({ label: "Submit" });
|
|
799
|
+
return form;
|
|
800
|
+
}
|
|
801
|
+
__name(readPageForm, "readPageForm");
|
|
802
|
+
function resolveFormTarget(action, pageUrl) {
|
|
803
|
+
let target;
|
|
804
|
+
try {
|
|
805
|
+
target = new URL(action?.trim() || pageUrl.href, pageUrl);
|
|
806
|
+
} catch {
|
|
807
|
+
return void 0;
|
|
808
|
+
}
|
|
809
|
+
if (target.protocol !== "http:" && target.protocol !== "https:") return void 0;
|
|
810
|
+
target.hash = "";
|
|
811
|
+
return target.origin === pageUrl.origin ? `${target.pathname}${target.search}` : target.href;
|
|
812
|
+
}
|
|
813
|
+
__name(resolveFormTarget, "resolveFormTarget");
|
|
814
|
+
function readLabelText(html) {
|
|
815
|
+
return decodeHtml(stripTags(html.replace(/<(select|textarea|button)\b[\s\S]*?<\/\1>/gi, " "))).replace(/\s+/g, " ").trim();
|
|
816
|
+
}
|
|
817
|
+
__name(readLabelText, "readLabelText");
|
|
818
|
+
function readDecodedAttribute(attributes, name) {
|
|
819
|
+
const value = readHtmlAttribute(attributes, name);
|
|
820
|
+
return value === void 0 ? void 0 : decodeHtml(value);
|
|
821
|
+
}
|
|
822
|
+
__name(readDecodedAttribute, "readDecodedAttribute");
|
|
823
|
+
function hasHtmlAttribute(attributes, name) {
|
|
824
|
+
return new RegExp(`(?:^|\\s)${name}(?=\\s|=|/|$)`, "i").test(attributes);
|
|
825
|
+
}
|
|
826
|
+
__name(hasHtmlAttribute, "hasHtmlAttribute");
|
|
827
|
+
function readHtmlAttribute(attributes, name) {
|
|
828
|
+
const match = new RegExp(
|
|
829
|
+
`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s"'=<>\`]+))`,
|
|
830
|
+
"i"
|
|
831
|
+
).exec(attributes);
|
|
832
|
+
return match ? match[1] ?? match[2] ?? match[3] : void 0;
|
|
833
|
+
}
|
|
834
|
+
__name(readHtmlAttribute, "readHtmlAttribute");
|
|
835
|
+
function readCodeLanguage(attributesList) {
|
|
836
|
+
for (const attributes of attributesList) {
|
|
837
|
+
const language = readHtmlAttribute(attributes, "data-language") ?? readHtmlAttribute(attributes, "data-lang") ?? readHtmlAttribute(attributes, "class")?.match(/(?:^|\s)lang(?:uage)?-(\S+)/)?.[1];
|
|
838
|
+
if (language && /^[\w#+.-]+$/.test(language)) return language;
|
|
839
|
+
}
|
|
840
|
+
return void 0;
|
|
841
|
+
}
|
|
842
|
+
__name(readCodeLanguage, "readCodeLanguage");
|
|
843
|
+
function toMarkdownTableRows(content) {
|
|
844
|
+
const rows = [];
|
|
845
|
+
for (const [, row] of content.matchAll(/<tr\b[^>]*>([\s\S]*?)<\/tr>/gi)) {
|
|
846
|
+
const cells = [];
|
|
847
|
+
for (const [, , attributes, cell] of row.matchAll(/<(td|th)\b([^>]*)>([\s\S]*?)<\/\1>/gi)) {
|
|
848
|
+
cells.push(decodeHtml(toInlineMarkdown(cell)).trim().replace(/\|/g, "\\|"));
|
|
849
|
+
const span = Number.parseInt(readHtmlAttribute(attributes, "colspan") ?? "1", 10);
|
|
850
|
+
for (let extra = 1; extra < Math.min(span, 1e3); extra++) cells.push("");
|
|
851
|
+
}
|
|
852
|
+
if (cells.length) rows.push(cells);
|
|
853
|
+
}
|
|
854
|
+
if (!rows.length) return void 0;
|
|
855
|
+
const columns = rows.reduce((widest, row) => Math.max(widest, row.length), 0);
|
|
856
|
+
const line = /* @__PURE__ */ __name((cells) => `| ${Array.from({ length: columns }, (_, index) => cells[index] ?? "").join(" | ")} |`.replace(
|
|
857
|
+
/ {2,}/g,
|
|
858
|
+
" "
|
|
859
|
+
), "line");
|
|
860
|
+
return [line(rows[0]), line(Array(columns).fill("---")), ...rows.slice(1).map(line)].join("\n");
|
|
861
|
+
}
|
|
862
|
+
__name(toMarkdownTableRows, "toMarkdownTableRows");
|
|
389
863
|
function toInlineMarkdown(html) {
|
|
390
864
|
let source = html.replace(/<a\b[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, text) => {
|
|
391
865
|
const label = toInlineMarkdown(text).trim() || href;
|
|
392
866
|
return `[${label}](${href})`;
|
|
393
|
-
}).replace(
|
|
394
|
-
|
|
395
|
-
(
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
867
|
+
}).replace(/<img\b([^>]*)>/gi, (_, attributes) => {
|
|
868
|
+
const src = readHtmlAttribute(attributes, "src");
|
|
869
|
+
const alt = readHtmlAttribute(attributes, "alt") ?? "";
|
|
870
|
+
if (!src) return alt;
|
|
871
|
+
if (/^data:/i.test(src.trim())) return alt;
|
|
872
|
+
return ``;
|
|
873
|
+
}).replace(/<strong\b[^>]*>([\s\S]*?)<\/strong>/gi, (_, content) => {
|
|
399
874
|
return `**${toInlineMarkdown(content).trim()}**`;
|
|
400
875
|
}).replace(/<b\b[^>]*>([\s\S]*?)<\/b>/gi, (_, content) => {
|
|
401
876
|
return `**${toInlineMarkdown(content).trim()}**`;
|
|
@@ -583,6 +1058,7 @@ function decodeHtml(input) {
|
|
|
583
1058
|
__name(decodeHtml, "decodeHtml");
|
|
584
1059
|
|
|
585
1060
|
export {
|
|
1061
|
+
createFarmMarkdownViewResponse,
|
|
586
1062
|
FARM_MARKDOWN_CONTENT_TYPE,
|
|
587
1063
|
farmRequestWantsMarkdown,
|
|
588
1064
|
createFarmMarkdownErrorBody,
|
|
@@ -596,5 +1072,6 @@ export {
|
|
|
596
1072
|
getFarmMarkdownMirrorPath,
|
|
597
1073
|
getFarmMarkdownAlternatePath,
|
|
598
1074
|
isFarmMarkdownMirrorExposed,
|
|
599
|
-
matchesFarmMarkdownRoutePattern
|
|
1075
|
+
matchesFarmMarkdownRoutePattern,
|
|
1076
|
+
extractFarmPageActions
|
|
600
1077
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkCRQPYWLKcjs = require('./chunk-CRQPYWLK.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkB6ZCT36Xcjs = require('./chunk-B6ZCT36X.cjs');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
var _chunkI57LW5VZcjs = require('./chunk-I57LW5VZ.cjs');
|
|
@@ -13,7 +13,7 @@ var _chunkS3JO3N4Hcjs = require('./chunk-S3JO3N4H.cjs');
|
|
|
13
13
|
|
|
14
14
|
// src/navigation.ts
|
|
15
15
|
function useRouter2() {
|
|
16
|
-
const router =
|
|
16
|
+
const router = _chunkCRQPYWLKcjs.useRouter.call(void 0, );
|
|
17
17
|
return {
|
|
18
18
|
push: router.push,
|
|
19
19
|
replace: router.replace,
|
|
@@ -21,21 +21,21 @@ function useRouter2() {
|
|
|
21
21
|
forward: router.forward,
|
|
22
22
|
refresh() {
|
|
23
23
|
if (typeof window === "undefined") return Promise.resolve();
|
|
24
|
-
return
|
|
24
|
+
return _chunkB6ZCT36Xcjs.getRouter.call(void 0, ).refresh();
|
|
25
25
|
},
|
|
26
26
|
prefetch(href) {
|
|
27
27
|
if (typeof window === "undefined") return Promise.resolve();
|
|
28
|
-
return
|
|
28
|
+
return _chunkB6ZCT36Xcjs.getRouter.call(void 0, ).prefetch(_chunkI57LW5VZcjs.applyFarmBasePath.call(void 0, href));
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
_chunkS3JO3N4Hcjs.__name.call(void 0, useRouter2, "useRouter");
|
|
33
33
|
function usePathname() {
|
|
34
|
-
return
|
|
34
|
+
return _chunkCRQPYWLKcjs.useRouter.call(void 0, ).pathname;
|
|
35
35
|
}
|
|
36
36
|
_chunkS3JO3N4Hcjs.__name.call(void 0, usePathname, "usePathname");
|
|
37
37
|
function useSearchParams() {
|
|
38
|
-
return
|
|
38
|
+
return _chunkCRQPYWLKcjs.useRouter.call(void 0, ).searchParams;
|
|
39
39
|
}
|
|
40
40
|
_chunkS3JO3N4Hcjs.__name.call(void 0, useSearchParams, "useSearchParams");
|
|
41
41
|
|