mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-03-13 10:30:18 +08:00
* chore: add oxlint support * style: apply autofix * style: apply autofix for toSorted * style: use alternative api for nsfw-flag jsPlugins * fix: git diff * fix: codeql * test: console.log * style: update lint workflow to use Checkstyle SARIF converter * style: remove debug log from extractDateFromURL function * chore: use oxlint-json-to-sarif * test: console.log * test: remove console.log * test: update cookie data expectation in getCookies test https://github.com/mccutchen/go-httpbin/pull/235 breaks this * style: type-aware linting * style: enable type-aware linting for oxlint
189 lines
5.8 KiB
TypeScript
189 lines
5.8 KiB
TypeScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
import { config } from '../../lib/config';
|
|
import { namespaces } from '../../lib/registry';
|
|
import { getCurrentPath } from '../../lib/utils/helpers';
|
|
import { categories } from './data';
|
|
|
|
const fullTests = await (await fetch('https://cdn.jsdelivr.net/gh/DIYgod/RSSHub@gh-pages/build/test-full-routes.json')).json();
|
|
const testResult = fullTests.testResults[0].assertionResults;
|
|
|
|
const foloAnalysis = await (
|
|
await fetch('https://raw.githubusercontent.com/RSSNext/rsshub-docs/refs/heads/main/rsshub-analytics.json', {
|
|
headers: {
|
|
'user-agent': config.trueUA,
|
|
},
|
|
})
|
|
).json();
|
|
const foloAnalysisResult = foloAnalysis.data as Record<string, { subscriptionCount: number; topFeeds: any[] }>;
|
|
const foloAnalysisTop100 = Object.entries(foloAnalysisResult)
|
|
.toSorted((a, b) => b[1].subscriptionCount - a[1].subscriptionCount)
|
|
.slice(0, 150);
|
|
|
|
const __dirname = getCurrentPath(import.meta.url);
|
|
|
|
// Build namespace-centric data structure
|
|
interface NamespaceData {
|
|
name: string;
|
|
url?: string;
|
|
description?: string;
|
|
zh?: {
|
|
name?: string;
|
|
description?: string;
|
|
};
|
|
categories: string[];
|
|
heat: number;
|
|
routes: Record<string, RouteData>;
|
|
}
|
|
|
|
interface RouteData {
|
|
path: string | string[];
|
|
name: string;
|
|
url?: string;
|
|
maintainers: string[];
|
|
example: string;
|
|
parameters?: Record<string, any>;
|
|
description?: string;
|
|
categories?: string[];
|
|
features?: Record<string, any>;
|
|
radar?: any[];
|
|
view?: number;
|
|
location?: string;
|
|
heat: number;
|
|
topFeeds: any[];
|
|
zh?: {
|
|
name?: string;
|
|
description?: string;
|
|
parameters?: Record<string, any>;
|
|
};
|
|
test?: {
|
|
code: number;
|
|
message?: string;
|
|
};
|
|
}
|
|
|
|
const namespacesData: Record<string, NamespaceData> = {};
|
|
|
|
// First pass: build namespace data with all routes
|
|
for (const namespace in namespaces) {
|
|
const nsData = namespaces[namespace];
|
|
|
|
// Determine default category
|
|
let defaultCategory = nsData.categories?.[0];
|
|
if (!defaultCategory) {
|
|
for (const routePath in nsData.routes) {
|
|
if (nsData.routes[routePath].categories) {
|
|
defaultCategory = nsData.routes[routePath].categories[0];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!defaultCategory) {
|
|
defaultCategory = 'other';
|
|
}
|
|
|
|
// Collect all categories for this namespace
|
|
const nsCategories = new Set<string>(nsData.categories || []);
|
|
|
|
// Initialize namespace data
|
|
namespacesData[namespace] = {
|
|
name: nsData.name === 'Unknown' ? namespace : nsData.name,
|
|
url: nsData.url,
|
|
description: nsData.description,
|
|
zh: nsData.zh
|
|
? {
|
|
name: nsData.zh.name,
|
|
description: nsData.zh.description,
|
|
}
|
|
: undefined,
|
|
categories: [],
|
|
heat: 0,
|
|
routes: {},
|
|
};
|
|
|
|
// Process routes
|
|
const processedPaths = new Set<string>();
|
|
|
|
for (const routePath in nsData.routes) {
|
|
const realPath = `/${namespace}${routePath}`;
|
|
const routeData = nsData.routes[routePath];
|
|
|
|
// Skip duplicate array paths
|
|
if (Array.isArray(routeData.path)) {
|
|
if (processedPaths.has(routeData.path[0])) {
|
|
continue;
|
|
}
|
|
processedPaths.add(routeData.path[0]);
|
|
}
|
|
|
|
// Determine route categories
|
|
const routeCategories = routeData.categories || nsData.categories || [defaultCategory];
|
|
|
|
// Check if popular
|
|
const isPopular = foloAnalysisTop100.some(([p]) => p === realPath);
|
|
if (isPopular && !routeCategories.includes('popular')) {
|
|
routeCategories.push('popular');
|
|
}
|
|
|
|
// Add categories to namespace
|
|
for (const cat of routeCategories) {
|
|
nsCategories.add(cat);
|
|
}
|
|
|
|
// Get test result
|
|
const test = testResult.find((t) => t.title === realPath);
|
|
const parsedTest = test
|
|
? {
|
|
code: test.status === 'passed' ? 0 : 1,
|
|
message: test.failureMessages?.[0],
|
|
}
|
|
: undefined;
|
|
|
|
const heat = foloAnalysisResult[realPath]?.subscriptionCount || 0;
|
|
|
|
// Build route data
|
|
namespacesData[namespace].routes[realPath] = {
|
|
path: routeData.path,
|
|
name: routeData.name,
|
|
url: routeData.url,
|
|
maintainers: routeData.maintainers,
|
|
example: routeData.example,
|
|
parameters: routeData.parameters,
|
|
description: routeData.description,
|
|
categories: routeCategories,
|
|
features: routeData.features,
|
|
radar: routeData.radar,
|
|
view: routeData.view,
|
|
location: routeData.location,
|
|
heat,
|
|
topFeeds: foloAnalysisResult[realPath]?.topFeeds || [],
|
|
zh: routeData.zh
|
|
? {
|
|
name: routeData.zh.name,
|
|
description: routeData.zh.description,
|
|
parameters: routeData.zh.parameters,
|
|
}
|
|
: undefined,
|
|
test: parsedTest,
|
|
};
|
|
|
|
namespacesData[namespace].heat += heat;
|
|
}
|
|
|
|
namespacesData[namespace].categories = [...nsCategories];
|
|
}
|
|
|
|
// Generate JSON output
|
|
fs.mkdirSync(path.join(__dirname, '../../assets/build/docs'), { recursive: true });
|
|
fs.writeFileSync(path.join(__dirname, '../../assets/build/docs/routes.json'), JSON.stringify(namespacesData, null, 2));
|
|
|
|
// Generate categories data
|
|
const categoriesData = categories.map((cat) => ({
|
|
id: cat.link.replace('/routes/', ''),
|
|
icon: cat.icon,
|
|
en: cat.en,
|
|
zh: cat.zh,
|
|
}));
|
|
fs.writeFileSync(path.join(__dirname, '../../assets/build/docs/categories.json'), JSON.stringify(categoriesData, null, 2));
|