chore: revive remark formatter

refs: #14040
This commit is contained in:
Tony 2026-05-08 04:40:49 +08:00
parent 78068da475
commit 70cd080406
6 changed files with 523 additions and 2 deletions

View File

@ -21,6 +21,7 @@ jobs:
node-version: lts/*
cache: 'pnpm'
- run: pnpm i
- run: npm run format:description
- run: npm run format
- name: Commit files
run: |

View File

@ -18,7 +18,7 @@ jobs:
name: npm publish
if: github.repository == 'DIYgod/RSSHub'
runs-on: ubuntu-slim
timeout-minutes: 5
timeout-minutes: 10
env:
HUSKY: 0
steps:

View File

@ -34,7 +34,8 @@ export const route: Route = {
description:
"The English blog on any of Uber's regional sites (e.g., www.uber.com/en-JP/blog) is the same engineering blog provided by this route, so language selection is not supported. This route is not for the public news blog on specific regional sites (e.g., www.uber.com/ja-JP/blog).",
zh: {
description: 'uber的任何区域站点的英文blog例如www.uber.com/en-JP/blog都是相同的内容正是本路由提供的engineering blog因此本路由不提供语言选择本路由不是uber在特定区域站点的公开新闻blog例如www.uber.com/ja-JP/blog)',
description:
'uber 的任何区域站点的英文 blog例如 [www.uber.com/en-JP/blog](http://www.uber.com/en-JP/blog))都是相同的内容,正是本路由提供的 engineering blog因此本路由不提供语言选择本路由不是 uber 在特定区域站点的公开新闻 blog例如 [www.uber.com/ja-JP/blog](http://www.uber.com/ja-JP/blog)',
},
};

View File

@ -38,6 +38,7 @@
"eslint": "eslint --cache . --concurrency auto",
"format": "oxlint --type-aware --fix . && oxfmt .",
"format:check": "oxlint --type-aware . && oxfmt . --check",
"format:description": "tsx scripts/workflow/format-description.ts",
"format:staged": "lint-staged",
"lint": "oxlint --type-aware .",
"prepare": "husky || true",
@ -180,6 +181,7 @@
"eslint-plugin-simple-import-sort": "13.0.0",
"eslint-plugin-unicorn": "64.0.0",
"eslint-plugin-yml": "3.3.2",
"fast-string-width": "3.0.2",
"fs-extra": "11.3.5",
"globals": "17.6.0",
"got": "15.0.5",
@ -194,6 +196,9 @@
"oxlint": "1.62.0",
"oxlint-plugin-eslint": "1.62.0",
"oxlint-tsgolint": "0.22.1",
"remark": "15.0.1",
"remark-gfm": "4.0.1",
"remark-pangu": "2.2.0",
"remark-parse": "11.0.0",
"tsdown": "0.21.10",
"typescript": "5.9.3",

View File

@ -398,6 +398,9 @@ importers:
eslint-plugin-yml:
specifier: 3.3.2
version: 3.3.2(eslint@10.3.0(jiti@2.6.1))
fast-string-width:
specifier: 3.0.2
version: 3.0.2
fs-extra:
specifier: 11.3.5
version: 11.3.5
@ -440,6 +443,15 @@ importers:
oxlint-tsgolint:
specifier: 0.22.1
version: 0.22.1
remark:
specifier: 15.0.1
version: 15.0.1
remark-gfm:
specifier: 4.0.1
version: 4.0.1
remark-pangu:
specifier: 2.2.0
version: 2.2.0
remark-parse:
specifier: 11.0.0
version: 11.0.0
@ -2810,6 +2822,9 @@ packages:
'@types/triple-beam@1.3.5':
resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==}
'@types/unist@2.0.11':
resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
@ -3268,6 +3283,9 @@ packages:
caseless@0.12.0:
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
chai@6.2.2:
resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
engines: {node: '>=18'}
@ -4582,6 +4600,9 @@ packages:
long@5.3.2:
resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
lowercase-keys@3.0.0:
resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -4635,9 +4656,39 @@ packages:
markdown-table@2.0.0:
resolution: {integrity: sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==}
markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
mdast-util-find-and-replace@3.0.2:
resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==}
mdast-util-from-markdown@2.0.3:
resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==}
mdast-util-gfm-autolink-literal@2.0.1:
resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==}
mdast-util-gfm-footnote@2.1.0:
resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==}
mdast-util-gfm-strikethrough@2.0.0:
resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==}
mdast-util-gfm-table@2.0.0:
resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==}
mdast-util-gfm-task-list-item@2.0.0:
resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==}
mdast-util-gfm@3.1.0:
resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==}
mdast-util-phrasing@4.1.0:
resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
mdast-util-to-markdown@2.1.2:
resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==}
mdast-util-to-string@4.0.0:
resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
@ -4661,6 +4712,27 @@ packages:
micromark-core-commonmark@2.0.3:
resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==}
micromark-extension-gfm-autolink-literal@2.1.0:
resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==}
micromark-extension-gfm-footnote@2.1.0:
resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==}
micromark-extension-gfm-strikethrough@2.1.0:
resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==}
micromark-extension-gfm-table@2.1.1:
resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==}
micromark-extension-gfm-tagfilter@2.0.0:
resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==}
micromark-extension-gfm-task-list-item@2.1.0:
resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==}
micromark-extension-gfm@3.0.0:
resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==}
micromark-factory-destination@2.0.1:
resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==}
@ -5023,6 +5095,10 @@ packages:
pako@2.1.0:
resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
pangu@4.0.7:
resolution: {integrity: sha512-weZKJIwwy5gjt4STGVUH9bix3BGk7wZ2ahtIypwe3e/mllsrIZIvtfLx1dPX56GcpZFOCFKmeqI1qVuB9enRzA==}
hasBin: true
parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@ -5263,9 +5339,22 @@ packages:
resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==}
hasBin: true
remark-gfm@4.0.1:
resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
remark-pangu@2.2.0:
resolution: {integrity: sha512-3h2UiRIbnEQR+IxYPhQ5SMbAZPobIV8ddza8U1hJLsfLranbv/cdFiwnZEgMOJYKmi+9XHLMxrAIipmIsLrzPg==}
engines: {node: '>=10'}
remark-parse@11.0.0:
resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
remark-stringify@11.0.0:
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
remark@15.0.1:
resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==}
repeat-string@1.6.1:
resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==}
engines: {node: '>=0.10'}
@ -5871,9 +5960,27 @@ packages:
unified@11.0.5:
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
unist-util-is@4.1.0:
resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==}
unist-util-is@6.0.1:
resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==}
unist-util-stringify-position@4.0.0:
resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
unist-util-visit-parents@3.1.1:
resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==}
unist-util-visit-parents@6.0.1:
resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
unist-util-visit@2.0.3:
resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==}
unist-util-visit@5.0.0:
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
universal-user-agent@7.0.3:
resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==}
@ -6271,6 +6378,9 @@ packages:
zod@4.4.3:
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
snapshots:
'@actions/core@3.0.1':
@ -8190,6 +8300,8 @@ snapshots:
'@types/triple-beam@1.3.5': {}
'@types/unist@2.0.11': {}
'@types/unist@3.0.3': {}
'@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.3.0(jiti@2.6.1))(typescript@5.9.3)':
@ -8634,6 +8746,8 @@ snapshots:
caseless@0.12.0: {}
ccount@2.0.1: {}
chai@6.2.2: {}
chalk@5.6.2: {}
@ -10136,6 +10250,8 @@ snapshots:
long@5.3.2: {}
longest-streak@3.1.0: {}
lowercase-keys@3.0.0: {}
lowercase-keys@4.0.1: {}
@ -10196,6 +10312,15 @@ snapshots:
dependencies:
repeat-string: 1.6.1
markdown-table@3.0.4: {}
mdast-util-find-and-replace@3.0.2:
dependencies:
'@types/mdast': 4.0.4
escape-string-regexp: 5.0.0
unist-util-is: 6.0.1
unist-util-visit-parents: 6.0.1
mdast-util-from-markdown@2.0.3:
dependencies:
'@types/mdast': 4.0.4
@ -10213,6 +10338,80 @@ snapshots:
transitivePeerDependencies:
- supports-color
mdast-util-gfm-autolink-literal@2.0.1:
dependencies:
'@types/mdast': 4.0.4
ccount: 2.0.1
devlop: 1.1.0
mdast-util-find-and-replace: 3.0.2
micromark-util-character: 2.1.1
mdast-util-gfm-footnote@2.1.0:
dependencies:
'@types/mdast': 4.0.4
devlop: 1.1.0
mdast-util-from-markdown: 2.0.3
mdast-util-to-markdown: 2.1.2
micromark-util-normalize-identifier: 2.0.1
transitivePeerDependencies:
- supports-color
mdast-util-gfm-strikethrough@2.0.0:
dependencies:
'@types/mdast': 4.0.4
mdast-util-from-markdown: 2.0.3
mdast-util-to-markdown: 2.1.2
transitivePeerDependencies:
- supports-color
mdast-util-gfm-table@2.0.0:
dependencies:
'@types/mdast': 4.0.4
devlop: 1.1.0
markdown-table: 3.0.4
mdast-util-from-markdown: 2.0.3
mdast-util-to-markdown: 2.1.2
transitivePeerDependencies:
- supports-color
mdast-util-gfm-task-list-item@2.0.0:
dependencies:
'@types/mdast': 4.0.4
devlop: 1.1.0
mdast-util-from-markdown: 2.0.3
mdast-util-to-markdown: 2.1.2
transitivePeerDependencies:
- supports-color
mdast-util-gfm@3.1.0:
dependencies:
mdast-util-from-markdown: 2.0.3
mdast-util-gfm-autolink-literal: 2.0.1
mdast-util-gfm-footnote: 2.1.0
mdast-util-gfm-strikethrough: 2.0.0
mdast-util-gfm-table: 2.0.0
mdast-util-gfm-task-list-item: 2.0.0
mdast-util-to-markdown: 2.1.2
transitivePeerDependencies:
- supports-color
mdast-util-phrasing@4.1.0:
dependencies:
'@types/mdast': 4.0.4
unist-util-is: 6.0.1
mdast-util-to-markdown@2.1.2:
dependencies:
'@types/mdast': 4.0.4
'@types/unist': 3.0.3
longest-streak: 3.1.0
mdast-util-phrasing: 4.1.0
mdast-util-to-string: 4.0.0
micromark-util-classify-character: 2.0.1
micromark-util-decode-string: 2.0.1
unist-util-visit: 5.0.0
zwitch: 2.0.4
mdast-util-to-string@4.0.0:
dependencies:
'@types/mdast': 4.0.4
@ -10255,6 +10454,64 @@ snapshots:
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
micromark-extension-gfm-autolink-literal@2.1.0:
dependencies:
micromark-util-character: 2.1.1
micromark-util-sanitize-uri: 2.0.1
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
micromark-extension-gfm-footnote@2.1.0:
dependencies:
devlop: 1.1.0
micromark-core-commonmark: 2.0.3
micromark-factory-space: 2.0.1
micromark-util-character: 2.1.1
micromark-util-normalize-identifier: 2.0.1
micromark-util-sanitize-uri: 2.0.1
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
micromark-extension-gfm-strikethrough@2.1.0:
dependencies:
devlop: 1.1.0
micromark-util-chunked: 2.0.1
micromark-util-classify-character: 2.0.1
micromark-util-resolve-all: 2.0.1
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
micromark-extension-gfm-table@2.1.1:
dependencies:
devlop: 1.1.0
micromark-factory-space: 2.0.1
micromark-util-character: 2.1.1
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
micromark-extension-gfm-tagfilter@2.0.0:
dependencies:
micromark-util-types: 2.0.2
micromark-extension-gfm-task-list-item@2.1.0:
dependencies:
devlop: 1.1.0
micromark-factory-space: 2.0.1
micromark-util-character: 2.1.1
micromark-util-symbol: 2.0.1
micromark-util-types: 2.0.2
micromark-extension-gfm@3.0.0:
dependencies:
micromark-extension-gfm-autolink-literal: 2.1.0
micromark-extension-gfm-footnote: 2.1.0
micromark-extension-gfm-strikethrough: 2.1.0
micromark-extension-gfm-table: 2.1.1
micromark-extension-gfm-tagfilter: 2.0.0
micromark-extension-gfm-task-list-item: 2.1.0
micromark-util-combine-extensions: 2.0.1
micromark-util-types: 2.0.2
micromark-factory-destination@2.0.1:
dependencies:
micromark-util-character: 2.1.1
@ -10700,6 +10957,8 @@ snapshots:
pako@2.1.0: {}
pangu@4.0.7: {}
parent-module@1.0.1:
dependencies:
callsites: 3.1.0
@ -10959,6 +11218,23 @@ snapshots:
dependencies:
jsesc: 3.1.0
remark-gfm@4.0.1:
dependencies:
'@types/mdast': 4.0.4
mdast-util-gfm: 3.1.0
micromark-extension-gfm: 3.0.0
remark-parse: 11.0.0
remark-stringify: 11.0.0
unified: 11.0.5
transitivePeerDependencies:
- supports-color
remark-pangu@2.2.0:
dependencies:
pangu: 4.0.7
unist-util-is: 4.1.0
unist-util-visit: 2.0.3
remark-parse@11.0.0:
dependencies:
'@types/mdast': 4.0.4
@ -10968,6 +11244,21 @@ snapshots:
transitivePeerDependencies:
- supports-color
remark-stringify@11.0.0:
dependencies:
'@types/mdast': 4.0.4
mdast-util-to-markdown: 2.1.2
unified: 11.0.5
remark@15.0.1:
dependencies:
'@types/mdast': 4.0.4
remark-parse: 11.0.0
remark-stringify: 11.0.0
unified: 11.0.5
transitivePeerDependencies:
- supports-color
repeat-string@1.6.1: {}
request-promise-core@1.1.4(request@2.88.2):
@ -11610,10 +11901,38 @@ snapshots:
trough: 2.2.0
vfile: 6.0.3
unist-util-is@4.1.0: {}
unist-util-is@6.0.1:
dependencies:
'@types/unist': 3.0.3
unist-util-stringify-position@4.0.0:
dependencies:
'@types/unist': 3.0.3
unist-util-visit-parents@3.1.1:
dependencies:
'@types/unist': 2.0.11
unist-util-is: 4.1.0
unist-util-visit-parents@6.0.1:
dependencies:
'@types/unist': 3.0.3
unist-util-is: 6.0.1
unist-util-visit@2.0.3:
dependencies:
'@types/unist': 2.0.11
unist-util-is: 4.1.0
unist-util-visit-parents: 3.1.1
unist-util-visit@5.0.0:
dependencies:
'@types/unist': 3.0.3
unist-util-is: 6.0.1
unist-util-visit-parents: 6.0.1
universal-user-agent@7.0.3: {}
universalify@0.2.0: {}
@ -11998,3 +12317,5 @@ snapshots:
meriyah: 6.1.4
zod@4.4.3: {}
zwitch@2.0.4: {}

View File

@ -0,0 +1,193 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import stringWidth from 'fast-string-width';
import { remark } from 'remark';
import remarkGfm from 'remark-gfm';
import remarkPangu from 'remark-pangu';
import typescript from 'typescript';
const __dirname = import.meta.dirname;
const routesDir = path.resolve(__dirname, '../../lib/routes');
function remarkDirectiveSpace() {
return (tree: any) => {
walkDirectiveAst(tree);
};
}
function walkDirectiveAst(node: any): void {
if (node.type === 'text' && typeof node.value === 'string') {
node.value = node.value.replaceAll(/^:::([A-Za-z][\w-]*)/gm, '::: $1');
}
if (Array.isArray(node.children)) {
for (const child of node.children) {
walkDirectiveAst(child);
}
}
}
const processor = remark()
.data('settings', {
bullet: '-',
})
.use(remarkDirectiveSpace)
.use(remarkPangu)
.use(remarkGfm, {
stringLength: stringWidth,
});
interface DescriptionEdit {
start: number;
end: number;
raw: string;
}
function getPropertyName(name: typescript.PropertyName): string {
if (typescript.isIdentifier(name) || typescript.isPrivateIdentifier(name) || typescript.isStringLiteral(name) || typescript.isNoSubstitutionTemplateLiteral(name)) {
return name.text;
}
return '';
}
const TARGETS: Record<string, string> = { route: 'Route', namespace: 'Namespace' };
function isTargetTypedDeclaration(decl: typescript.VariableDeclaration): boolean {
if (!typescript.isIdentifier(decl.name)) {
return false;
}
const expectedType = TARGETS[decl.name.text];
if (!expectedType) {
return false;
}
if (decl.type && typescript.isTypeReferenceNode(decl.type)) {
const typeName = decl.type.typeName;
if (typescript.isIdentifier(typeName) && typeName.text === expectedType) {
return true;
}
}
return false;
}
function collectDescriptionEdits(sourceFile: typescript.SourceFile): DescriptionEdit[] {
const edits: DescriptionEdit[] = [];
const visitObject = (obj: typescript.ObjectLiteralExpression) => {
for (const prop of obj.properties) {
if (!typescript.isPropertyAssignment(prop)) {
continue;
}
const name = getPropertyName(prop.name);
if (name === 'description') {
const init = prop.initializer;
if (typescript.isStringLiteral(init) || typescript.isNoSubstitutionTemplateLiteral(init)) {
edits.push({
start: init.getStart(sourceFile),
end: init.getEnd(),
raw: init.text,
});
}
} else if ((name === 'ja' || name === 'zh' || name === 'zh-TW') && typescript.isObjectLiteralExpression(prop.initializer)) {
visitObject(prop.initializer);
}
}
};
for (const stmt of sourceFile.statements) {
if (!typescript.isVariableStatement(stmt)) {
continue;
}
const isExported = stmt.modifiers?.some((m) => m.kind === typescript.SyntaxKind.ExportKeyword);
if (!isExported) {
continue;
}
for (const decl of stmt.declarationList.declarations) {
if (!isTargetTypedDeclaration(decl)) {
continue;
}
if (decl.initializer && typescript.isObjectLiteralExpression(decl.initializer)) {
visitObject(decl.initializer);
}
}
}
return edits;
}
function escapeTemplateLiteral(s: string): string {
return s
.replaceAll('\\', String.raw`\\`)
.replaceAll('`', '\\`')
.replaceAll('${', '\\${');
}
async function* walk(dir: string): AsyncGenerator<string> {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
yield* walk(full);
} else if (entry.isFile() && /\.tsx?$/.test(entry.name) && !entry.name.endsWith('.d.ts')) {
yield full;
}
}
}
async function processFile(filePath: string): Promise<void> {
const sourceText = await fs.readFile(filePath, 'utf8');
if (!sourceText.includes('description')) {
return;
}
const sourceFile = typescript.createSourceFile(filePath, sourceText, typescript.ScriptTarget.Latest, false, filePath.endsWith('.tsx') ? typescript.ScriptKind.TSX : typescript.ScriptKind.TS);
const edits = collectDescriptionEdits(sourceFile);
if (edits.length === 0) {
return;
}
edits.sort((a, b) => b.start - a.start);
let result = sourceText;
let changed = false;
const formattedResults = await Promise.all(
edits.map(async (edit) => {
if (!edit.raw.trim()) {
return { edit, formatted: null as string | null };
}
const file = await processor.process(edit.raw);
return {
edit,
formatted: String(file).replace(/\n+$/, ''),
};
})
);
for (const { edit, formatted } of formattedResults) {
if (!formatted || formatted === edit.raw) {
continue;
}
const replacement = '`' + escapeTemplateLiteral(formatted) + '`'; // oxlint handles unncessary single line template literals.
result = result.slice(0, edit.start) + replacement + result.slice(edit.end);
changed = true;
}
if (changed) {
await fs.writeFile(filePath, result, 'utf8');
}
}
async function main() {
const started = performance.now();
// @ts-ignore ts(2550)
const files: string[] = await Array.fromAsync(walk(routesDir));
await Promise.all(files.map((f) => processFile(f)));
// oxlint-disable-next-line no-console
console.log(`Finished in ${Math.round(performance.now() - started)}ms on ${files.length} files.`);
}
await main();