Skip to content

Commit 177fae4

Browse files
committed
docs: extension sorts demos by release
1 parent 05b6ac8 commit 177fae4

File tree

1 file changed

+63
-7
lines changed

1 file changed

+63
-7
lines changed

docs/extensions/mrdocs-demos.js

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,83 @@ const fs = require("fs");
1313

1414
function getSubdirectoriesSync(url) {
1515
try {
16+
// cache setup
1617
let urlPath = new URL(url).pathname;
1718
let cacheFilenamePath = urlPath.replace(/[^a-zA-Z0-9]/g, '') + '.json';
1819
let cachePath = `${__dirname}/../build/requests/${cacheFilenamePath}`;
1920
fs.mkdirSync(`${__dirname}/../build/requests/`, {recursive: true});
2021
const readFromCacheFile = fs.existsSync(cachePath) && fs.statSync(cachePath).mtime > new Date(Date.now() - 1000 * 60 * 60 * 24);
22+
23+
// read file or make request
2124
const data =
2225
readFromCacheFile ?
2326
fs.readFileSync(cachePath, 'utf-8') :
2427
request('GET', url).getBody('utf-8')
2528
if (!readFromCacheFile) {
2629
fs.writeFileSync(cachePath, data);
2730
}
28-
const regex = /<a href="([^"]+)\/">/g;
29-
const directories = [];
31+
32+
// parse entries: name + date (if present)
33+
// Matches: <a href="name/">name/</a> [spaces] 11-Sep-2025 20:51
34+
const entryRe = /<a href="([^"]+)\/">[^<]*<\/a>\s+(\d{2}-[A-Za-z]{3}-\d{4}\s+\d{2}:\d{2})?/g;
35+
36+
const month = { Jan:0,Feb:1,Mar:2,Apr:3,May:4,Jun:5,Jul:6,Aug:7,Sep:8,Oct:9,Nov:10,Dec:11 };
37+
const parseDate = (s) => {
38+
if (!s) return null; // missing or no date in listing
39+
// "11-Sep-2025 20:51"
40+
const m = /^(\d{2})-([A-Za-z]{3})-(\d{4})\s+(\d{2}):(\d{2})$/.exec(s.trim());
41+
if (!m) return null;
42+
const [, d, mon, y, hh, mm] = m;
43+
return new Date(Date.UTC(+y, month[mon], +d, +hh, +mm));
44+
};
45+
46+
const isSemver = (name) => {
47+
// allow optional leading 'v', ignore pre-release/build metadata for ordering
48+
const m = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(name);
49+
if (!m) return null;
50+
return { major: +m[1], minor: +m[2], patch: +m[3] };
51+
};
52+
53+
const entries = [];
3054
let match;
31-
while ((match = regex.exec(data)) !== null) {
32-
if (match[1] !== '..' && match[1] !== '.') {
33-
directories.push(match[1]);
34-
}
55+
while ((match = entryRe.exec(data)) !== null) {
56+
const name = match[1];
57+
if (name === '.' || name === '..') continue;
58+
const dt = parseDate(match[2] || null);
59+
const sv = isSemver(name);
60+
entries.push({
61+
name,
62+
date: dt, // may be null
63+
semver: !!sv,
64+
major: sv ? sv.major : 0,
65+
minor: sv ? sv.minor : 0,
66+
patch: sv ? sv.patch : 0,
67+
});
3568
}
36-
return directories;
69+
70+
// sort
71+
entries.sort((a, b) => {
72+
// 1) non-semver first
73+
if (a.semver !== b.semver) return a.semver ? 1 : -1;
74+
75+
if (!a.semver && !b.semver) {
76+
// non-semver: newer date first; if no date, push to end among non-semver
77+
const ad = a.date ? a.date.getTime() : -Infinity;
78+
const bd = b.date ? b.date.getTime() : -Infinity;
79+
if (ad !== bd) return bd - ad;
80+
// tie-breaker: name asc for stability
81+
return a.name.localeCompare(b.name);
82+
}
83+
84+
// semver: major ↓, minor ↓, patch ↓
85+
if (a.major !== b.major) return b.major - a.major;
86+
if (a.minor !== b.minor) return b.minor - a.minor;
87+
if (a.patch !== b.patch) return b.patch - a.patch;
88+
// final tie-breaker: name asc
89+
return a.name.localeCompare(b.name);
90+
});
91+
92+
return entries.map(e => e.name);
3793
} catch (error) {
3894
console.error('Error:', error);
3995
return [];

0 commit comments

Comments
 (0)