chore(deps-dev): bump eslint-plugin-unicorn from 65.0.1 to 66.0.0 (#22274)

* chore(deps-dev): bump eslint-plugin-unicorn from 65.0.1 to 66.0.0

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

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

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

* style: fix unicorn-js/prefer-url-href

* style: oxlint disable

* style: fix unicorn-js/no-useless-else

* style: no-unsafe-string-replacement

* style: fix no-duplicate-loops

* style: fix prefer-number-is-safe-integer

* style: fix prefer-single-array-predicate

* style: fix no-object-methods-with-collections

* style: fix no-useless-boolean-cast

* style: fix no-useless-template-literals

* style: fix no-negated-array-predicate

* style: fix prefer-direct-iteration

* style: fix consistent-optional-chaining

* style: fix prefer-simple-sort-comparator

* style: fix prefer-global-number-constants

* style: fix prefer-type-literal-last

* style: fix require-array-sort-compare.

* style: fix prefer-early-return

* style: fix prefer-short-arrow-method

* style: fix prefer-array-from-map

* style: fix prefer-scoped-selector

* style: fix no-global-object-property-assignment

* style: fix no-unnecessary-global-this

* style: fix no-unreadable-object-destructuring

* style: fix no-invalid-argument-count

* style: fix prefer-smaller-scope

* style: fix prefer-iterator-to-array.

* style: fix prefer-object-iterable-methods

* style: fix typo

* style: fix max-nested-calls

* style: fix no-incorrect-template-string-interpolation

* style: fix no-break-in-nested-loop

* style: fix prefer-await

* style: fix no-computed-property-existence-check

* style: fix prefer-number-coercion

* style: fix no-empty-file

* style: update eslint unicorn v66 recommended preset

* style: add unicorn/prefer-spread to oxlint-disable comments

* style: fix no-array-reduce

* style: delete github/no-then as it's covered by unicorn/prefer-await

---------

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>
This commit is contained in:
dependabot[bot] 2026-06-16 14:43:42 +08:00 committed by GitHub
parent 4d2e5fe799
commit 873618e99d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
870 changed files with 2943 additions and 2974 deletions

View File

@ -18,7 +18,6 @@
"@stylistic/eslint-plugin",
"eslint-plugin-simple-import-sort",
"oxlint-plugin-eslint",
"./eslint-plugins/no-then.js",
"./eslint-plugins/nsfw-flag.js"
],
"rules": {
@ -149,57 +148,76 @@
// #endregion
// #region --- unicorn recommended ---
// "unicorn-js/better-dom-traversing": "error", false postive on cheerio
// "unicorn-js/better-dom-traversing": "error", false positive on cheerio
"unicorn/catch-error-name": "error",
"unicorn-js/class-reference-in-static-methods": "error",
// "unicorn-js/comment-content": "error", re-evaluate when unicorn > 66.0.0
"unicorn/consistent-assert": "error",
"unicorn-js/consistent-compound-words": "error", // use jsPlugins
"unicorn-js/consistent-class-member-order": "error",
"unicorn-js/consistent-compound-words": "error",
"unicorn/consistent-date-clone": "error",
"unicorn/consistent-empty-array-spread": "error",
"unicorn/consistent-existence-index-check": "error",
// "unicorn/consistent-function-scoping": "error",
"unicorn-js/consistent-json-file-read": "error", // use jsPlugins
"unicorn-js/consistent-export-decorator-position": "error",
// "unicorn/consistent-function-scoping": "error", -> warn
"unicorn-js/consistent-json-file-read": "error",
"unicorn-js/consistent-optional-chaining": "error",
"unicorn/consistent-template-literal-escape": "error",
"unicorn/empty-brace-spaces": "error",
"unicorn/error-message": "error",
"unicorn/escape-case": "error",
// "unicorn/expiring-todo-comments": "error", // not yet implemented
// "unicorn/explicit-length-check": "error",
"unicorn-js/explicit-timer-delay": "error",
// "unicorn/filename-case": "error",
"unicorn/import-style": "error",
"unicorn-js/isolated-functions": "error", // use jsPlugins
"unicorn-js/isolated-functions": "error",
"unicorn-js/max-nested-calls": "error",
"unicorn/new-for-builtins": "error",
"unicorn/no-abusive-eslint-disable": "error",
"unicorn/no-accessor-recursion": "error",
"unicorn/no-anonymous-default-export": "error",
// "unicorn/no-array-callback-reference": "error",
"unicorn-js/no-array-fill-with-reference-type": "error", // use jsPlugins
"unicorn-js/no-array-fill-with-reference-type": "error",
"unicorn/no-array-for-each": "error",
"unicorn-js/no-array-from-fill": "error", // use jsPlugins
"unicorn-js/no-array-from-fill": "error",
"unicorn/no-array-method-this-argument": "error",
// "unicorn/no-array-reduce": "error",
"unicorn/no-array-reverse": "error",
// "unicorn/no-array-sort": "error",
// "unicorn/no-await-expression-member": "error",
"unicorn/no-await-in-promise-methods": "error",
"unicorn-js/no-blob-to-file": "error", // use jsPlugins
"unicorn-js/no-canvas-to-image": "error", // use jsPlugins
"unicorn-js/no-confusing-array-splice": "error", // use jsPlugins
"unicorn-js/no-blob-to-file": "error",
// "unicorn-js/no-break-in-nested-loop": "error", unopinionated
// "unicorn-js/no-canvas-to-image": "error", // unused
"unicorn-js/no-computed-property-existence-check": "error",
"unicorn-js/no-confusing-array-splice": "error",
"unicorn-js/no-confusing-array-with": "error",
"unicorn/no-console-spaces": "error",
// "unicorn-js/no-declarations-before-early-exit": "error", re-evaluate when unicorn > 66.0.0
"unicorn/no-document-cookie": "error",
"unicorn-js/no-duplicate-set-values": "error", // use jsPlugins
"unicorn-js/no-duplicate-loops": "error",
"unicorn-js/no-duplicate-set-values": "error",
// "unicorn/no-empty-file": "error",
"unicorn-js/no-exports-in-scripts": "error", // use jsPlugins
"unicorn-js/no-error-property-assignment": "error",
"unicorn-js/no-exports-in-scripts": "error",
// "unicorn/no-for-loop": "error", // won't be implemented
"unicorn-js/no-global-object-property-assignment": "error",
// "unicorn/no-hex-escape": "error",
"unicorn/no-immediate-mutation": "error",
"unicorn-js/no-incorrect-query-selector": "error", // use jsPlugins
"unicorn-js/no-incorrect-query-selector": "error",
// "unicorn-js/no-incorrect-template-string-interpolation": "error", too many false positives
"unicorn/no-instanceof-builtins": "error",
"unicorn-js/no-invalid-argument-count": "error",
"unicorn/no-invalid-fetch-options": "error",
"unicorn/no-invalid-remove-event-listener": "error",
"unicorn-js/no-late-current-target-access": "error", // use jsPlugins
"unicorn-js/no-late-current-target-access": "error",
"unicorn/no-lonely-if": "error",
"unicorn/no-magic-array-flat-depth": "error",
"unicorn-js/no-mismatched-map-key": "error",
// "unicorn/no-named-default": "error", -> use import/no-named-default
"unicorn-js/no-negated-array-predicate": "error",
"unicorn-js/no-negated-comparison": "error",
"no-negated-condition": "off",
"unicorn/no-negated-condition": "error",
"unicorn/no-negation-in-equality-check": "error",
@ -209,42 +227,64 @@
"unicorn/no-new-buffer": "error",
// "unicorn/no-null": "error",
// "unicorn/no-object-as-default-parameter": "error",
"unicorn-js/no-object-methods-with-collections": "error",
"unicorn-js/no-optional-chaining-on-undeclared-variable": "error",
// "unicorn/no-process-exit": "error",
"unicorn-js/no-redundant-comparison": "error",
"unicorn-js/no-return-array-push": "error",
"unicorn/no-single-promise-in-promise-methods": "error",
"unicorn/no-static-only-class": "error",
"unicorn-js/no-subtraction-comparison": "error",
"unicorn/no-thenable": "error",
"unicorn/no-this-assignment": "error",
"unicorn-js/no-this-outside-of-class": "error", // use jsPlugins
"unicorn-js/no-this-outside-of-class": "error",
// "unicorn-js/no-top-level-side-effects": "error", // allows dayjs.extend()
"unicorn/no-typeof-undefined": "error",
"unicorn-js/no-undeclared-class-members": "error",
"unicorn/no-unnecessary-array-flat-depth": "error",
"unicorn/no-unnecessary-array-splice-count": "error",
"unicorn/no-unnecessary-await": "error",
"unicorn-js/no-unnecessary-nested-ternary": "error", // use jsPlugins
"unicorn-js/no-unnecessary-polyfills": "error", // use jsPlugins
"unicorn-js/no-unnecessary-global-this": "error",
"unicorn-js/no-unnecessary-nested-ternary": "error",
"unicorn-js/no-unnecessary-polyfills": "error",
"unicorn/no-unnecessary-slice-end": "error",
"unicorn-js/no-unnecessary-splice": "error",
"unicorn/no-unreadable-array-destructuring": "error",
"unicorn/no-unreadable-iife": "error",
"unicorn-js/no-unused-array-method-return": "error", // use jsPlugins
// "unicorn-js/no-unreadable-new-expression": "error", // allows new URL(x).href
"unicorn-js/no-unreadable-object-destructuring": "error",
"unicorn-js/no-unsafe-buffer-conversion": "error",
"unicorn-js/no-unsafe-property-key": "error",
"unicorn-js/no-unsafe-string-replacement": "error",
"unicorn-js/no-unused-array-method-return": "error",
"unicorn-js/no-useless-boolean-cast": "error",
"unicorn/no-useless-collection-argument": "error",
"unicorn-js/no-useless-concat": "error",
"unicorn-js/no-useless-else": "error",
"unicorn/no-useless-error-capture-stack-trace": "error",
"unicorn/no-useless-fallback-in-spread": "error",
// "unicorn/no-useless-iterator-to-array": "error",
"unicorn/no-useless-length-check": "error",
"unicorn/no-useless-promise-resolve-reject": "error",
// "unicorn-js/no-useless-recursion": "error", unopinionated
"unicorn/no-useless-spread": "error",
// "unicorn/no-useless-switch-case": "error",
"unicorn-js/no-useless-template-literals": "error",
// "unicorn/no-useless-undefined": "error",
"unicorn/no-zero-fractions": "error",
// "unicorn/number-literal-case": "error",
// "unicorn/numeric-separators-style": "error",
"unicorn/prefer-add-event-listener": "error",
"unicorn-js/prefer-add-event-listener-options": "error",
"unicorn/prefer-array-find": "error",
"unicorn/prefer-array-flat": "error",
"unicorn/prefer-array-flat-map": "error",
"unicorn-js/prefer-array-from-map": "error",
"unicorn/prefer-array-index-of": "error",
"unicorn-js/prefer-array-last-methods": "error", // use jsPlugins
"unicorn-js/prefer-array-last-methods": "error",
"unicorn/prefer-array-some": "error",
"unicorn/prefer-at": "error",
"unicorn-js/prefer-await": "error",
"unicorn/prefer-bigint-literals": "error",
"unicorn/prefer-blob-reading-methods": "error",
"unicorn/prefer-class-fields": "error",
@ -252,68 +292,94 @@
// "unicorn/prefer-code-point": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-default-parameters": "error",
"unicorn-js/prefer-direct-iteration": "error",
"unicorn/prefer-dom-node-append": "error",
"unicorn/prefer-dom-node-dataset": "error",
"unicorn/prefer-dom-node-remove": "error",
"unicorn/prefer-dom-node-text-content": "error",
"unicorn-js/prefer-early-return": "error",
"unicorn/prefer-event-target": "error",
"unicorn-js/prefer-export-from": "error", // use jsPlugins
"unicorn-js/prefer-get-or-insert-computed": "error", // use jsPlugins
"unicorn-js/prefer-export-from": "error",
"unicorn-js/prefer-get-or-insert-computed": "error",
"unicorn-js/prefer-global-number-constants": "error",
// "unicorn/prefer-global-this": "error",
// "unicorn-js/prefer-https": "error",
"unicorn-js/prefer-identifier-import-export-specifiers": "error",
"unicorn/prefer-includes": "error",
"unicorn-js/prefer-includes-over-repeated-comparisons": "error", // use jsPlugins
"unicorn-js/prefer-includes-over-repeated-comparisons": "error",
"unicorn-js/prefer-iterable-in-constructor": "error",
"unicorn-js/prefer-iterator-to-array": "error",
// "unicorn-js/prefer-iterator-to-array-at-end": "error",
"unicorn/prefer-keyboard-event-key": "error",
"unicorn-js/prefer-location-assign": "error",
"unicorn/prefer-logical-operator-over-ternary": "error",
"unicorn-js/prefer-math-abs": "error", // use jsPlugins
"unicorn-js/prefer-math-abs": "error",
"unicorn/prefer-math-min-max": "error",
"unicorn/prefer-math-trunc": "error",
// "unicorn-js/prefer-minimal-ternary": "error", re-evaluate when unicorn > 66.0.0
"unicorn/prefer-modern-dom-apis": "error",
"unicorn/prefer-modern-math-apis": "error",
// "unicorn/prefer-module": "error",
"unicorn/prefer-native-coercion-functions": "error",
"unicorn/prefer-negative-index": "error",
"unicorn/prefer-node-protocol": "error",
// "unicorn/prefer-number-properties": "error",
"unicorn-js/prefer-number-coercion": "error",
"unicorn-js/prefer-number-is-safe-integer": "error",
// "unicorn/prefer-number-properties": "error", // checkNaN: false
"unicorn-js/prefer-object-define-properties": "error",
"unicorn-js/prefer-object-destructuring-defaults": "error",
"unicorn/prefer-object-from-entries": "error",
"unicorn-js/prefer-object-iterable-methods": "error",
"unicorn/prefer-optional-catch-binding": "error",
// "unicorn-js/prefer-path2d": "error", // unused
"unicorn-js/prefer-private-class-fields": "error",
"unicorn/prefer-prototype-methods": "error",
"unicorn/prefer-query-selector": "error",
"unicorn-js/prefer-queue-microtask": "error", // use jsPlugins
"unicorn-js/prefer-queue-microtask": "error",
"unicorn/prefer-reflect-apply": "error",
"unicorn/prefer-regexp-test": "error",
"unicorn/prefer-response-static-json": "error",
"unicorn-js/prefer-scoped-selector": "error",
"unicorn/prefer-set-has": "error",
"unicorn/prefer-set-size": "error",
"unicorn-js/prefer-simple-condition-first": "error", // use jsPlugins
"unicorn-js/prefer-single-call": "error", // use jsPlugins
"unicorn-js/prefer-split-limit": "error", // use jsPlugins
"unicorn-js/prefer-short-arrow-method": "error",
"unicorn-js/prefer-simple-condition-first": "error",
"unicorn-js/prefer-simple-sort-comparator": "error",
"unicorn-js/prefer-single-array-predicate": "error",
"unicorn-js/prefer-single-call": "error",
"unicorn-js/prefer-single-object-destructuring": "error",
"unicorn-js/prefer-smaller-scope": "error",
"unicorn-js/prefer-split-limit": "error",
// "unicorn/prefer-spread": "error",
"unicorn-js/prefer-string-match-all": "error", // use jsPlugins
"unicorn-js/prefer-string-pad-start-end": "error", // use jsPlugins
"unicorn-js/prefer-string-match-all": "error",
"unicorn-js/prefer-string-pad-start-end": "error",
"unicorn/prefer-string-raw": "error",
"unicorn-js/prefer-string-repeat": "error", // use jsPlugins
"unicorn-js/prefer-string-repeat": "error",
"unicorn/prefer-string-replace-all": "error",
// "unicorn/prefer-string-slice": "error",
"unicorn/prefer-string-starts-ends-with": "error",
"unicorn/prefer-string-trim-start-end": "error",
"unicorn/prefer-structured-clone": "error",
// "unicorn/prefer-switch": "error", // use jsPlugins
// "unicorn/prefer-switch": "error",
"unicorn/prefer-ternary": "error",
// "unicorn/prefer-top-level-await": "error",
"unicorn/prefer-type-error": "error",
"unicorn-js/prefer-type-literal-last": "error",
// "unicorn-js/prefer-uint8array-base64": "error", re-evaluate when node > 25
"unicorn-js/prefer-url-href": "error",
// "unicorn/prevent-abbreviations": "error",
"unicorn/relative-url-style": "error",
"unicorn/require-array-join-separator": "error",
"unicorn-js/require-css-escape": "error", // use jsPlugins
"unicorn-js/require-array-sort-compare": "error",
"unicorn-js/require-css-escape": "error",
"unicorn/require-module-attributes": "error",
"unicorn/require-module-specifiers": "error",
"unicorn/require-number-to-fixed-digits-argument": "error",
"unicorn-js/require-passive-events": "error", // use jsPlugins
"unicorn-js/require-passive-events": "error",
"unicorn-js/require-proxy-trap-boolean-return": "error",
// "unicorn/switch-case-braces": "error",
"unicorn-js/switch-case-break-position": "error", // use jsPlugins
"unicorn-js/template-indent": "error", // use jsPlugins
"unicorn-js/switch-case-break-position": "error",
"unicorn-js/template-indent": "error",
// "unicorn/text-encoding-identifier-case": "error",
"unicorn/throw-new-error": "error",
// #endregion
@ -415,14 +481,14 @@
}
],
"eslint-js/no-implicit-globals": "error", // use jsPlugins
"eslint-js/no-implicit-globals": "error",
"no-labels": "error",
"no-lonely-if": "error",
"no-multi-str": "error",
"no-new-func": "error",
"eslint-js/no-restricted-syntax": [
"error", // use jsPlugins
"error",
{
"selector": "CallExpression[callee.property.name='get'][arguments.length=0]",
"message": "Please use .toArray() instead."
@ -474,7 +540,7 @@
"no-useless-concat": "warn",
"no-useless-rename": "error",
"no-var": "error",
"eslint-js/object-shorthand": "error", // use jsPlugins
"eslint-js/object-shorthand": "error",
"prefer-arrow-callback": "error",
"prefer-const": "error",
"prefer-object-has-own": "error",
@ -650,9 +716,6 @@
],
// #endregion
// github
"github/no-then": "warn",
// rsshub
"@rsshub/nsfw-flag/add-nsfw-flag": "error"
},

View File

@ -1,45 +0,0 @@
import { eslintCompatPlugin } from '@oxlint/plugins';
const rule = {
meta: {
type: 'suggestion',
docs: {
description: 'enforce using `async/await` syntax over Promises',
url: 'https://github.com/github/eslint-plugin-github/blob/main/docs/rules/no-then.md',
recommended: true,
},
schema: [],
messages: {
preferAsyncAwait: 'Prefer async/await to Promise.{{method}}()',
},
},
createOnce(context) {
return {
MemberExpression(node) {
if (node.property && node.property.name === 'then') {
context.report({
node: node.property,
messageId: 'preferAsyncAwait',
data: { method: 'then' },
});
} else if (node.property && node.property.name === 'catch') {
context.report({
node: node.property,
messageId: 'preferAsyncAwait',
data: { method: 'catch' },
});
}
},
};
},
};
export default eslintCompatPlugin({
meta: {
name: 'github',
},
rules: {
'no-then': rule,
},
});

View File

@ -119,96 +119,92 @@ export default eslintCompatPlugin({
missingNsfwFlag: 'NSFW route is missing the nsfw flag in features',
},
},
createOnce(context) {
return {
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'
) {
const routeDeclaration = node.declaration.declarations[0];
const routeObject = routeDeclaration.init;
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') {
let featuresProperty = null;
let nsfwProperty = null;
if (routeObject && routeObject.type === 'ObjectExpression') {
let featuresProperty = null;
let nsfwProperty = null;
// 查找 features 属性
for (const prop of routeObject.properties) {
if (prop.type === 'Property' && prop.key && prop.key.name === 'features') {
featuresProperty = prop;
// 查找 features 属性
for (const prop of routeObject.properties) {
if (prop.type === 'Property' && prop.key && prop.key.name === 'features') {
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') {
nsfwProperty = featureProp;
break;
}
}
// 在 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') {
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');
} else {
// 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) {
return fixer.replaceText(nsfwProperty.value, 'true');
},
});
}
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'),
});
}
}
},
}),
},
},
});

View File

@ -9,10 +9,10 @@ for (const namespace in namespaces) {
for (const path in namespaces[namespace].routes) {
if (namespaces[namespace].routes[path].categories?.length) {
for (const category of namespaces[namespace].routes[path].categories!) {
if (!categoryList[category]) {
if (!Object.hasOwn(categoryList, category)) {
categoryList[category] = {};
}
if (!categoryList[category][namespace]) {
if (!Object.hasOwn(categoryList[category], namespace)) {
categoryList[category][namespace] = {
...namespaces[namespace],
routes: {},

View File

@ -19,12 +19,12 @@ for (const namespace in namespaces) {
const subdomain = parsedDomain.subdomain || '.';
const domain = parsedDomain.domain;
if (domain) {
if (!radar[domain]) {
if (!Object.hasOwn(radar, domain)) {
radar[domain] = {
_name: namespaces[namespace].name,
} as RadarDomain;
}
if (!radar[domain][subdomain]) {
if (!Object.hasOwn(radar[domain], subdomain)) {
radar[domain][subdomain] = [];
}
radar[domain][subdomain].push({

View File

@ -19,12 +19,12 @@ for (const namespace in namespaces) {
const subdomain = parsedDomain.subdomain || '.';
const domain = parsedDomain.domain;
if (domain) {
if (!radar[domain]) {
if (!Object.hasOwn(radar, domain)) {
radar[domain] = {
_name: namespaces[namespace].name,
} as RadarDomain;
}
if (!radar[domain][subdomain]) {
if (!Object.hasOwn(radar[domain], subdomain)) {
radar[domain][subdomain] = [];
}
radar[domain][subdomain].push({

View File

@ -718,9 +718,8 @@ const TRUE_UA = 'RSSHub/1.0 (+http://github.com/DIYgod/RSSHub; like FeedFetcher-
const toBoolean = (value: string | undefined, defaultValue: boolean) => {
if (value === undefined) {
return defaultValue;
} else {
return ['', '0', 'false'].includes(value) ? false : !!value;
}
return ['', '0', 'false'].includes(value) ? false : !!value;
};
const toInt = (value: string | undefined, defaultValue?: number) => (value === undefined ? defaultValue : Number.parseInt(value));
@ -1220,24 +1219,25 @@ const calculateValue = () => {
};
calculateValue();
(async () => {
if (envs.REMOTE_CONFIG) {
const { default: logger } = await import('@/utils/logger');
try {
const data = await ofetch(envs.REMOTE_CONFIG, {
headers: {
Authorization: `Basic ${envs.REMOTE_CONFIG_AUTH}`,
},
});
if (data) {
envs = Object.assign(envs, data);
calculateValue();
logger.info('Remote config loaded.');
} else {
logger.error('Remote config load failed.');
}
} catch (error) {
logger.error('Remote config load failed.', error);
if (!envs.REMOTE_CONFIG) {
return;
}
const { default: logger } = await import('@/utils/logger');
try {
const data = await ofetch(envs.REMOTE_CONFIG, {
headers: {
Authorization: `Basic ${envs.REMOTE_CONFIG_AUTH}`,
},
});
if (data) {
envs = Object.assign(envs, data);
calculateValue();
logger.info('Remote config loaded.');
} else {
logger.error('Remote config load failed.');
}
} catch (error) {
logger.error('Remote config load failed.', error);
}
})();

View File

@ -27,12 +27,14 @@ export const errorHandler: ErrorHandler = (error, ctx) => {
}
debug.error++;
if (!debug.errorPaths[requestPath]) {
const errorPathCount = debug.errorPaths[requestPath];
if (!errorPathCount) {
debug.errorPaths[requestPath] = 0;
}
debug.errorPaths[requestPath]++;
if (!debug.errorRoutes[matchedRoute] && hasMatchedRoute) {
const errorRouteCount = debug.errorRoutes[matchedRoute];
if (!errorRouteCount && hasMatchedRoute) {
debug.errorRoutes[matchedRoute] = 0;
}
hasMatchedRoute && debug.errorRoutes[matchedRoute]++;

View File

@ -6,7 +6,8 @@ import { getDebugInfo, setDebugInfo } from '@/utils/debug-info';
const middleware: MiddlewareHandler = async (ctx, next) => {
{
const debug = getDebugInfo();
if (!debug.paths[ctx.req.path]) {
const pathCount = debug.paths[ctx.req.path];
if (!pathCount) {
debug.paths[ctx.req.path] = 0;
}
debug.paths[ctx.req.path]++;
@ -21,7 +22,8 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
const debug = getDebugInfo();
const rPath = routePath(ctx);
const hasMatchedRoute = rPath !== '/*';
if (!debug.routes[rPath] && hasMatchedRoute) {
const routeCount = debug.routes[rPath];
if (!routeCount && hasMatchedRoute) {
debug.routes[rPath] = 0;
}
hasMatchedRoute && debug.routes[rPath]++;

View File

@ -264,7 +264,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
}
if (ctx.req.query('filterout_category')) {
const categoryRegex = makeRegex(ctx.req.query('filterout_category')!);
isFilter = isFilter && !category.some((c) => (categoryRegex instanceof RE2JS ? categoryRegex.matcher(c).find() : c.match(categoryRegex)));
isFilter = isFilter && category.every((c) => !(categoryRegex instanceof RE2JS ? categoryRegex.matcher(c).find() : c.match(categoryRegex)));
}
return isFilter;
@ -296,9 +296,8 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
const encodedlink = encodeURIComponent(item.link);
item.link = `https://t.me/iv?url=${encodedlink}&rhash=${ctx.req.query('tgiv')}`;
return item;
} else {
return item;
}
return item;
});
}
@ -407,9 +406,8 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
if (num.test(ctx.req.query('brief')!)) {
const brief: number = Number.parseInt(ctx.req.query('brief')!);
for (const item of data.item) {
let text;
if (item.description) {
text = sanitizeHtml(item.description, { allowedTags: [], allowedAttributes: {} });
const text = sanitizeHtml(item.description, { allowedTags: [], allowedAttributes: {} });
item.description = text.length > brief ? `<p>${text.slice(0, brief)}…</p>` : `<p>${text}</p>`;
}
}

View File

@ -110,22 +110,22 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
if (ctx.get('redirect')) {
return ctx.redirect(ctx.get('redirect'), 301);
} else if (ctx.get('no-content')) {
}
if (ctx.get('no-content')) {
return ctx.body(null);
} else {
// retain .ums for backward compatibility
switch (outputType) {
case 'ums':
case 'rss3':
return ctx.json(rss3(result));
case 'json':
ctx.header('Content-Type', 'application/feed+json; charset=UTF-8');
return ctx.body(json(result));
case 'atom':
return ctx.render(<Atom data={result} />);
default:
return ctx.render(<RSS data={result} />);
}
}
// retain .ums for backward compatibility
switch (outputType) {
case 'ums':
case 'rss3':
return ctx.json(rss3(result));
case 'json':
ctx.header('Content-Type', 'application/feed+json; charset=UTF-8');
return ctx.body(json(result));
case 'atom':
return ctx.render(<Atom data={result} />);
default:
return ctx.render(<RSS data={result} />);
}
};

View File

@ -42,7 +42,7 @@ export async function registerRoute(namespace: string, route: Route, namespaceCo
const { namespaces } = await import('./registry');
if (!namespaces[namespace]) {
if (!Object.hasOwn(namespaces, namespace)) {
namespaces[namespace] = {
...namespaceConfig,
name: namespaceConfig?.name || namespace,
@ -55,13 +55,14 @@ export async function registerRoute(namespace: string, route: Route, namespaceCo
const subApp = app.basePath(`/${namespace}`);
const wrappedHandler: Handler = async (ctx) => {
if (!ctx.get('data')) {
const response = await route.handler(ctx);
if (response instanceof Response) {
return response;
}
ctx.set('data', response);
if (ctx.get('data')) {
return;
}
const response = await route.handler(ctx);
if (response instanceof Response) {
return response;
}
ctx.set('data', response);
};
for (const path of paths) {

View File

@ -139,7 +139,7 @@ if (Object.keys(modules).length) {
content.namespace
);
} else if ('route' in content) {
if (!namespaces[namespace]) {
if (!Object.hasOwn(namespaces, namespace)) {
namespaces[namespace] = {
name: namespace,
routes: {},
@ -160,7 +160,7 @@ if (Object.keys(modules).length) {
};
}
} else if ('apiRoute' in content) {
if (!namespaces[namespace]) {
if (!Object.hasOwn(namespaces, namespace)) {
namespaces[namespace] = {
name: namespace,
routes: {},
@ -278,19 +278,20 @@ for (const namespace of namespacesByDepth) {
for (const [path, routeData] of sortedRoutes) {
const wrappedHandler: Handler = async (ctx) => {
if (!ctx.get('apiData')) {
if (typeof routeData.handler !== 'function') {
if (process.env.NODE_ENV === 'test') {
const { apiRoute } = await import(`./routes/${namespace}/${routeData.location}`);
routeData.handler = apiRoute.handler;
} else if (routeData.module) {
const { apiRoute } = await routeData.module();
routeData.handler = apiRoute.handler;
}
}
const data = await routeData.handler(ctx);
ctx.set('apiData', data);
if (ctx.get('apiData')) {
return;
}
if (typeof routeData.handler !== 'function') {
if (process.env.NODE_ENV === 'test') {
const { apiRoute } = await import(`./routes/${namespace}/${routeData.location}`);
routeData.handler = apiRoute.handler;
} else if (routeData.module) {
const { apiRoute } = await routeData.module();
routeData.handler = apiRoute.handler;
}
}
const data = await routeData.handler(ctx);
ctx.set('apiData', data);
};
subApp.get(path, wrappedHandler);
}

View File

@ -9,7 +9,7 @@ import timezone from '@/utils/timezone';
export const handler = async (ctx) => {
const { category = 'zx' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 20;
const rootUrl = 'https://005.tv';
const currentUrl = new URL(category ? `${category}/` : '', rootUrl).href;

View File

@ -13,7 +13,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx: Context): Promise<Data> => {
const { filter } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '100', 10);
const limit = Number(ctx.req.query('limit') ?? '100');
const baseUrl = 'https://0xxx.ws';
const targetUrl: string = new URL(filter ? `?${filter}` : '', baseUrl).href;

View File

@ -13,7 +13,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx: Context): Promise<Data> => {
const { category = 'newslists', id } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const baseUrl = 'https://info.10000link.com';
const targetUrl: string = new URL(`${category}.aspx${id ? `?chid=${id}` : ''}`, baseUrl).href;

View File

@ -7,7 +7,7 @@ import { parseDate } from '@/utils/parse-date';
export const handler = async (ctx) => {
const { tag } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 20;
const rootUrl = 'https://news.10jqka.com.cn';
const apiUrl = new URL('tapp/news/push/stock', rootUrl).href;

View File

@ -25,7 +25,7 @@ const renderDescription = (description, images) =>
);
export const handler = async (ctx: Context): Promise<Data> => {
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '100', 10);
const limit = Number(ctx.req.query('limit') ?? '100');
const baseUrl = 'https://tf.121.com.cn';
const imgBaseUrl = 'https://wx.121.com.cn';

View File

@ -8,7 +8,7 @@ import timezone from '@/utils/timezone';
const handler = async (ctx) => {
const { category = 'zxfb' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 15;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 15;
const rootUrl = 'https://www.12371.cn/';
const currentUrl = `${rootUrl}${category}/`;

View File

@ -38,7 +38,10 @@ async function handler(ctx) {
description: `网易云音乐歌手专辑 - ${data.artist.name}`,
image: data.artist.img1v1Url || data.artist.picUrl,
item: data.hotAlbums.map((item) => {
const singer = item.artists.length === 1 ? item.artists[0].name : item.artists.reduce((prev, cur) => (prev.name || prev) + '/' + cur.name);
let singer = item.artists[0].name;
for (const artist of item.artists.slice(1)) {
singer += '/' + artist.name;
}
return {
title: `${item.name} - ${singer}`,
description: renderPlaylistDescription({

View File

@ -55,7 +55,10 @@ async function handler(ctx) {
description: `网易云音乐歌单 - ${data.name}`,
item: data.trackIds.slice(0, 201).map((item) => {
const thisSong = songs.find((element) => element.id === item.id);
const singer = thisSong.artists.length === 1 ? thisSong.artists[0].name : thisSong.artists.reduce((prev, cur) => (prev.name || prev) + '/' + cur.name);
let singer = thisSong.artists[0].name;
for (const artist of thisSong.artists.slice(1)) {
singer += '/' + artist.name;
}
return {
title: `${thisSong.name} - ${singer}`,
description: renderPlaylistDescription({

View File

@ -122,7 +122,8 @@ async function handler(ctx) {
const cfg = config[category];
if (!cfg) {
throw new InvalidParameterError('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
} else if ((category !== 'whole' && type === 'click' && time === 'month') || (category === 'whole' && type === 'click' && time === 'hour') || (type === 'follow' && time === 'hour')) {
}
if ((category !== 'whole' && type === 'click' && time === 'month') || (category === 'whole' && type === 'click' && time === 'hour') || (type === 'follow' && time === 'hour')) {
throw new InvalidParameterError('Bad timeRange range. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
}

View File

@ -91,7 +91,7 @@ async function handler(ctx) {
return {
title: $('title')
.text()
.replace(/最新的/, $('.article-nav .active').text()),
.replace(/最新的/, () => $('.article-nav .active').text()),
link: currentUrl,
item: items,
description: $('meta[property="og:description"]').attr('content'),

View File

@ -12,7 +12,7 @@ import { parseDate } from '@/utils/parse-date';
export const handler = async (ctx: Context): Promise<Data> => {
const { category = 'newly' } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const baseUrl = 'https://www.199it.com';
const targetUrl: string = new URL(category, baseUrl).href;

View File

@ -9,7 +9,7 @@ import { parseDate } from '@/utils/parse-date';
import timezone from '@/utils/timezone';
import { isValidHost } from '@/utils/valid-host';
const setCookie = function (cookieName, cookieValue, seconds, path, domain, secure) {
const setCookie = function (cookieName, cookieValue, seconds, path, domain, secure?) {
let expires = null;
if (seconds !== -1) {
expires = new Date();

View File

@ -10,7 +10,7 @@ const rootUrl = 'https://www.1lou.me';
export const handler = async (ctx) => {
const { params } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 50;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 50;
const queryString = Object.entries(ctx.req.query())
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)

View File

@ -7,7 +7,7 @@ import got from '@/utils/got';
export const handler = async (ctx) => {
const { category = 'latest/awarded' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const rootUrl = 'https://1x.com';
const currentUrl = new URL(`gallery/${category}`, rootUrl).href;

View File

@ -43,7 +43,7 @@ const processMenu = (data: any[]) => {
export const handler = async (ctx: Context): Promise<Data> => {
const { name = '热点' } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const domain = 'm.21jingji.com';
const baseUrl = `https://${domain}`;

View File

@ -64,7 +64,7 @@ const getProperty = (object, key) => {
async function handler(ctx) {
const category = ctx.req.param('category') ?? '24';
if (!categories[category]) {
if (!Object.hasOwn(categories, category)) {
throw new InvalidParameterError('This category does not exist. Please refer to the documentation for the correct usage.');
}

View File

@ -98,7 +98,7 @@ async function handler(ctx: Context): Promise<Data> {
description:
renderToString(
<ThreeKnsDescription
cover={$item.find('.entry-media img').attr('src')?.trim().replace('.', baseUrl)}
cover={$item.find('.entry-media img').attr('src')?.trim().replace('.', () => baseUrl)}
title={title}
tid={$item.find('.jb-chakan').text().trim()}
category={category}
@ -114,7 +114,7 @@ async function handler(ctx: Context): Promise<Data> {
return {
title: $('title').text(),
link: currentUrl.toString(),
link: currentUrl.href,
allowEmpty: true,
item: items,
};

View File

@ -9,7 +9,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx) => {
const { category = '' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 18;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 18;
const domain = '423down.com';
const rootUrl = `https://www.${domain}`;

View File

@ -37,9 +37,8 @@ async function handler(ctx) {
const categoryUrl = `${SUB_URL}pages/${category}/`;
const slug = category === 'album' ? 'photo' : category;
const {
data: [{ id: categoryId }],
} = await got(`${SUB_URL}wp-json/wp/v2/categories?slug=${slug}`);
const { data } = await got(`${SUB_URL}wp-json/wp/v2/categories?slug=${slug}`);
const categoryId = data[0].id;
const { data: posts } = await got(`${SUB_URL}wp-json/wp/v2/posts?categories=${categoryId}&per_page=${limit}`);
return {

View File

@ -36,9 +36,8 @@ async function handler(ctx) {
const category = ctx.req.param('category');
const categoryUrl = `${SUB_URL}category/${category}/`;
const {
data: [{ id: categoryId }],
} = await got(`${SUB_URL}wp-json/wp/v2/categories?slug=${category}`);
const { data } = await got(`${SUB_URL}wp-json/wp/v2/categories?slug=${category}`);
const categoryId = data[0].id;
const { data: posts } = await got(`${SUB_URL}wp-json/wp/v2/posts?categories=${categoryId}&per_page=${limit}`);
return {

View File

@ -40,7 +40,8 @@ function getPeriodConfig(period) {
range: 'last7days',
title: `${SUB_NAME_PREFIX} - Top views in 7 days`,
};
} else if (period === '30') {
}
if (period === '30') {
return {
url: `${SUB_URL}hot-of-month/`,
range: 'last30days',

View File

@ -36,9 +36,8 @@ async function handler(ctx) {
const tag = ctx.req.param('tag');
const tagUrl = `${SUB_URL}tag/${tag}/`;
const {
data: [{ id: tagId }],
} = await got(`${SUB_URL}wp-json/wp/v2/tags?slug=${tag}`);
const { data } = await got(`${SUB_URL}wp-json/wp/v2/tags?slug=${tag}`);
const tagId = data[0].id;
const { data: posts } = await got(`${SUB_URL}wp-json/wp/v2/posts?tags=${tagId}&per_page=${limit}`);
return {

View File

@ -65,7 +65,7 @@ async function handler(ctx) {
const timestamp = Date.now();
const params = {
page: 1,
page_size: ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 50,
page_size: ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 50,
limit_time: 0,
name_en: '',
};

View File

@ -16,6 +16,6 @@ export const getToken = () =>
export const sign = (requestPath: string, payload: Record<string, any> = {}, timestamp: number, token: string) => {
payload.timestamp = timestamp;
payload.token = token;
const sortedParams = Object.keys(payload).toSorted();
const sortedParams = Object.keys(payload).toSorted((a, b) => a.localeCompare(b));
return md5(md5(requestPath) + md5(sortedParams + md5(token) + timestamp));
};

View File

@ -30,7 +30,7 @@ export const route: Route = {
async function handler(ctx) {
const { category = '1_1' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const currentUrl = new URL(`class/${category}.html`, rootUrl).href;

View File

@ -26,7 +26,7 @@ export const route: Route = {
async function handler(ctx) {
const { category = 'weekvisit' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const currentUrl = new URL(`top/${category.split(/_/, 1)[0]}_1.html`, rootUrl).href;

View File

@ -121,7 +121,7 @@ const renderDescription = ({ images, details }: { images?: Array<{ src?: string;
{details.map((detail, index) => (
<tr key={`${detail.label}-${index}`}>
<th>{detail.label}</th>
<td>{detail.value?.href && detail.value?.text ? <a href={detail.value.href}>{detail.value.text}</a> : detail.value}</td>
<td>{detail.value?.href && detail.value.text ? <a href={detail.value.href}>{detail.value.text}</a> : detail.value}</td>
</tr>
))}
</tbody>

View File

@ -86,14 +86,17 @@ const decrypt = (txt: string, articleid: string, chapterid: string, decryptionMa
const lineMap = {};
const articleKey = Number(articleid) + 3_061_711;
const chapterKey = Number(chapterid) + 3_421_001;
for (const key of Object.keys(decryptionMap)) {
lineMap[(Number(key) ^ chapterKey) - articleKey] = (Number(decryptionMap[key]) ^ chapterKey) - articleKey;
for (const [key, value] of Object.entries(decryptionMap)) {
lineMap[(Number(key) ^ chapterKey) - articleKey] = (Number(value) ^ chapterKey) - articleKey;
}
return txt
.replaceAll(/\u2003|\n/g, '')
.split('<br><br>')
.flatMap((line, index, array) => (lineMap[index] ? array[lineMap[index]] : line).split('<br>'))
.flatMap((line, index, array) => {
const mapped = lineMap[index];
return (mapped ? array[mapped] : line).split('<br>');
})
.slice(1, -2)
.join('<br><br>');
};

View File

@ -12,7 +12,7 @@ import { parseDate } from '@/utils/parse-date';
export const handler = async (ctx: Context): Promise<Data> => {
const { category = 'dy' } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '25', 10);
const limit = Number(ctx.req.query('limit') ?? '25');
const encoding = 'gb2312';

View File

@ -10,7 +10,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx) => {
const { category = 'news' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 10;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 10;
const rootUrl = 'https://www.78dm.net';
const currentUrl = new URL(category.includes('/') ? `${category}.html` : category, rootUrl).href;

View File

@ -8,7 +8,7 @@ import timezone from '@/utils/timezone';
export const handler = async (ctx) => {
const { category = 'sy/gzdt_210283' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const rootUrl = 'https://81rc.81.cn';
const currentUrl = new URL(category?.endsWith('/') ? `${category}/` : category, rootUrl).href;

View File

@ -86,7 +86,7 @@ export const route: Route = {
async function handler(ctx) {
const { id = '751' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const rootUrl = 'https://www.8264.com';
const currentUrl = new URL(`list/${id}`, rootUrl).href;

View File

@ -24,7 +24,7 @@ export const route: Route = {
};
async function handler(ctx) {
const limit = Number.parseInt(ctx.req.query('limit') ?? 10, 10);
const limit = Number(ctx.req.query('limit') ?? 10);
const { cat = '8kasianidol' } = ctx.req.param();
const categoryInfo = await getCategoryInfo(cat);
const items = await getPosts(limit, { categories: categoryInfo.id });

View File

@ -28,7 +28,7 @@ export const route: Route = {
};
async function handler(ctx) {
const limit = Number.parseInt(ctx.req.query('limit') ?? 10, 10);
const limit = Number(ctx.req.query('limit') ?? 10);
const items = await getPosts(limit);
return {
title: `${SUB_NAME_PREFIX}-最新`,

View File

@ -28,13 +28,13 @@ export const route: Route = {
};
async function handler(ctx) {
const limit = Number.parseInt(ctx.req.query('limit') ?? 10, 10);
const limit = Number(ctx.req.query('limit') ?? 10);
const tag = ctx.req.param('tag');
const tagInfo = await getTagInfo(tag);
const items = await getPosts(limit, { tags: tagInfo.id });
return {
title: `${tagInfo.title}`,
title: tagInfo.title,
link: `${SUB_URL}/tag/${tag}/`,
item: items,
};

View File

@ -49,8 +49,10 @@ async function handler(ctx) {
const feed = await parser.parseURL(link);
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10;
const items = await Promise.all(
feed.items.splice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10).map((item) =>
feed.items.splice(0, limit).map((item) =>
cache.tryGet(item.link, async () => {
const response = await got({
method: 'get',

View File

@ -20,11 +20,12 @@ const ProcessFeed = (data) => {
content.find('div.ad-disclaimer-container').remove();
content.find('div').each((i, e) => {
if ($(e)[0].attribs.class) {
const classes = $(e)[0].attribs.class;
if (/\w{10}\s\w{10}/.test(classes)) {
$(e).remove();
}
if (!$(e)[0].attribs.class) {
return;
}
const classes = $(e)[0].attribs.class;
if (/\w{10}\s\w{10}/.test(classes)) {
$(e).remove();
}
});

View File

@ -10,7 +10,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx) => {
const { category = 'news/All' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 15;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 15;
const rootUrl = 'http://www.a9vg.com';
const currentUrl = new URL(`list/${category}`, rootUrl).href;

View File

@ -9,7 +9,7 @@ import { parseDate } from '@/utils/parse-date';
export const handler = async (ctx: Context): Promise<Data> => {
const { category } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '100', 10);
const limit = Number(ctx.req.query('limit') ?? '100');
const apiSlug = 'wp-json/wp/v2';
const baseUrl = 'https://60s.aa1.cn';

View File

@ -34,7 +34,7 @@ The supported channels are all listed in the table below. For other channels, pl
async function handler(ctx) {
const { category = 'news/justin' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const rootUrl = 'https://www.abc.net.au';
const apiUrl = new URL('news-web/api/loader/channelrefetch', rootUrl).href;
@ -131,7 +131,7 @@ async function handler(ctx) {
if (enclosureMatches) {
const enclosureMatch = enclosureMatches
.map((e) => e.match(new RegExp(enclosurePattern)))
.toSorted((a, b) => Number.parseInt(a[2], 10) - Number.parseInt(b[2], 10))
.toSorted((a, b) => Number(a[2]) - Number(b[2]))
.pop();
item.enclosure_url = enclosureMatch[3];

View File

@ -6,7 +6,10 @@ const rootUrl = 'https://www.abmedia.io';
const cateAPIUrl = `${rootUrl}/wp-json/wp/v2/categories`;
const postsAPIUrl = `${rootUrl}/wp-json/wp/v2/posts`;
const getCategoryId = (category) => got.get(`${cateAPIUrl}?slug=${category}`).then((res) => res.data[0].id);
const getCategoryId = async (category) => {
const res = await got.get(`${cateAPIUrl}?slug=${category}`);
return res.data[0].id;
};
export const route: Route = {
path: '/:category?',

View File

@ -9,7 +9,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx) => {
const { category = 'latest/news' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const rootUrl = 'https://www.accessbriefing.com';
const currentUrl = new URL(category, rootUrl).href;

View File

@ -45,7 +45,7 @@ export const route: Route = {
parameters: {
categoryId: {
description: '分区 ID',
options: Object.keys(categoryMap).map((id) => ({ value: id, label: categoryMap[id].title })),
options: Object.entries(categoryMap).map(([id, value]) => ({ value: id, label: value.title })),
},
sortType: {
description: '排序',
@ -94,7 +94,7 @@ export const route: Route = {
async function handler(ctx) {
const { categoryId, sortType = 'createTime', timeRange = 'all' } = ctx.req.param();
if (!categoryMap[categoryId]) {
if (!Object.hasOwn(categoryMap, categoryId)) {
throw new InvalidParameterError(`Invalid category Id: ${categoryId}`);
}
if (!sortTypeEnum.has(sortType)) {

View File

@ -40,6 +40,7 @@ async function handler(ctx) {
const newsIndexJsonText = $('script:contains("window.__INITIAL_STATE__")').text().replaceAll('window.__INITIAL_STATE__=', '');
const newsIndexJson = JSON.parse(newsIndexJsonText);
const limit = ctx.req.query('limit');
const newsListResponse = await ofetch(`${rootUrl}/rajax/news_h.jsp?cmd=getWafNotCk_getList`, {
method: 'POST',
headers: {
@ -47,7 +48,7 @@ async function handler(ctx) {
},
body: new URLSearchParams({
page: '1',
pageSize: String(ctx.req.query('limit') ?? 20),
pageSize: String(limit ?? 20),
fromMid: newsIndexJson.modules.module366.id,
idList: `[${newsIndexJson.modules.module366.prop3}]`,
sortKey: newsIndexJson.modules.module366.blob0.sortKey,

View File

@ -26,7 +26,7 @@ export const route: Route = {
async function handler(ctx) {
const { id = '1', name = '重要通知' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const rootUrl = 'http://www.acpaa.cn';
const currentUrl = new URL(`article/taglist.jhtml?tagIds=${id}&tagname=${name}`, rootUrl).href;

View File

@ -13,7 +13,7 @@ import timezone from '@/utils/timezone';
import { renderDescription } from './templates/description';
export const handler = async (ctx: Context): Promise<Data> => {
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '24', 10);
const limit = Number(ctx.req.query('limit') ?? '24');
const baseUrl = 'https://www.adquan.com';
const targetUrl: string = new URL('case_library/index', baseUrl).href;

View File

@ -13,7 +13,7 @@ import timezone from '@/utils/timezone';
import { renderDescription } from './templates/description';
export const handler = async (ctx: Context): Promise<Data> => {
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const baseUrl = 'https://www.adquan.com';
const targetUrl: string = baseUrl;

View File

@ -10,7 +10,7 @@ import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';
export const handler = async (ctx: Context): Promise<Data> => {
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '5', 10);
const limit = Number(ctx.req.query('limit') ?? '5');
const baseUrl = 'https://aflcio.org';
const targetUrl: string = new URL('blog', baseUrl).href;

View File

@ -57,10 +57,12 @@ async function handler() {
const content = load(detailResponse.data);
content('img').each((_, ele) => {
if (ele.attribs['data-original']) {
ele.attribs.src = ele.attribs['data-original'];
delete ele.attribs['data-original'];
if (!ele.attribs['data-original']) {
return;
}
ele.attribs.src = ele.attribs['data-original'];
delete ele.attribs['data-original'];
});
content('.video_detail_collect').remove();

View File

@ -10,7 +10,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx) => {
const { category = 'zx/zxfb/' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 10;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 10;
const rootUrl = 'http://www.agri.cn';
const currentUrl = new URL(category.endsWith('/') ? category : `${category}/`, rootUrl).href;

View File

@ -21,8 +21,8 @@ function parseDateString(dateStr: string, ctx: DateContext): Date | undefined {
return undefined;
}
const month = Number.parseInt(match[1], 10);
const day = Number.parseInt(match[2], 10);
const month = Number(match[1]);
const day = Number(match[2]);
// 检测跨年:如果当前日期比上一个日期大,说明跨年了
if (ctx.prevMonth > 0 && (month > ctx.prevMonth || (month === ctx.prevMonth && day > ctx.prevDay))) {

View File

@ -14,7 +14,7 @@ export const route: Route = {
maintainers: ['3tuuu'],
handler: async (ctx) => {
// 每页数量限制
const limit = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
// 用项目中已有的获取页面方法,获取页面以及 Token
const currentUrl = new URL('discover', rootUrl).href;
const currentHtml = await ofetch(currentUrl);

View File

@ -10,7 +10,7 @@ export const handler = async (ctx) => {
const [pid, sid] = id?.split(/-/) ?? [undefined, undefined];
const limit = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const currentUrl = new URL(`discover${id ? `/${id}` : ''}`, rootUrl).href;

View File

@ -13,7 +13,7 @@ export const route: Route = {
maintainers: ['zreo0'],
handler: async (ctx) => {
// 每页数量限制
const limit = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
// 用项目中已有的获取页面方法,获取页面以及 Token
const currentUrl = new URL('discover', rootUrl).href;
const currentHtml = await ofetch(currentUrl);

View File

@ -8,7 +8,7 @@ import { buildApiUrl, processItems, rootUrl } from './util';
export const handler = async (ctx) => {
const { id, filter = 'id' } = ctx.req.param();
const limit = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const currentUrl = new URL(id ? `topic/${id}` : 'discover', rootUrl).href;

View File

@ -26,7 +26,7 @@ export const route: Route = {
};
async function handler(ctx) {
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 5;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 5;
const items = await fetchContentItems([109], limit);
return {

View File

@ -28,7 +28,7 @@ export const route: Route = {
};
async function handler(ctx) {
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 5;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 5;
const streamIds = [109, 416, 438, 529, 721, 834, 835];
const items = await fetchContentItems(streamIds, limit);

View File

@ -28,7 +28,7 @@ export const route: Route = {
async function handler(ctx) {
const id = ctx.req.param('id');
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const currentUrl = new URL(`/data/search?column=${id}`, rootUrl).href;

View File

@ -29,7 +29,7 @@ export const route: Route = {
async function handler(ctx) {
const { id, type = '' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const currentUrl = new URL(`thinktank/${id}.html`, rootUrl).href;

View File

@ -19,7 +19,7 @@ export const route: Route = {
async function handler(ctx) {
const { id = '1', period = '1' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const currentUrl = new URL(`toplist${id ? `?id=${id}${id === '1' ? `&period=${period}` : ''}` : ''}`, rootUrl).href;

View File

@ -29,8 +29,8 @@ const ProcessFeed = (limit, tryGet, items) =>
.toArray()
.map((c) => content(c).text());
item.pubDate = timezone(parseDate(content('div.info').text().split('时间:').pop()), +8);
item.upvotes = content('span.like-num').text() ? Number.parseInt(content('span.like-num').text(), 10) : 0;
item.comments = commentMatches ? Number.parseInt(commentMatches[1], 10) : 0;
item.upvotes = content('span.like-num').text() ? Number(content('span.like-num').text()) : 0;
item.comments = commentMatches ? Number(commentMatches[1]) : 0;
return item;
})

View File

@ -31,7 +31,7 @@ export const route: Route = {
async function handler(ctx) {
const id = ctx.req.param('id');
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 30;
const currentUrl = new URL(`zhuanti/${id}.html`, rootUrl).href;

View File

@ -14,7 +14,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx: Context): Promise<Data> => {
const { category = 'new' } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const rootUrl = 'https://www.ali213.net';
const targetUrl: string = new URL(`news/${category.endsWith('/') ? category : `${category}/`}`, rootUrl).href;

View File

@ -13,7 +13,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx: Context): Promise<Data> => {
const { category } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '1', 10);
const limit = Number(ctx.req.query('limit') ?? '1');
const rootUrl = 'https://www.ali213.net';
const apiRootUrl = 'https://mp.ali213.net';

View File

@ -36,7 +36,7 @@ export const route: Route = {
async function handler(ctx) {
const { category, game } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 10;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 10;
let url = `${baseUrl}/information`;
if (category) {

View File

@ -71,8 +71,9 @@ async function handler(ctx) {
};
});
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50;
items = await Promise.all(
items.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50).map((item) =>
items.slice(0, limit).map((item) =>
cache.tryGet(item.link, async () => {
const detailResponse = await ofetch(item.link);

View File

@ -83,7 +83,7 @@ async function handler(ctx) {
.filter(Boolean);
const uniqueItems: DataItem[] = [];
for (const item of items) {
if (!uniqueItems.some((uniqueItem) => uniqueItem.link === item?.link)) {
if (uniqueItems.every((uniqueItem) => uniqueItem.link !== item?.link)) {
uniqueItems.push(item!);
}
}

View File

@ -13,7 +13,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx: Context): Promise<Data> => {
const { device, sort, searchParams } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const baseUrl = 'https://amazfitwatchfaces.com';
const targetUrl: string = new URL(`${device}/${sort}${searchParams ? `?${searchParams}` : ''}`, baseUrl).href;

View File

@ -26,7 +26,7 @@ async function handler(ctx) {
const link = `${baseUrl}/engineering`;
const response = await ofetch(link);
const $ = load(response);
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 20;
const list: DataItem[] = $('a[class*="cardLink"]')
.toArray()

View File

@ -25,7 +25,7 @@ async function handler(ctx) {
const link = 'https://www.anthropic.com/news';
const response = await ofetch(link);
const $ = load(response);
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 10;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 10;
const list: DataItem[] = $('[class^="PublicationList-module-scss-module__"][class$="__list"] a')
.toArray()

View File

@ -35,9 +35,8 @@ async function handler() {
const text = $e.text();
const match = regexp.exec(text);
if (match) {
let data;
try {
data = JSON.parse(match[1]);
const data = JSON.parse(match[1]);
if (Array.isArray(data) && data.length === 2 && data[0] === 1) {
textList.push(data[1]);
}

View File

@ -9,7 +9,7 @@ import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';
export const handler = async (ctx: Context): Promise<Data> => {
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const baseUrl = 'https://anytxt.net';
const targetUrl: string = new URL('download/', baseUrl).href;

View File

@ -72,20 +72,20 @@ async function handler(ctx) {
description: e.description,
guid: e.id,
};
} else if (e.__typename === 'VideoPlaylistItem') {
}
if (e.__typename === 'VideoPlaylistItem') {
return {
title: e.title,
link: e.url,
description: e.description,
guid: e.contentId,
};
} else {
return;
}
return;
})
.filter(Boolean)
.toSorted((a, b) => b.pubDate - a.pubDate)
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20);
.slice(0, ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 20);
const items = ctx.req.query('fulltext') === 'true' ? await pMap(list, (item) => fetchArticle(item), { concurrency: 10 }) : list;

View File

@ -84,7 +84,7 @@ async function handler(ctx) {
})
.filter((e) => Boolean(e.link) && !new URL(e.link).pathname.split('/').includes('hub'))
.toSorted((a, b) => (a.pubDate && b.pubDate ? b.pubDate - a.pubDate : b.lastmod - a.lastmod))
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20);
.slice(0, ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 20);
const items = ctx.req.query('fulltext') === 'true' ? await pMap(list, (item) => fetchArticle(item), { concurrency: 20 }) : list;

View File

@ -5,7 +5,7 @@ import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';
export function removeDuplicateByKey(items, key: string) {
return [...new Map(items.map((x) => [x[key], x])).values()];
return new Map(items.map((x) => [x[key], x])).values().toArray();
}
export function fetchArticle(item) {
@ -25,9 +25,8 @@ export function fetchArticle(item) {
author: gtmParsed.author,
...item,
};
} else {
return item;
}
return item;
}
const rawLdjson = JSON.parse($('#link-ld-json').text());
let ldjson;
@ -47,21 +46,20 @@ export function fetchArticle(item) {
guid: $("meta[name='brightspot.contentId']").attr('content'),
author: ldjson.author,
};
} else {
// Live
ldjson = rawLdjson;
const url = new URL(item.link);
const description = url.hash ? $(url.hash).parent().find('.LiveBlogPost-body').html() : ldjson.description;
const pubDate = url.hash ? parseDate(Number.parseInt($(url.hash).parent().attr('data-posted-date-timestamp'), 10)) : parseDate(ldjson.coverageStartTime);
return {
...item,
category: ldjson.keywords,
pubDate,
description,
guid: $("meta[name='brightspot.contentId']").attr('content'),
};
}
// Live
ldjson = rawLdjson;
const url = new URL(item.link);
const description = url.hash ? $(url.hash).parent().find('.LiveBlogPost-body').html() : ldjson.description;
const pubDate = url.hash ? parseDate(Number($(url.hash).parent().attr('data-posted-date-timestamp'))) : parseDate(ldjson.coverageStartTime);
return {
...item,
category: ldjson.keywords,
pubDate,
description,
guid: $("meta[name='brightspot.contentId']").attr('content'),
};
});
}

View File

@ -10,7 +10,7 @@ import { baseUrl, fetchItems } from './util';
export const handler = async (ctx: Context): Promise<Data> => {
const { category = 'highlights', country = 'us' } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '100', 10);
const limit = Number(ctx.req.query('limit') ?? '100');
const targetUrl: string = new URL(category.endsWith('/') ? category : `${category}/`, baseUrl).href;

View File

@ -10,7 +10,7 @@ import { baseUrl, fetchItems } from './util';
export const handler = async (ctx: Context): Promise<Data> => {
const { time = '24h', country = 'us' } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const targetUrl: string = new URL('mostwanted/', baseUrl).href;

View File

@ -79,7 +79,7 @@ async function handler(ctx) {
}
platform = undefined;
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 100;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 100;
const rootUrl = 'https://apps.apple.com';
const currentUrl = new URL(`${country}/app/${id}`, rootUrl).href;
@ -129,8 +129,7 @@ async function handler(ctx) {
image = platformAttribute.iconArtwork?.url?.replace('{w}x{h}{c}.{f}', '3000x3000bb.webp');
} else {
title = appName;
for (const pid of Object.keys(platformAttributes)) {
const platformAttribute = platformAttributes[pid];
for (const [pid, platformAttribute] of Object.entries(platformAttributes)) {
items = [
...items,
...platformAttribute.versionHistory.map((v) => ({

View File

@ -54,7 +54,7 @@ const fetchArticle = (item: Item & { link: string }) =>
});
async function handler(ctx) {
const limit = Math.max(Number.parseInt(ctx.req.query('limit') ?? '', 10) || defaultLimit, 1);
const limit = Math.max(Number(ctx.req.query('limit') ?? '') || defaultLimit, 1);
const feedResponse = await ofetch(feedUrl, {
parseResponse: (text) => text,
});

View File

@ -13,7 +13,7 @@ import { renderDescription } from './templates/security-releases';
export const handler = async (ctx: Context): Promise<Data> => {
const { language = 'en-us' } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const baseUrl = 'https://support.apple.com';
const targetUrl: string = new URL(`${language}/100100`, baseUrl).href;

View File

@ -13,7 +13,7 @@ export const route: Route = {
};
async function handler(ctx) {
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 35;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 35;
const rootUrl = 'https://www.aqara.cn';
const currentUrl = new URL('news', rootUrl).href;

View File

@ -14,7 +14,7 @@ export const route: Route = {
};
async function handler(ctx) {
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 50;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 50;
const rootUrl = 'https://aqara.com';
const apiSlug = 'wp-json/wp/v2';

View File

@ -13,7 +13,7 @@ import { renderDescription } from './templates/description';
export const handler = async (ctx: Context): Promise<Data> => {
const { category = 'all' } = ctx.req.param();
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '10', 10);
const limit = Number(ctx.req.query('limit') ?? '10');
const baseUrl = 'https://asiafruitchina.net';
const targetUrl: string = new URL(`categories?gspx=${category}`, baseUrl).href;

View File

@ -12,7 +12,7 @@ import { parseDate } from '@/utils/parse-date';
import { renderDescription } from './templates/description';
export const handler = async (ctx: Context): Promise<Data> => {
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
const limit = Number(ctx.req.query('limit') ?? '30');
const baseUrl = 'https://asiafruitchina.net';
const targetUrl: string = new URL('category/news', baseUrl).href;

View File

@ -26,7 +26,7 @@ export const route: Route = {
async function handler(ctx) {
const category = ctx.req.param('category');
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 24;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 24;
const rootUrl = 'https://asiantolick.com';
const apiUrl = new URL('ajax/buscar_posts.php', rootUrl).href;

View File

@ -22,7 +22,7 @@ async function handler(ctx) {
const baseUrl = 'https://www.atptour.com';
const favIcon = `${baseUrl}/assets/atptour/assets/favicon.ico`;
const { lang = 'en' } = ctx.req.param();
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 15;
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 15;
const link = `${baseUrl}/${lang}/-/tour/news/latest-filtered-results/0/${limit}`;
const { data } = await got(link, {

View File

@ -31,7 +31,7 @@ const renderDescription = ({ images, description }: { images?: DescriptionImage[
);
export const handler = async (ctx: Context): Promise<Data> => {
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '50', 10);
const limit = Number(ctx.req.query('limit') ?? '50');
const baseUrl = 'https://augmentcode.com';
const targetUrl: string = new URL('blog', baseUrl).href;

Some files were not shown because too many files have changed in this diff Show More