static-llms-txt 0.1.0 → 0.1.1
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/index.cjs +43 -3
- package/package.json +26 -4
package/index.cjs
CHANGED
|
@@ -51,7 +51,8 @@ function inline(node) {
|
|
|
51
51
|
|
|
52
52
|
function codeBlock(node) {
|
|
53
53
|
const code = node.querySelector("code") || node;
|
|
54
|
-
const
|
|
54
|
+
const wrap = node.parentNode && node.parentNode.getAttribute ? node.parentNode.getAttribute("class") || "" : ""; // VitePress: <div class="language-js"><pre>
|
|
55
|
+
const cls = (code.getAttribute("class") || "") + " " + (node.getAttribute("class") || "") + " " + wrap + " " + (node.getAttribute("data-language") || node.getAttribute("data-lang") || "");
|
|
55
56
|
const lang = (/(?:language|lang|highlight-source)-([\w+#.-]+)/.exec(cls) || [])[1] || (node.getAttribute("data-language") || node.getAttribute("data-lang") || "");
|
|
56
57
|
// Line-per-element highlighters (Shiki, Expressive Code) put each line in its own block element.
|
|
57
58
|
const lines = code.querySelectorAll(".line, .ec-line");
|
|
@@ -146,9 +147,44 @@ function meta(doc, selector) {
|
|
|
146
147
|
|
|
147
148
|
// One HTML document → { title, description, canonical, noindex, redirect, sections, text }.
|
|
148
149
|
// sections: [{ heading, id, text }] where the first one (heading "") is the text before any h2.
|
|
150
|
+
// Minifiers such as html-minifier-terser (removeOptionalTags, used by Docusaurus) drop the table end
|
|
151
|
+
// tags HTML lets you omit. node-html-parser copes with omitted </li> and </p> but not with table parts:
|
|
152
|
+
// one such table and <body> and <main> vanish from the tree. Put the table end tags back first.
|
|
153
|
+
// Well-formed tables come out unchanged; nested tables are left alone.
|
|
154
|
+
function closeTableTags(html) {
|
|
155
|
+
if (!/<table\b/i.test(html)) return html;
|
|
156
|
+
return html.replace(/<table\b[\s\S]*?<\/table>/gi, (table) => {
|
|
157
|
+
if (/<table\b/i.test(table.slice(6))) return table;
|
|
158
|
+
let cell = "", row = false, part = "", out = "", last = 0, m;
|
|
159
|
+
const re = /<(\/?)(td|th|tr|thead|tbody|tfoot|table)\b[^>]*>/gi;
|
|
160
|
+
const shut = (to) => {
|
|
161
|
+
let s = "";
|
|
162
|
+
if (cell) { s += "</" + cell + ">"; cell = ""; }
|
|
163
|
+
if (to !== "cell" && row) { s += "</tr>"; row = false; }
|
|
164
|
+
if (to === "part" && part) { s += "</" + part + ">"; part = ""; }
|
|
165
|
+
return s;
|
|
166
|
+
};
|
|
167
|
+
while ((m = re.exec(table))) {
|
|
168
|
+
out += table.slice(last, m.index);
|
|
169
|
+
last = re.lastIndex;
|
|
170
|
+
const end = m[1] === "/", tag = m[2].toLowerCase();
|
|
171
|
+
if (end) {
|
|
172
|
+
if (tag === "td" || tag === "th") { if (cell) { out += m[0]; cell = ""; } }
|
|
173
|
+
else if (tag === "tr") { out += shut("row").replace(/<\/tr>$/, "") + m[0]; row = false; }
|
|
174
|
+
else if (tag === "table") out += shut("part") + m[0];
|
|
175
|
+
else { out += shut("row") + m[0]; part = ""; }
|
|
176
|
+
} else if (tag === "td" || tag === "th") { out += shut("cell") + m[0]; cell = tag; }
|
|
177
|
+
else if (tag === "tr") { out += shut("row") + m[0]; row = true; }
|
|
178
|
+
else if (tag === "table") out += m[0];
|
|
179
|
+
else { out += shut("part") + m[0]; part = tag; }
|
|
180
|
+
}
|
|
181
|
+
return out + table.slice(last);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
149
185
|
function readHtml(html, options) {
|
|
150
186
|
const o = options || {};
|
|
151
|
-
const doc = parse(String(html), { comment: false, blockTextElements: { script: false, style: false, noscript: false } });
|
|
187
|
+
const doc = parse(closeTableTags(String(html)), { comment: false, blockTextElements: { script: false, style: false, noscript: false } });
|
|
152
188
|
const robots = meta(doc, 'meta[name="robots"]') + " " + meta(doc, 'meta[name="googlebot"]');
|
|
153
189
|
const refresh = doc.querySelector('meta[http-equiv="refresh"], meta[http-equiv="Refresh"]');
|
|
154
190
|
const canonicalEl = doc.querySelector('link[rel="canonical"]');
|
|
@@ -245,8 +281,12 @@ function scan(dir, options) {
|
|
|
245
281
|
for (const rel of walkHtml(root)) {
|
|
246
282
|
if (/(^|\/)(404|500)(\.html?|\/index\.html?)$/i.test(rel)) continue;
|
|
247
283
|
if (excludes.some((re) => re.test(rel))) continue;
|
|
248
|
-
const
|
|
284
|
+
const html = fs.readFileSync(path.join(root, rel), "utf8");
|
|
285
|
+
const info = readHtml(html, { content: o.content, exclude: o.remove });
|
|
249
286
|
if (info.noindex || info.redirect) continue;
|
|
287
|
+
if (!info.text && html.length > 2000 && o.warn !== false) {
|
|
288
|
+
console.warn("static-llms-txt: found no text in " + rel + ", so it is left out. If the page has text, please report it at https://github.com/fengyiqicoder/onetagai/issues");
|
|
289
|
+
}
|
|
250
290
|
if (info.text.length < (o.minLength === undefined ? 40 : o.minLength)) continue;
|
|
251
291
|
const p = urlPath(rel, o.cleanUrls);
|
|
252
292
|
const url = o.site ? joinUrl(o.site, p) : /^https?:\/\//i.test(info.canonical) ? info.canonical : "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "static-llms-txt",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Write llms.txt and llms-full.txt for any static site from the HTML it already built. Works after Eleventy, Hugo, Jekyll, Astro, Gatsby, Docusaurus or plain HTML. No API key.",
|
|
5
5
|
"main": "./index.cjs",
|
|
6
6
|
"module": "./index.mjs",
|
|
@@ -13,14 +13,36 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"bin": {
|
|
16
|
-
"static-llms-txt": "
|
|
16
|
+
"static-llms-txt": "cli.cjs"
|
|
17
17
|
},
|
|
18
|
-
"files": [
|
|
18
|
+
"files": [
|
|
19
|
+
"index.cjs",
|
|
20
|
+
"index.mjs",
|
|
21
|
+
"index.d.ts",
|
|
22
|
+
"cli.cjs",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
19
26
|
"scripts": {
|
|
20
27
|
"test": "node --test test/*.test.mjs",
|
|
21
28
|
"prepublishOnly": "npm test"
|
|
22
29
|
},
|
|
23
|
-
"keywords": [
|
|
30
|
+
"keywords": [
|
|
31
|
+
"llms.txt",
|
|
32
|
+
"llms-txt",
|
|
33
|
+
"llms-full.txt",
|
|
34
|
+
"llmstxt",
|
|
35
|
+
"static-site",
|
|
36
|
+
"html-to-markdown",
|
|
37
|
+
"ssg",
|
|
38
|
+
"eleventy",
|
|
39
|
+
"hugo",
|
|
40
|
+
"jekyll",
|
|
41
|
+
"ai",
|
|
42
|
+
"seo",
|
|
43
|
+
"geo",
|
|
44
|
+
"cli"
|
|
45
|
+
],
|
|
24
46
|
"license": "MIT",
|
|
25
47
|
"author": "OneTag AI (https://onetagai.com)",
|
|
26
48
|
"homepage": "https://github.com/fengyiqicoder/onetagai/tree/main/packages/static-llms-txt#readme",
|