├── .gitignore ├── wrangler.toml ├── .prettierrc ├── .editorconfig ├── README.md ├── package.json ├── worker-configuration.d.ts ├── src ├── index.ts └── rss │ ├── template.ts │ ├── index.ts │ └── routes │ └── bilibili.ts ├── LICENSE └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "rss-worker" 2 | main = "src/index.ts" 3 | compatibility_date = "2023-09-14" 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 140, 3 | "singleQuote": true, 4 | "semi": true, 5 | "useTabs": true 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | tab_width = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.yml] 13 | indent_style = space 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RSSWorker 2 | 一个能运行在 Cloudflare worker 上面的rss订阅源生成器(灵感来自[RSSHub](https://docs.rsshub.app/)) 3 | 4 | ## 使用方法 5 | 1. 安装依赖 - `npm install` 6 | 2. 部署到 Cloudflare worker - `npm run deploy` 7 | 8 | ## 可用路由 9 | ### 哔哩哔哩 10 | - `/bilibili/dynamic/:uid` - 用户动态 11 | - `/bilibili/videos/:uid` - 投稿视频 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "src", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "deploy": "wrangler deploy", 7 | "dev": "wrangler dev" 8 | }, 9 | "devDependencies": { 10 | "@cloudflare/workers-types": "^4.20230419.0", 11 | "itty-router": "^3.0.12", 12 | "typescript": "^5.0.4", 13 | "wrangler": "^3.0.0" 14 | } 15 | } -------------------------------------------------------------------------------- /worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | interface Env { 2 | // Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/ 3 | // MY_KV_NAMESPACE: KVNamespace; 4 | // 5 | // Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/ 6 | // MY_DURABLE_OBJECT: DurableObjectNamespace; 7 | // 8 | // Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/ 9 | // MY_BUCKET: R2Bucket; 10 | // 11 | // Example binding to a Service. Learn more at https://developers.cloudflare.com/workers/runtime-apis/service-bindings/ 12 | // MY_SERVICE: Fetcher; 13 | // 14 | // Example binding to a Queue. Learn more at https://developers.cloudflare.com/queues/javascript-apis/ 15 | // MY_QUEUE: Queue; 16 | } 17 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import apiRouter from './rss'; 2 | 3 | export default { 4 | async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { 5 | const url = new URL(request.url); 6 | if (url.pathname.startsWith('/rss')) { 7 | // You can also use more robust routing 8 | return apiRouter.handle(request); 9 | } 10 | 11 | // 更加优雅的首页~ 12 | return new Response( 13 | ` 14 | 15 | 16 | 17 | 18 | RSSWorker - Made with ❤ 19 | 20 | 21 |

RSSWorker - Made with ❤

22 |

See GitHub for more information.

23 | 24 | 25 | ` 26 | , 27 | { headers: { 'Content-Type': 'text/html' } } 28 | ); 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 TheresaQWQ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/rss/template.ts: -------------------------------------------------------------------------------- 1 | const rssTemplate = ` 2 | 3 | 4 | <![CDATA[{{title}}]]> 5 | {{link}} 6 | 7 | RSSHub 8 | zh-cn 9 | {{items}} 10 | 11 | ` 12 | 13 | const itemTemplate = ` 14 | 15 | <![CDATA[{{title}}]]> 16 | {{link}} 17 | {{guid}} 18 | {{pubDate}} 19 | 20 | 21 | {{extra}} 22 | ` 23 | 24 | export interface RSSItem { 25 | title: string; 26 | link: string; 27 | guid?: string; 28 | pubDate: string; 29 | description: string; 30 | author?: string; 31 | // 扩展参数 32 | extra?: { 33 | key: string; 34 | value: string; 35 | cdata?: boolean; 36 | }[] 37 | } 38 | 39 | export const generateRSSContent = (title: string, link: string, desc: string, items: RSSItem[]) => { 40 | const content = rssTemplate 41 | .replace('{{title}}', title) 42 | .replace('{{link}}', link) 43 | .replace('{{desc}}', desc) 44 | .replace('{{items}}', items.map(item => { 45 | let str = itemTemplate 46 | .replace('{{title}}', item.title) 47 | .replace('{{link}}', item.link) 48 | .replace('{{guid}}', item.guid || item.link) 49 | .replace('{{pubDate}}', item.pubDate) 50 | .replace('{{description}}', item.description) 51 | .replace('{{author}}', item.author || '') 52 | 53 | if (item.extra) { 54 | const extra = item.extra.map(extra => { 55 | return `<${extra.key}>${extra.cdata ? '' : ''}` 56 | }) 57 | 58 | str = str.replace('{{extra}}', extra.join('')) 59 | } 60 | 61 | return str 62 | }).join('')) 63 | 64 | return content 65 | } -------------------------------------------------------------------------------- /src/rss/index.ts: -------------------------------------------------------------------------------- 1 | import { RequestLike, Router } from 'itty-router'; 2 | import { RSSItem, generateRSSContent } from './template'; 3 | 4 | import { 5 | BilibiliDynamic, 6 | BilibiliVideos 7 | } from './routes/bilibili' 8 | 9 | const router = Router(); 10 | 11 | const routes: { 12 | path: string, 13 | handler: (req: RequestLike, params: any) => Promise<{ 14 | title: string, 15 | link: string, 16 | description: string, 17 | items: RSSItem[] 18 | }> 19 | }[] 20 | = [ 21 | { 22 | // 哔哩哔哩动态 23 | path: '/bilibili/dynamic/:uid', 24 | handler: BilibiliDynamic, 25 | }, 26 | { 27 | // 哔哩哔哩视频更新 28 | path: '/bilibili/videos/:uid', 29 | handler: BilibiliVideos, 30 | } 31 | ] 32 | 33 | router.get('*', async (req) => { 34 | const url = new URL(req.url); 35 | const pathname = url.pathname.substring(4); 36 | 37 | for (const route of routes) { 38 | // 匹配包含参数的路由 39 | const routeRegex = new RegExp(`^${route.path.replace(/\/:\w+/g, '(/\\w+)')}$`); 40 | const match = routeRegex.test(pathname) 41 | if (match) { 42 | const paramsArr = (routeRegex.exec(pathname)?.slice(1) || []).map((item) => decodeURIComponent(item).substring(1)); 43 | const paramsKeys: string[] = route.path.match(/\/:(\w+)/g)?.map((item) => item.substring(2)) || []; 44 | const params: { 45 | [index: string]: string 46 | } = {}; 47 | 48 | console.log(paramsArr, paramsKeys) 49 | 50 | paramsArr.forEach((param, index) => { 51 | params[paramsKeys[index]] = param; 52 | }) 53 | 54 | try { 55 | const response = await route.handler(req, params); 56 | const content = generateRSSContent(response.title, response.link, response.description, response.items) 57 | return new Response(content, { 58 | headers: { 59 | 'Content-Type': 'application/xml; charset=utf-8', 60 | 'Cache-Control': 'public, max-age=300', 61 | } 62 | }) 63 | } catch (error) { 64 | // TODO: 更加优雅的错误页面 65 | const e = error as unknown as Error 66 | return new Response(`${e.stack}`, { 67 | status: 500, 68 | headers: { 69 | 'Content-Type': 'text/plain; charset=utf-8', 70 | 'Cache-Control': 'no-cache, no-store, must-revalidate', 71 | } 72 | }) 73 | } 74 | } 75 | } 76 | 77 | // TODO: 更加优雅的404页面 78 | return new Response('Not Found', { 79 | status: 404, 80 | headers: { 81 | 'Content-Type': 'text/plain; charset=utf-8', 82 | 'Cache-Control': 'no-cache, no-store, must-revalidate', 83 | } 84 | }) 85 | }) 86 | 87 | export default router; 88 | -------------------------------------------------------------------------------- /src/rss/routes/bilibili.ts: -------------------------------------------------------------------------------- 1 | import { RequestLike } from "itty-router"; 2 | 3 | export const BilibiliDynamic = async (req: RequestLike, params: any) => { 4 | const url = new URL(req.url); 5 | const uid = params.uid; 6 | const directLink = url.searchParams.get('directLink') === 'true'; 7 | 8 | if (!uid) { 9 | throw new Error('uid is required'); 10 | } 11 | 12 | const resp = await fetch(`https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history?host_uid=${uid}`) 13 | const json = await resp.json() as any 14 | 15 | if (json.code !== 0) { 16 | throw new Error(json.message); 17 | } 18 | 19 | const author = json.data.cards[0].desc.user_profile.info.uname 20 | const cards = json.data.cards 21 | 22 | /** 23 | * 以下代码来自项目 DIYgod/RSSHub 24 | */ 25 | const items = await Promise.all( 26 | cards.map(async (item: any) => { 27 | const getTitle = (data: any) => (data ? data.title || data.description || data.content || (data.vest && data.vest.content) || '' : ''); 28 | const getDes = (data: any) => 29 | data.dynamic || data.desc || data.description || data.content || data.summary || (data.vest && data.vest.content) + (data.sketch && `
${data.sketch.title}
${data.sketch.desc_text}`) || data.intro || ''; 30 | const getOriginDes = (data: any) => (data && (data.apiSeasonInfo && data.apiSeasonInfo.title && `//转发自: ${data.apiSeasonInfo.title}`) + (data.index_title && `
${data.index_title}`)) || ''; 31 | const getOriginName = (data: any) => data.uname || (data.author && data.author.name) || (data.upper && data.upper.name) || (data.user && (data.user.uname || data.user.name)) || (data.owner && data.owner.name) || ''; 32 | const getOriginTitle = (data: any) => (data.title ? `${data.title}
` : ''); 33 | 34 | const parsed = JSON.parse(item.card); 35 | 36 | const data = getTitle(parsed.item) ? parsed.item : parsed; 37 | const origin = parsed.origin ? JSON.parse(parsed.origin) : null; 38 | 39 | // img 40 | let imgHTML = ''; 41 | const getImgs = (data: any) => { 42 | let imgs = ''; 43 | // 动态图片 44 | if (data.pictures) { 45 | for (let i = 0; i < data.pictures.length; i++) { 46 | imgs += ``; 47 | } 48 | } 49 | // 专栏封面 50 | if (data.image_urls) { 51 | for (let i = 0; i < data.image_urls.length; i++) { 52 | imgs += ``; 53 | } 54 | } 55 | // 视频封面 56 | if (data.pic) { 57 | imgs += ``; 58 | } 59 | // 音频/番剧/直播间封面/小视频封面 60 | if (data.cover && data.cover.unclipped) { 61 | imgs += ``; 62 | } else if (data.cover) { 63 | imgs += ``; 64 | } 65 | // 专题页封面 66 | if (data.sketch && data.sketch.cover_url) { 67 | imgs += ``; 68 | } 69 | return imgs; 70 | }; 71 | 72 | imgHTML += getImgs(data); 73 | 74 | if (origin) { 75 | imgHTML += getImgs(origin.item || origin); 76 | } 77 | // video小视频 78 | let videoHTML = ''; 79 | if (data.video_playurl) { 80 | videoHTML += ``; 81 | } 82 | 83 | // some rss readers disallow http content. 84 | // 部分 RSS 阅读器要求内容必须使用https传输 85 | // bilibili short video does support https request, but https request may timeout ocassionally. 86 | // to maximize content availability, here add two source tags. 87 | // bilibili的API中返回的视频地址采用http,然而经验证,短视频地址支持https访问,但偶尔会返回超时错误(可能是网络原因)。 88 | // 因此保险起见加入两个source标签 89 | // link 90 | let link = ''; 91 | if (data.dynamic_id) { 92 | link = `https://t.bilibili.com/${data.dynamic_id}`; 93 | } else if (item.desc?.dynamic_id) { 94 | link = `https://t.bilibili.com/${item.desc.dynamic_id}`; 95 | } 96 | 97 | // emoji 98 | let data_content = getDes(data); 99 | // 换行处理 100 | data_content = data_content.replace(/\r\n/g, '
').replace(/\n/g, '
'); 101 | if (item.display.emoji_info) { 102 | const emoji = item.display.emoji_info.emoji_details; 103 | emoji.forEach((item: any) => { 104 | data_content = data_content.replace( 105 | new RegExp(`\\${item.text}`.replace(/\\?/g, '\\?'), 'g'), 106 | `${item.text}` 107 | ); 108 | }); 109 | } 110 | const getUrl = (data: any) => { 111 | if (!data) { 112 | return ''; 113 | } 114 | let url; 115 | if (data.aid) { 116 | const id = item?.desc?.bvid || item?.desc?.origin?.bvid; 117 | url = `https://www.bilibili.com/video/${id}`; 118 | directLink && (link = url); 119 | return `
视频地址:${url}`; 120 | } 121 | if (data.image_urls) { 122 | url = `https://www.bilibili.com/read/cv${data.id}`; 123 | directLink && (link = url); 124 | return `
专栏地址:${url}`; 125 | } 126 | if (data.upper) { 127 | url = `https://www.bilibili.com/audio/au${data.id}`; 128 | directLink && (link = url); 129 | return `
音频地址:${url}`; 130 | } 131 | if (data.roomid) { 132 | url = `https://live.bilibili.com/${data.roomid}`; 133 | directLink && (link = url); 134 | return `
直播间地址:${url}`; 135 | } 136 | if (data.sketch) { 137 | url = data.sketch.target_url; 138 | directLink && (link = url); 139 | return `
活动地址:${url}`; 140 | } 141 | if (data.url) { 142 | url = data.url; 143 | directLink && (link = url); 144 | return `
地址:${url}`; 145 | } 146 | return ''; 147 | }; 148 | 149 | return { 150 | title: getTitle(data), 151 | description: (() => { 152 | const description = data_content || getDes(data); 153 | const originName = origin && getOriginName(origin) ? `

//转发自: @${getOriginName(origin)}: ${getOriginTitle(origin.item || origin)}${getDes(origin.item || origin)}` : getOriginDes(origin); 154 | const imgHTMLSource = imgHTML ? `
${imgHTML}` : ''; 155 | const videoHTMLSource = videoHTML ? `
${videoHTML}` : ''; 156 | return `${description}${originName}
${getUrl(data)}${getUrl(origin)}${imgHTMLSource}${videoHTMLSource}`; 157 | })(), 158 | pubDate: item.desc?.timestamp ? new Date(item.desc?.timestamp).toISOString() : null, 159 | link, 160 | author, 161 | }; 162 | }) 163 | ); 164 | 165 | return { 166 | title: `${author} 的 bilibili 动态`, 167 | link: `https://space.bilibili.com/${uid}/dynamic`, 168 | description: `${author} 的 bilibili 动态`, 169 | items: items 170 | } 171 | } 172 | 173 | export const BilibiliVideos = async (req: RequestLike, params: any) => { 174 | const uid = params.uid; 175 | const data: any = await (await fetch(`https://api.bilibili.com/x/space/arc/search?mid=${uid}`)).json() 176 | 177 | if (data.code !== 0) { 178 | throw new Error(data.message); 179 | } 180 | 181 | const list = data.data.list.vlist 182 | 183 | return { 184 | title: `${data.data.list.vlist[0].author} 投稿的视频`, 185 | link: `https://space.bilibili.com/${uid}`, 186 | description: `${data.data.list.vlist[0].author} 投稿的视频`, 187 | items: list.map((item: any) => { 188 | return { 189 | title: item.title, 190 | description: item.description, 191 | pubDate: new Date(item.created * 1000).toISOString(), 192 | link: `https://www.bilibili.com/video/${item.bvid}`, 193 | guid: item.aid 194 | } 195 | }) 196 | } 197 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | "lib": ["es2021"] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, 16 | "jsx": "react" /* Specify what JSX code is generated. */, 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | 26 | /* Modules */ 27 | "module": "es2022" /* Specify what module code is generated. */, 28 | // "rootDir": "./", /* Specify the root folder within your source files. */ 29 | "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, 30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 34 | "types": ["@cloudflare/workers-types"] /* Specify type package names to be included without being referenced in a source file. */, 35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 36 | "resolveJsonModule": true /* Enable importing .json files */, 37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 38 | 39 | /* JavaScript Support */ 40 | "allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */, 41 | "checkJs": false /* Enable error reporting in type-checked JavaScript files. */, 42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 43 | 44 | /* Emit */ 45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 50 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 51 | // "removeComments": true, /* Disable emitting comments. */ 52 | "noEmit": true /* Disable emitting files from a compilation. */, 53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 61 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 68 | 69 | /* Interop Constraints */ 70 | "isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */, 71 | "allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */, 72 | // "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, 73 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 74 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 75 | 76 | /* Type Checking */ 77 | "strict": true /* Enable all strict type-checking options. */, 78 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 79 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 80 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 81 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 82 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 83 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 84 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 85 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 86 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 87 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 88 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 89 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 90 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 91 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 92 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 93 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 94 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 95 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 96 | 97 | /* Completeness */ 98 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 99 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 100 | } 101 | } 102 | --------------------------------------------------------------------------------