@soubiran/vite 0.1.2 → 0.1.4
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/og-template.svg +25 -0
- package/dist/utils-CgX7pSaU.mjs +12 -0
- package/dist/utils.d.mts +4 -0
- package/dist/utils.mjs +3 -0
- package/dist/vite.config.mjs +193 -10
- package/package.json +6 -2
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { joinURL, withoutTrailingSlash } from "ufo";
|
|
2
|
+
|
|
3
|
+
//#region src/utils.ts
|
|
4
|
+
function getUri(id) {
|
|
5
|
+
return withoutTrailingSlash(id.split("/pages/")[1].replace(/\.md$/, "").replace(/\.vue$/, "").replace(/index$/, ""));
|
|
6
|
+
}
|
|
7
|
+
function toUrl(hostname, ...paths) {
|
|
8
|
+
return joinURL(`https://${hostname}`, ...paths);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
export { toUrl as n, getUri as t };
|
package/dist/utils.d.mts
ADDED
package/dist/utils.mjs
ADDED
package/dist/vite.config.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { n as toUrl, t as getUri } from "./utils-CgX7pSaU.mjs";
|
|
1
2
|
import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { basename, dirname, join, resolve } from "node:path";
|
|
3
4
|
import ui from "@nuxt/ui/vite";
|
|
@@ -19,7 +20,6 @@ import implicitFigures from "markdown-it-image-figures";
|
|
|
19
20
|
import linkAttributes from "markdown-it-link-attributes";
|
|
20
21
|
import { fromAsyncCodeToHtml } from "@shikijs/markdown-it/async";
|
|
21
22
|
import { codeToHtml } from "shiki";
|
|
22
|
-
import { defaultOptions, findHeadlineElements, flatHeadlineItemsToNestedTree, getTokensText, slugify } from "markdown-it-table-of-contents";
|
|
23
23
|
import { Buffer } from "node:buffer";
|
|
24
24
|
import fs from "fs-extra";
|
|
25
25
|
import sharp from "sharp";
|
|
@@ -39,15 +39,6 @@ function createAssert(customAssert) {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
//#endregion
|
|
43
|
-
//#region src/utils.ts
|
|
44
|
-
function getUri(id) {
|
|
45
|
-
return withoutTrailingSlash(id.split("/pages/")[1].replace(/\.md$/, "").replace(/\.vue$/, "").replace(/index$/, ""));
|
|
46
|
-
}
|
|
47
|
-
function toUrl(hostname, ...paths) {
|
|
48
|
-
return joinURL(`https://${hostname}`, ...paths);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
42
|
//#endregion
|
|
52
43
|
//#region src/canonical.ts
|
|
53
44
|
function getCanonicalUrl(id, hostname) {
|
|
@@ -167,6 +158,198 @@ async function shikiHighlight(md) {
|
|
|
167
158
|
}));
|
|
168
159
|
}
|
|
169
160
|
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region ../../node_modules/.pnpm/markdown-it-table-of-contents@1.1.0_patch_hash=bf17e463c2a0f62d05f1686e2d4c458136845ea3b2c32121b585ceededa45171/node_modules/markdown-it-table-of-contents/index.mjs
|
|
163
|
+
/**
|
|
164
|
+
* Slugify a string to be used as anchor
|
|
165
|
+
* @param {string} text Text to slugify
|
|
166
|
+
* @param {string} rawToken Raw token to extract text from
|
|
167
|
+
* @returns {string} Slugified anchor string
|
|
168
|
+
*/
|
|
169
|
+
function slugify(text, rawToken) {
|
|
170
|
+
return encodeURIComponent(String(text).trim().toLowerCase().replace(/\s+/g, "-"));
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Default formatter for headline text
|
|
174
|
+
* @param {string} content Text content of the headline
|
|
175
|
+
* @param {*} md Markdown-it instance
|
|
176
|
+
* @returns {string} Formatted content
|
|
177
|
+
*/
|
|
178
|
+
function format(content, md) {
|
|
179
|
+
return md.renderInline(content);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Generates the opening HTML for a container with a specified class and optional header HTML.
|
|
183
|
+
* @param {string} containerClass The CSS class to apply to the container div
|
|
184
|
+
* @param {string} containerHeaderHtml Optional HTML to include as the container's header
|
|
185
|
+
* @returns {string} HTML string
|
|
186
|
+
*/
|
|
187
|
+
function transformContainerOpen(containerClass, containerHeaderHtml) {
|
|
188
|
+
let tocOpenHtml = "<div class=\"" + containerClass + "\">";
|
|
189
|
+
if (containerHeaderHtml) tocOpenHtml += containerHeaderHtml;
|
|
190
|
+
return tocOpenHtml;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Generates the closing HTML / footer for a container
|
|
194
|
+
* @param {string} containerFooterHtml The HTML string to be used for closing the container
|
|
195
|
+
* @returns {string} HTML string
|
|
196
|
+
*/
|
|
197
|
+
function transformContainerClose(containerFooterHtml) {
|
|
198
|
+
let tocFooterHtml = "";
|
|
199
|
+
if (containerFooterHtml) tocFooterHtml = containerFooterHtml;
|
|
200
|
+
return tocFooterHtml + "</div>";
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Helper to extract text from tokens, same function as in markdown-it-anchor
|
|
204
|
+
* @param {Array<any>} tokens Tokens
|
|
205
|
+
* @param {string} rawToken Raw token to extract text from
|
|
206
|
+
* @returns {string}
|
|
207
|
+
*/
|
|
208
|
+
function getTokensText(tokens, rawToken) {
|
|
209
|
+
return tokens.filter((t) => ["text", "code_inline"].includes(t.type)).map((t) => t.content).join("").trim();
|
|
210
|
+
}
|
|
211
|
+
const defaultOptions = {
|
|
212
|
+
includeLevel: [1, 2],
|
|
213
|
+
containerClass: "table-of-contents",
|
|
214
|
+
slugify,
|
|
215
|
+
markerPattern: /^\[\[toc\]\]/im,
|
|
216
|
+
omitTag: "<!-- omit from toc -->",
|
|
217
|
+
listType: "ul",
|
|
218
|
+
format,
|
|
219
|
+
containerHeaderHtml: void 0,
|
|
220
|
+
containerFooterHtml: void 0,
|
|
221
|
+
transformLink: void 0,
|
|
222
|
+
transformContainerOpen,
|
|
223
|
+
transformContainerClose,
|
|
224
|
+
getTokensText
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* @typedef {Object} HeadlineItem
|
|
228
|
+
* @property {number} level Headline level
|
|
229
|
+
* @property {string | null} anchor Anchor target
|
|
230
|
+
* @property {string} text Text of headline
|
|
231
|
+
* @property {any | null} token Raw token of headline
|
|
232
|
+
*/
|
|
233
|
+
/**
|
|
234
|
+
* @typedef {Object} TocItem
|
|
235
|
+
* @property {number} level Item level
|
|
236
|
+
* @property {string} text Text of link
|
|
237
|
+
* @property {string | null} anchor Target of link
|
|
238
|
+
* @property {Array<TocItem>} children Sub-items for this list item
|
|
239
|
+
*/
|
|
240
|
+
/**
|
|
241
|
+
* Finds all headline items for the defined levels in a Markdown document.
|
|
242
|
+
* @param {Array<number>} levels includeLevels like `[1, 2, 3]`
|
|
243
|
+
* @param {*} tokens Tokens gathered by the plugin
|
|
244
|
+
* @param {*} options Plugin options
|
|
245
|
+
* @returns {Array<HeadlineItem>}
|
|
246
|
+
*/
|
|
247
|
+
function findHeadlineElements(levels, tokens, options) {
|
|
248
|
+
/** @type {HeadlineItem[]} */
|
|
249
|
+
const headings = [];
|
|
250
|
+
/** @type {HeadlineItem | null} */
|
|
251
|
+
let currentHeading = null;
|
|
252
|
+
tokens.forEach((token, index) => {
|
|
253
|
+
if (token.type === "heading_open") {
|
|
254
|
+
const prev = index > 0 ? tokens[index - 1] : null;
|
|
255
|
+
if (prev && prev.type === "html_block" && prev.content.trim().toLowerCase().replace("\n", "") === options.omitTag) return;
|
|
256
|
+
const id = findExistingIdAttr(token);
|
|
257
|
+
const level = parseInt(token.tag.toLowerCase().replace("h", ""), 10);
|
|
258
|
+
if (levels.indexOf(level) >= 0) currentHeading = {
|
|
259
|
+
level,
|
|
260
|
+
text: "",
|
|
261
|
+
anchor: id || null,
|
|
262
|
+
token: null
|
|
263
|
+
};
|
|
264
|
+
} else if (currentHeading && token.type === "inline") {
|
|
265
|
+
const textContent = options.getTokensText(token.children, token);
|
|
266
|
+
currentHeading.text = textContent;
|
|
267
|
+
currentHeading.token = token;
|
|
268
|
+
if (!currentHeading.anchor) currentHeading.anchor = options.slugify(textContent, token);
|
|
269
|
+
} else if (token.type === "heading_close") {
|
|
270
|
+
if (currentHeading) headings.push(currentHeading);
|
|
271
|
+
currentHeading = null;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
return headings;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Helper to find an existing id attr on a token. Should be a heading_open token, but could be anything really
|
|
278
|
+
* Provided by markdown-it-anchor or markdown-it-attrs
|
|
279
|
+
* @param {any} token Token
|
|
280
|
+
* @returns {string | null} Id attribute to use as anchor
|
|
281
|
+
*/
|
|
282
|
+
function findExistingIdAttr(token) {
|
|
283
|
+
if (token && token.attrs && token.attrs.length > 0) {
|
|
284
|
+
const idAttr = token.attrs.find((attr) => {
|
|
285
|
+
if (Array.isArray(attr) && attr.length >= 2) return attr[0] === "id";
|
|
286
|
+
return false;
|
|
287
|
+
});
|
|
288
|
+
if (idAttr && Array.isArray(idAttr) && idAttr.length >= 2) {
|
|
289
|
+
const [_, val] = idAttr;
|
|
290
|
+
return val;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Helper to get minimum headline level so that the TOC is nested correctly
|
|
297
|
+
* @param {Array<HeadlineItem>} headlineItems Search these
|
|
298
|
+
* @returns {number} Minimum level
|
|
299
|
+
*/
|
|
300
|
+
function getMinLevel(headlineItems) {
|
|
301
|
+
return Math.min(...headlineItems.map((item) => item.level));
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Helper that creates a TOCItem
|
|
305
|
+
* @param {number} level
|
|
306
|
+
* @param {string} text
|
|
307
|
+
* @param {string | null} anchor
|
|
308
|
+
* @param {TocItem} rootNode
|
|
309
|
+
* @returns {TocItem}
|
|
310
|
+
*/
|
|
311
|
+
function addListItem(level, text, anchor, rootNode) {
|
|
312
|
+
const listItem = {
|
|
313
|
+
level,
|
|
314
|
+
text,
|
|
315
|
+
anchor,
|
|
316
|
+
children: []
|
|
317
|
+
};
|
|
318
|
+
rootNode.children.push(listItem);
|
|
319
|
+
return listItem;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Turns a list of flat headline items into a nested tree object representing the TOC
|
|
323
|
+
* @param {Array<HeadlineItem>} headlineItems
|
|
324
|
+
* @returns {TocItem} Tree of TOC items
|
|
325
|
+
*/
|
|
326
|
+
function flatHeadlineItemsToNestedTree(headlineItems) {
|
|
327
|
+
/** @type {TocItem} */
|
|
328
|
+
const toc = {
|
|
329
|
+
level: getMinLevel(headlineItems) - 1,
|
|
330
|
+
anchor: null,
|
|
331
|
+
text: "",
|
|
332
|
+
children: []
|
|
333
|
+
};
|
|
334
|
+
let currentRootNode = toc;
|
|
335
|
+
let prevListItem = currentRootNode;
|
|
336
|
+
headlineItems.forEach((headlineItem) => {
|
|
337
|
+
if (headlineItem.level > prevListItem.level) {
|
|
338
|
+
Array.from({ length: headlineItem.level - prevListItem.level }).forEach((_) => {
|
|
339
|
+
currentRootNode = prevListItem;
|
|
340
|
+
prevListItem = addListItem(headlineItem.level, "", null, currentRootNode);
|
|
341
|
+
});
|
|
342
|
+
prevListItem.text = headlineItem.text;
|
|
343
|
+
prevListItem.anchor = headlineItem.anchor;
|
|
344
|
+
} else if (headlineItem.level === prevListItem.level) prevListItem = addListItem(headlineItem.level, headlineItem.text, headlineItem.anchor, currentRootNode);
|
|
345
|
+
else if (headlineItem.level < prevListItem.level) {
|
|
346
|
+
for (let i = 0; i < prevListItem.level - headlineItem.level; i++);
|
|
347
|
+
prevListItem = addListItem(headlineItem.level, headlineItem.text, headlineItem.anchor, currentRootNode);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
return toc;
|
|
351
|
+
}
|
|
352
|
+
|
|
170
353
|
//#endregion
|
|
171
354
|
//#region src/markdown-it/table-of-contents.ts
|
|
172
355
|
function tableOfContentsRule(md) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soubiran/vite",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.4",
|
|
5
5
|
"author": "Estéban Soubiran <esteban@soubiran.dev>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": "https://github.com/sponsors/Barbapapazes",
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./dist/vite.config.d.ts",
|
|
17
17
|
"import": "./dist/vite.config.mjs"
|
|
18
|
+
},
|
|
19
|
+
"./utils": {
|
|
20
|
+
"types": "./dist/utils.d.ts",
|
|
21
|
+
"import": "./dist/utils.mjs"
|
|
18
22
|
}
|
|
19
23
|
},
|
|
20
24
|
"main": "dist/vite.config.mjs",
|
|
@@ -54,7 +58,7 @@
|
|
|
54
58
|
"vite": "npm:rolldown-vite@7.1.20",
|
|
55
59
|
"vite-ssg": "^28.2.2",
|
|
56
60
|
"vue-router": "^4.6.3",
|
|
57
|
-
"@soubiran/ui": "0.1.
|
|
61
|
+
"@soubiran/ui": "0.1.4"
|
|
58
62
|
},
|
|
59
63
|
"devDependencies": {
|
|
60
64
|
"tsdown": "^0.18.3"
|