Ctrl K
ComunidadGuías…

eslint-plugins/nsfw-flag.js

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/**
 * ESLint 9 plugin to automatically mark NSFW routes with the nsfw flag
 */
import { eslintCompatPlugin } from '@oxlint/plugins';

const nsfwRoutes = [
    '141jav',
    '141ppv',
    '18comic',
    '2048',
    '7mmtv',
    '8kcos',
    '91porn',
    '95mm',
    'abskoop',
    'asiantolick',
    'asmr-200',
    'booru',
    'chikubi',
    'chub',
    'civitai',
    'cool18',
    'coomer',
    'copymanga',
    'cosplaytele',
    'dlsite',
    'e-hentai',
    'ehentai',
    'everia',
    'fanbox',
    'fansly',
    'fantia',
    'freexcomic',
    'furaffinity',
    'gelbooru',
    'hanime1',
    'iwara',
    'javbus',
    'javdb',
    'javlibrary',
    'javtiful',
    'javtrailers',
    'jpxgmn',
    'kemono',
    'kisskiss',
    'komiic',
    'konachan',
    'koyso',
    'laimanhua',
    'literotica',
    'mangadex',
    'manhuagui',
    'manyvids',
    'missav',
    'netflav',
    'nhentai',
    'olevod',
    'oreno3d',
    'patreon',
    'pixiv',
    'pornhub',
    'rawkuma',
    'sehuatang',
    'shuiguopai',
    'sis001',
    'skeb',
    'skebetter',
    'spankbang',
    't66y',
    'uraaka-joshi',
    'wnacg',
    'xbookcn',
    'xmanhua',
    'xsijishe',
    'yande',
    'zaimanhua',
    'zodgame',
    '4kup',
    'misskon',
    '4khd',
];

// 检查是否是 NSFW 路由文件
function isNsfwRoute(filePath) {
    const normalizedPath = filePath.replaceAll('\\', '/');
    return nsfwRoutes.some((nsfwKey) => {
        const routePattern = `/lib/routes/${nsfwKey}/`;
        return normalizedPath.includes(routePattern);
    });
}

export default eslintCompatPlugin({
    meta: {
        name: '@rsshub/nsfw-flag',
        version: '1.0.0',
    },
    configs: {
        recommended: {
            plugins: {
                '@rsshub/nsfw-flag': 'self',
            },
            rules: {
                '@rsshub/nsfw-flag/add-nsfw-flag': 'error',
            },
        },
    },
    rules: {
        'add-nsfw-flag': {
            meta: {
                type: 'problem',
                docs: {
                    description: 'Automatically add nsfw flag to NSFW routes',
                    category: 'Best Practices',
                    recommended: true,
                },
                fixable: 'code',
                schema: [],
                messages: {
                    missingNsfwFlag: 'NSFW route is missing the nsfw flag in features',
                },
            },
            createOnce: (context) => ({
                before() {
                    // 如果不是 NSFW 路由,跳过检查
                    if (!isNsfwRoute(context.filename)) {
                        return false;
                    }
                },
                ExportNamedDeclaration(node) {
                    // 查找 export const route: Route = {...}
                    if (
                        !node.declaration ||
                        node.declaration.type !== 'VariableDeclaration' ||
                        !node.declaration.declarations ||
                        !node.declaration.declarations[0] ||
                        !node.declaration.declarations[0].id ||
                        node.declaration.declarations[0].id.name !== 'route'
                    ) {
                        return;
                    }
                    const routeDeclaration = node.declaration.declarations[0];
                    const routeObject = routeDeclaration.init;

                    if (!routeObject || routeObject.type !== 'ObjectExpression') {
                        return;
                    }

                    let featuresProperty = null;
                    let nsfwProperty = null;

                    // 查找 features 属性
                    for (const prop of routeObject.properties) {
                        if (!(prop.type === 'Property' && prop.key && prop.key.name === 'features')) {
                            continue;
                        }

                        featuresProperty = prop;

                        // 在 features 中查找 nsfw 属性
                        if (prop.value && prop.value.type === 'ObjectExpression') {
                            for (const featureProp of prop.value.properties) {
                                if (!(featureProp.type === 'Property' && featureProp.key && featureProp.key.name === 'nsfw')) {
                                    continue;
                                }

                                nsfwProperty = featureProp;
                                break;
                            }
                        }
                        break;
                    }

                    // 检查是否需要添加或修复 nsfw 标志
                    if (!featuresProperty) {
                        // 没有 features 属性,需要添加整个 features 对象
                        context.report({
                            node: routeObject,
                            messageId: 'missingNsfwFlag',
                            fix(fixer) {
                                // 在对象的最后添加 features 属性
                                const lastProperty = routeObject.properties.at(-1);

                                return lastProperty
                                    ? fixer.insertTextAfter(lastProperty, ',\n    features: {\n        nsfw: true,\n    }')
                                    : // 空对象的情况
                                      fixer.insertTextAfter(routeObject.properties.length > 0 ? routeObject.properties.at(-1) : routeObject, '\n    features: {\n        nsfw: true,\n    }\n');
                            },
                        });
                    } else if (!nsfwProperty) {
                        // 有 features 属性但没有 nsfw 属性
                        context.report({
                            node: featuresProperty.value,
                            messageId: 'missingNsfwFlag',
                            fix(fixer) {
                                const featuresObject = featuresProperty.value;
                                if (featuresObject.properties.length > 0) {
                                    const lastFeatureProp = featuresObject.properties.at(-1);
                                    return fixer.insertTextAfter(lastFeatureProp, ',\n        nsfw: true');
                                }
                                // features 是空对象
                                return fixer.replaceTextRange([featuresObject.range[0] + 1, featuresObject.range[1] - 1], '\n        nsfw: true,\n    ');
                            },
                        });
                    } else if (nsfwProperty.value && (nsfwProperty.value.type !== 'Literal' || nsfwProperty.value.value !== true)) {
                        // nsfw 属性存在但不是 true
                        context.report({
                            node: nsfwProperty.value,
                            messageId: 'missingNsfwFlag',
                            fix: (fixer) => fixer.replaceText(nsfwProperty.value, 'true'),
                        });
                    }
                },
            }),
        },
    },
});