Files
RSSHub/scripts/workflow/build-docs.ts
T
dependabot[bot]andTony 417ab04f06 chore(deps-dev): bump eslint-plugin-unicorn from 66.0.0 to 68.0.0 (#22310)
* chore(deps-dev): bump eslint-plugin-unicorn from 66.0.0 to 68.0.0

Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 66.0.0 to 68.0.0.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v66.0.0...v68.0.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-unicorn
  dependency-version: 68.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* style: fix no-useless-coercion

* style: fix prefer-boolean-return

* style: fix no-useless-logical-operand

* style: fix prefer-single-replace

* style: fix consistent-conditional-object-spread

* style: fix no-useless-else

* style: fix prefer-unicode-code-point-escapes

* style: fix operator-assignment

* style: fix prefer-continue

* style: fix prefer-math-constants

* style: fix prefer-hoisting-branch-code

* style: fix prefer-array-slice

* style: fix consistent-class-member-order

* style: fix no-return-array-push

* style: fix prefer-promise-with-resolvers

* style: fix no-array-concat-in-loop

* style: fix no-loop-iterable-mutation

* style: fix no-invalid-argument-count

* style: fix no-duplicate-if-branches

* style: fix prefer-else-if

* style: fix no-unreadable-for-of-expression

* style: fix logical-assignment-operators

* style: fix default-export-style

* style: revert false positve in prefer-type-literal-last in #22274

* style: fix arrow-body-style

* style: add v68 recommended preset

* style: refactor GraphQL queries to use template literals for better readability

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tony <TonyRL@users.noreply.github.com>
2026-06-20 23:11:27 +08:00

191 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) {
continue;
}
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));