├── .github └── workflows │ ├── code_health.yml │ └── populate_feed.yml ├── .gitignore ├── .nvmrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── __tests__ └── utils.test.js ├── config.json ├── feed.xml ├── jest.config.cjs ├── package-lock.json ├── package.json ├── scripts ├── build.js ├── collect-discussions.js ├── collect-issues.js ├── collect-releases.js ├── format-check.js ├── format.js └── validate.js └── utils └── index.js /.github/workflows/code_health.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - main 5 | push: 6 | branches: 7 | - main 8 | 9 | name: Source Code Health 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: actions/setup-node@v3 17 | with: 18 | node-version: '18.16.1' 19 | cache: 'npm' 20 | 21 | - name: Install dependencies 22 | run: npm ci 23 | 24 | - name: Lint 25 | run: npm run lint 26 | 27 | - name: Test 28 | run: npm run rss:build 29 | 30 | - name: RSS Build 31 | run: npm run rss:build 32 | 33 | - name: RSS Check Format 34 | run: npm run rss:format-check 35 | 36 | - name: RSS Validate 37 | run: npm run rss:validate 38 | -------------------------------------------------------------------------------- /.github/workflows/populate_feed.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | schedule: 4 | - cron: '0 0 * * 0' 5 | 6 | name: Populate Feed 7 | 8 | permissions: 9 | contents: write 10 | pull-requests: write 11 | issues: read 12 | packages: none 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: actions/setup-node@v3 20 | with: 21 | node-version: '18.16.1' 22 | cache: 'npm' 23 | 24 | - name: Install dependencies 25 | run: npm ci 26 | 27 | - name: Collect Releases 28 | run: npm run collect:releases 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | 32 | - name: Collect Issues (Comments) 33 | run: npm run collect:issues 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | 37 | - name: Collect Discussions (Comments) 38 | run: npm run collect:discussions 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 41 | 42 | - name: RSS Build 43 | run: npm run rss:build 44 | 45 | - name: RSS Format 46 | run: npm run rss:format 47 | 48 | - name: RSS Validate 49 | run: npm run rss:validate 50 | 51 | - name: Create Pull Request 52 | uses: gr2m/create-or-update-pull-request-action@77596e3166f328b24613f7082ab30bf2d93079d5 53 | env: 54 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 55 | with: 56 | commit-message: 'chore: updated feed data' 57 | title: Feed Updated 🍿 58 | body: 'Feed data Updated. cc: @ulisesGascon @mhdawson' 59 | assignees: ${{ github.actor }} 60 | labels: content-update 61 | branch: feed-update 62 | update-pull-request-title-and-body: true 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node,macos,linux,windows 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,linux,windows 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### macOS ### 20 | # General 21 | .DS_Store 22 | .AppleDouble 23 | .LSOverride 24 | 25 | # Icon must end with two \r 26 | Icon 27 | 28 | 29 | # Thumbnails 30 | ._* 31 | 32 | # Files that might appear in the root of a volume 33 | .DocumentRevisions-V100 34 | .fseventsd 35 | .Spotlight-V100 36 | .TemporaryItems 37 | .Trashes 38 | .VolumeIcon.icns 39 | .com.apple.timemachine.donotpresent 40 | 41 | # Directories potentially created on remote AFP share 42 | .AppleDB 43 | .AppleDesktop 44 | Network Trash Folder 45 | Temporary Items 46 | .apdisk 47 | 48 | ### macOS Patch ### 49 | # iCloud generated files 50 | *.icloud 51 | 52 | ### Node ### 53 | # Logs 54 | logs 55 | *.log 56 | npm-debug.log* 57 | yarn-debug.log* 58 | yarn-error.log* 59 | lerna-debug.log* 60 | .pnpm-debug.log* 61 | 62 | # Diagnostic reports (https://nodejs.org/api/report.html) 63 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 64 | 65 | # Runtime data 66 | pids 67 | *.pid 68 | *.seed 69 | *.pid.lock 70 | 71 | # Directory for instrumented libs generated by jscoverage/JSCover 72 | lib-cov 73 | 74 | # Coverage directory used by tools like istanbul 75 | coverage 76 | *.lcov 77 | 78 | # nyc test coverage 79 | .nyc_output 80 | 81 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 82 | .grunt 83 | 84 | # Bower dependency directory (https://bower.io/) 85 | bower_components 86 | 87 | # node-waf configuration 88 | .lock-wscript 89 | 90 | # Compiled binary addons (https://nodejs.org/api/addons.html) 91 | build/Release 92 | 93 | # Dependency directories 94 | node_modules/ 95 | jspm_packages/ 96 | 97 | # Snowpack dependency directory (https://snowpack.dev/) 98 | web_modules/ 99 | 100 | # TypeScript cache 101 | *.tsbuildinfo 102 | 103 | # Optional npm cache directory 104 | .npm 105 | 106 | # Optional eslint cache 107 | .eslintcache 108 | 109 | # Optional stylelint cache 110 | .stylelintcache 111 | 112 | # Microbundle cache 113 | .rpt2_cache/ 114 | .rts2_cache_cjs/ 115 | .rts2_cache_es/ 116 | .rts2_cache_umd/ 117 | 118 | # Optional REPL history 119 | .node_repl_history 120 | 121 | # Output of 'npm pack' 122 | *.tgz 123 | 124 | # Yarn Integrity file 125 | .yarn-integrity 126 | 127 | # dotenv environment variable files 128 | .env 129 | .env.development.local 130 | .env.test.local 131 | .env.production.local 132 | .env.local 133 | 134 | # parcel-bundler cache (https://parceljs.org/) 135 | .cache 136 | .parcel-cache 137 | 138 | # Next.js build output 139 | .next 140 | out 141 | 142 | # Nuxt.js build / generate output 143 | .nuxt 144 | dist 145 | 146 | # Gatsby files 147 | .cache/ 148 | # Comment in the public line in if your project uses Gatsby and not Next.js 149 | # https://nextjs.org/blog/next-9-1#public-directory-support 150 | # public 151 | 152 | # vuepress build output 153 | .vuepress/dist 154 | 155 | # vuepress v2.x temp and cache directory 156 | .temp 157 | 158 | # Docusaurus cache and generated files 159 | .docusaurus 160 | 161 | # Serverless directories 162 | .serverless/ 163 | 164 | # FuseBox cache 165 | .fusebox/ 166 | 167 | # DynamoDB Local files 168 | .dynamodb/ 169 | 170 | # TernJS port file 171 | .tern-port 172 | 173 | # Stores VSCode versions used for testing VSCode extensions 174 | .vscode-test 175 | 176 | # yarn v2 177 | .yarn/cache 178 | .yarn/unplugged 179 | .yarn/build-state.yml 180 | .yarn/install-state.gz 181 | .pnp.* 182 | 183 | ### Node Patch ### 184 | # Serverless Webpack directories 185 | .webpack/ 186 | 187 | # Optional stylelint cache 188 | 189 | # SvelteKit build / generate output 190 | .svelte-kit 191 | 192 | ### Windows ### 193 | # Windows thumbnail cache files 194 | Thumbs.db 195 | Thumbs.db:encryptable 196 | ehthumbs.db 197 | ehthumbs_vista.db 198 | 199 | # Dump file 200 | *.stackdump 201 | 202 | # Folder config file 203 | [Dd]esktop.ini 204 | 205 | # Recycle Bin used on file shares 206 | $RECYCLE.BIN/ 207 | 208 | # Windows Installer files 209 | *.cab 210 | *.msi 211 | *.msix 212 | *.msm 213 | *.msp 214 | 215 | # Windows shortcuts 216 | *.lnk 217 | 218 | # End of https://www.toptal.com/developers/gitignore/api/node,macos,linux,windows 219 | 220 | IGNORE/ -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18.16.1 -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | The Node.js Code of Conduct applies to this repo. 4 | 5 | The Node.js Code of Conduct document can be found at 6 | https://github.com/nodejs/admin/blob/main/CODE_OF_CONDUCT.md -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | * [Code of Conduct](#code-of-conduct) 4 | * [Issues](#issues) 5 | * [Pull Requests](#pull-requests) 6 | * [Developer's Certificate of Origin 1.1](#developers-certificate-of-origin) 7 | 8 | ## [Code of Conduct](./doc/contributing/code-of-conduct.md) 9 | 10 | The project has a 11 | [Code of Conduct](CODE_OF_CONDUCT.md) 12 | to which all contributors must adhere. 13 | 14 | See [details on our policy on Code of Conduct](CODE_OF_CONDUCT.md). 15 | 16 | ## [Issues](./doc/contributing/issues.md) 17 | 18 | You can use the issues to: 19 | - Asking for General Help 20 | - Discussing non-technical topics 21 | - Submitting a Bug Report 22 | 23 | 24 | ## [Pull Requests](./doc/contributing/pull-requests.md) 25 | 26 | Feel free to submit a pull request (PR) if you see something that can be improved. We will provide you support if you are new to open source and/or contributing to open source projects. 27 | 28 | 29 | 30 | ## Developer's Certificate of Origin 1.1 31 | 32 |
33 | By making a contribution to this project, I certify that:
34 | 
35 |  (a) The contribution was created in whole or in part by me and I
36 |      have the right to submit it under the open source license
37 |      indicated in the file; or
38 | 
39 |  (b) The contribution is based upon previous work that, to the best
40 |      of my knowledge, is covered under an appropriate open source
41 |      license and I have the right under that license to submit that
42 |      work with modifications, whether created in whole or in part
43 |      by me, under the same open source license (unless I am
44 |      permitted to submit under a different license), as indicated
45 |      in the file; or
46 | 
47 |  (c) The contribution was provided directly to me by some other
48 |      person who certified (a), (b) or (c) and I have not modified
49 |      it.
50 | 
51 |  (d) I understand and agree that this project and the contribution
52 |      are public and that a record of the contribution (including all
53 |      personal information I submit with it, including my sign-off) is
54 |      maintained indefinitely and may be redistributed consistent with
55 |      this project or the open source license(s) involved.
56 | 
-------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ulises Gascon and Contributors 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Official Node.js News Feeder 2 | 3 | ### Usage 4 | 5 | This project is a proof of concept of a news feeder using NodeJS. It uses the Github API to fetch the relevant information from issues, releases..and then it generates a RSS feed with the latest news. 6 | 7 | The RSS feed is available at https://raw.githubusercontent.com/nodejs/nodejs-news-feeder/main/feed.xml and https://nodejs.github.io/nodejs-news-feeder/feed.xml 8 | 9 | In order to update the RSS feed, you need to trigger the Github Action `Populate Feed` [manually](https://github.com/nodejs/nodejs-news-feeder/actions/workflows/populate_feed.yml) or wait for the CRON job. 10 | 11 | This process will generate a PR with the latest news, so we can change the content and decide when to merge it. 12 | 13 | ### Development 14 | 15 | ```bash 16 | git clone https://github.com/nodejs/nodejs-news-feeder 17 | cd nodejs-news-feeder 18 | nvm use 19 | npm install 20 | ``` 21 | 22 | 23 | ### Scripts 24 | 25 | #### Code linter 26 | 27 | ```bash 28 | npm run lint 29 | npm run lint:fix 30 | ``` 31 | 32 | #### Testing 33 | 34 | ```bash 35 | npm run test 36 | npm run test:watch 37 | npm run test:coverage 38 | ``` 39 | 40 | #### RSS formatter 41 | 42 | Update the `feed.xml` file format 43 | 44 | ```bash 45 | npm run rss:format-check 46 | npm run rss:format 47 | ``` 48 | 49 | #### RSS Build 50 | 51 | Update the `feed.xml` file with the latest news 52 | 53 | ```bash 54 | npm run rss:build 55 | ``` 56 | 57 | #### RSS Validate 58 | 59 | Check the current `feed.xml` against the https://validator.w3.org/feed/check.cgi 60 | 61 | ```bash 62 | npm run rss:validate 63 | ``` 64 | 65 | ### License 66 | 67 | MIT License -------------------------------------------------------------------------------- /__tests__/utils.test.js: -------------------------------------------------------------------------------- 1 | import { buildRFC822Date } from '../utils' 2 | 3 | describe('Utils', () => { 4 | describe('buildRFC822Date', () => { 5 | it('should return a date in RFC822 format', () => { 6 | expect(buildRFC822Date('2021-11-29T00:00:00.000Z')).toBe('Mon, 29 Nov 2021 01:00:00 BST') 7 | expect(buildRFC822Date('2021-09-08T00:00:00.000+01:00')).toBe('Wed, 08 Sep 2021 01:00:00 BST') 8 | }) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lastCheckTimestamp": 1694304480111, 3 | "reposPaginationLimit": 250, 4 | "releasePaginationLimit": 10, 5 | "commentsPaginationLimit": 100, 6 | "breakDelimiter": "", 7 | "discussionsInScope": [ 8 | { 9 | "team": "Node.js Core", 10 | "discussionId": "47703" 11 | } 12 | ], 13 | "issuesInScope": [ 14 | { 15 | "team": "News Feeder team", 16 | "issue": "nodejs/nodejs-news-feeder/issues/4" 17 | }, 18 | { 19 | "team": "Uvwasi team", 20 | "issue": "nodejs/uvwasi/issues/201" 21 | }, 22 | { 23 | "team": "Node-API and node-addon-api teams", 24 | "issue": "nodejs/abi-stable-node/issues/446" 25 | }, 26 | { 27 | "team": "Security WG", 28 | "issue": "nodejs/security-wg/issues/1006" 29 | }, 30 | { 31 | "team": "Single Executable team", 32 | "issue": "nodejs/single-executable/issues/74" 33 | }, 34 | { 35 | "team": "Performance team", 36 | "issue": "nodejs/performance/issues/98" 37 | }, 38 | { 39 | "team": "Website team", 40 | "issue": "nodejs/nodejs.org/issues/5602" 41 | }, 42 | { 43 | "team": "Diagnostic team", 44 | "issue": "nodejs/diagnostics/issues/619" 45 | } 46 | ] 47 | } -------------------------------------------------------------------------------- /feed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Node.js News 5 | https://nodejs.github.io/nodejs-news-feeder/feed.xml 6 | 7 | Node.js Core most relevant news 8 | Tue, 13 Jun 2023 04:17:50 GMT 9 | en-us 10 | https://validator.w3.org/feed/docs/rss2.html 11 | Sun, 10 Sep 2023 00:08:00 GMT 12 | 13 | Node.js News 14 | https://pbs.twimg.com/profile_images/1262824892535373825/BiXDFDDp_400x400.jpg 15 | https://github.com/nodejs/nodejs-news-feeder 16 | 17 | 18 | Released nodejs/caritat v1.2.0 19 | Released nodejs/caritat v1.2.0 by github-actions[bot]. More details

20 | ]]>
21 | Sun, 03 Sep 2023 18:19:00 GMT 22 | https://github.com/nodejs/caritat/releases/tag/v1.2.0 23 | https://github.com/nodejs/caritat/releases/tag/v1.2.0 24 |
25 | 26 | Released nodejs/node v20.6.1 27 | Released nodejs/node v20.6.1 by ruyadorno. More details

28 | ]]>
29 | Fri, 08 Sep 2023 16:49:00 GMT 30 | https://github.com/nodejs/node/releases/tag/v20.6.1 31 | https://github.com/nodejs/node/releases/tag/v20.6.1 32 |
33 | 34 | Released nodejs/node v20.6.0 35 | Released nodejs/node v20.6.0 by UlisesGascon. More details

36 | ]]>
37 | Mon, 04 Sep 2023 20:30:00 GMT 38 | https://github.com/nodejs/node/releases/tag/v20.6.0 39 | https://github.com/nodejs/node/releases/tag/v20.6.0 40 |
41 | 42 | Released nodejs/node-core-utils v3.4.0 43 | Released nodejs/node-core-utils v3.4.0 by github-actions[bot]. More details

44 | ]]>
45 | Mon, 04 Sep 2023 08:04:00 GMT 46 | https://github.com/nodejs/node-core-utils/releases/tag/v3.4.0 47 | https://github.com/nodejs/node-core-utils/releases/tag/v3.4.0 48 |
49 | 50 | Released nodejs/undici v5.24.0 51 | Released nodejs/undici v5.24.0 by mcollina. More details

52 | ]]>
53 | Fri, 08 Sep 2023 14:10:00 GMT 54 | https://github.com/nodejs/undici/releases/tag/v5.24.0 55 | https://github.com/nodejs/undici/releases/tag/v5.24.0 56 |
57 | 58 | Released nodejs/corepack v0.20.0 59 | Released nodejs/corepack v0.20.0 by github-actions[bot]. More details

60 | ]]>
61 | Tue, 29 Aug 2023 15:38:00 GMT 62 | https://github.com/nodejs/corepack/releases/tag/v0.20.0 63 | https://github.com/nodejs/corepack/releases/tag/v0.20.0 64 |
65 | 66 | Released nodejs/branch-diff v2.1.4 67 | Released nodejs/branch-diff v2.1.4 by github-actions[bot]. More details

68 | ]]>
69 | Mon, 21 Aug 2023 05:15:00 GMT 70 | https://github.com/nodejs/branch-diff/releases/tag/v2.1.4 71 | https://github.com/nodejs/branch-diff/releases/tag/v2.1.4 72 |
73 | 74 | Released nodejs/llhttp release/v9.0.1 75 | Released nodejs/llhttp release/v9.0.1 by ShogunPanda. More details

76 | ]]>
77 | Mon, 21 Aug 2023 12:10:00 GMT 78 | https://github.com/nodejs/llhttp/releases/tag/release/v9.0.1 79 | https://github.com/nodejs/llhttp/releases/tag/release/v9.0.1 80 |
81 | 82 | Released nodejs/branch-diff v2.1.3 83 | Released nodejs/branch-diff v2.1.3 by github-actions[bot]. More details

84 | ]]>
85 | Tue, 15 Aug 2023 01:09:00 GMT 86 | https://github.com/nodejs/branch-diff/releases/tag/v2.1.3 87 | https://github.com/nodejs/branch-diff/releases/tag/v2.1.3 88 |
89 | 90 | Released nodejs/caritat v1.1.1 91 | Released nodejs/caritat v1.1.1 by github-actions[bot]. More details

92 | ]]>
93 | Mon, 14 Aug 2023 13:44:00 GMT 94 | https://github.com/nodejs/caritat/releases/tag/v1.1.1 95 | https://github.com/nodejs/caritat/releases/tag/v1.1.1 96 |
97 | 98 | Released nodejs/caritat v1.1.0 99 | Released nodejs/caritat v1.1.0 by github-actions[bot]. More details

100 | ]]>
101 | Mon, 14 Aug 2023 13:39:00 GMT 102 | https://github.com/nodejs/caritat/releases/tag/v1.1.0 103 | https://github.com/nodejs/caritat/releases/tag/v1.1.0 104 |
105 | 106 | Released nodejs/node v20.5.1 107 | Released nodejs/node v20.5.1 by RafaelGSS. More details

108 | ]]>
109 | Wed, 09 Aug 2023 17:58:00 GMT 110 | https://github.com/nodejs/node/releases/tag/v20.5.1 111 | https://github.com/nodejs/node/releases/tag/v20.5.1 112 |
113 | 114 | Released nodejs/node v18.17.1 115 | Released nodejs/node v18.17.1 by RafaelGSS. More details

116 | ]]>
117 | Wed, 09 Aug 2023 17:58:00 GMT 118 | https://github.com/nodejs/node/releases/tag/v18.17.1 119 | https://github.com/nodejs/node/releases/tag/v18.17.1 120 |
121 | 122 | Released nodejs/node v16.20.2 123 | Released nodejs/node v16.20.2 by RafaelGSS. More details

124 | ]]>
125 | Wed, 09 Aug 2023 17:57:00 GMT 126 | https://github.com/nodejs/node/releases/tag/v16.20.2 127 | https://github.com/nodejs/node/releases/tag/v16.20.2 128 |
129 | 130 | Node-API and node-addon-api teams update on 2023-08-05 12:18:06 131 | node-api-headers v1.1.0 has been released.

132 | ]]>
133 | Sat, 05 Aug 2023 12:18:00 GMT 134 | https://github.com/nodejs/abi-stable-node/issues/446#issuecomment-1666490129 135 | https://github.com/nodejs/abi-stable-node/issues/446#issuecomment-1666490129 136 |
137 | 138 | Released nodejs/llhttp release/v9.0.0 139 | Released nodejs/llhttp release/v9.0.0 by ShogunPanda. More details

140 | ]]>
141 | Mon, 31 Jul 2023 14:31:00 GMT 142 | https://github.com/nodejs/llhttp/releases/tag/release/v9.0.0 143 | https://github.com/nodejs/llhttp/releases/tag/release/v9.0.0 144 |
145 | 146 | Released nodejs/node-api-headers v1.1.0 147 | Released nodejs/node-api-headers v1.1.0 by NickNaso. More details

148 | ]]>
149 | Sat, 05 Aug 2023 12:09:00 GMT 150 | https://github.com/nodejs/node-api-headers/releases/tag/v1.1.0 151 | https://github.com/nodejs/node-api-headers/releases/tag/v1.1.0 152 |
153 | 154 | Released nodejs/node-core-utils v3.3.0 155 | Released nodejs/node-core-utils v3.3.0 by github-actions[bot]. More details

156 | ]]>
157 | Fri, 04 Aug 2023 20:10:00 GMT 158 | https://github.com/nodejs/node-core-utils/releases/tag/v3.3.0 159 | https://github.com/nodejs/node-core-utils/releases/tag/v3.3.0 160 |
161 | 162 | Released nodejs/undici v5.23.0 163 | Released nodejs/undici v5.23.0 by ronag. More details

164 | ]]>
165 | Thu, 03 Aug 2023 08:33:00 GMT 166 | https://github.com/nodejs/undici/releases/tag/v5.23.0 167 | https://github.com/nodejs/undici/releases/tag/v5.23.0 168 |
169 | 170 | Released nodejs/node v20.5.0 171 | Released nodejs/node v20.5.0 by juanarbol. More details

172 | ]]>
173 | Thu, 20 Jul 2023 21:41:00 GMT 174 | https://github.com/nodejs/node/releases/tag/v20.5.0 175 | https://github.com/nodejs/node/releases/tag/v20.5.0 176 |
177 | 178 | Released nodejs/node v18.17.0 179 | Released nodejs/node v18.17.0 by danielleadams. More details

180 | ]]>
181 | Tue, 18 Jul 2023 20:05:00 GMT 182 | https://github.com/nodejs/node/releases/tag/v18.17.0 183 | https://github.com/nodejs/node/releases/tag/v18.17.0 184 |
185 | 186 | Released nodejs/branch-diff v2.1.2 187 | Released nodejs/branch-diff v2.1.2 by github-actions[bot]. More details

188 | ]]>
189 | Fri, 07 Jul 2023 07:18:00 GMT 190 | https://github.com/nodejs/branch-diff/releases/tag/v2.1.2 191 | https://github.com/nodejs/branch-diff/releases/tag/v2.1.2 192 |
193 | 194 | Released nodejs/node v20.4.0 195 | Released nodejs/node v20.4.0 by RafaelGSS. More details

196 | ]]>
197 | Wed, 05 Jul 2023 15:12:00 GMT 198 | https://github.com/nodejs/node/releases/tag/v20.4.0 199 | https://github.com/nodejs/node/releases/tag/v20.4.0 200 |
201 | 202 | Released nodejs/node-core-utils v3.2.1 203 | Released nodejs/node-core-utils v3.2.1 by github-actions[bot]. More details

204 | ]]>
205 | Tue, 04 Jul 2023 15:23:00 GMT 206 | https://github.com/nodejs/node-core-utils/releases/tag/v3.2.1 207 | https://github.com/nodejs/node-core-utils/releases/tag/v3.2.1 208 |
209 | 210 | Released nodejs/readable-stream v4.4.2 211 | Released nodejs/readable-stream v4.4.2 by mcollina. More details

212 | ]]>
213 | Mon, 03 Jul 2023 12:59:00 GMT 214 | https://github.com/nodejs/readable-stream/releases/tag/v4.4.2 215 | https://github.com/nodejs/readable-stream/releases/tag/v4.4.2 216 |
217 | 218 | Released nodejs/readable-stream v4.4.1 219 | Released nodejs/readable-stream v4.4.1 by mcollina. More details

220 | ]]>
221 | Mon, 03 Jul 2023 12:59:00 GMT 222 | https://github.com/nodejs/readable-stream/releases/tag/v4.4.1 223 | https://github.com/nodejs/readable-stream/releases/tag/v4.4.1 224 |
225 | 226 | Released nodejs/caritat v1.0.1 227 | Released nodejs/caritat v1.0.1 by github-actions[bot]. More details

228 | ]]>
229 | Wed, 28 Jun 2023 23:01:00 GMT 230 | https://github.com/nodejs/caritat/releases/tag/v1.0.1 231 | https://github.com/nodejs/caritat/releases/tag/v1.0.1 232 |
233 | 234 | Released nodejs/caritat v1.0.0 235 | Released nodejs/caritat v1.0.0 by github-actions[bot]. More details

236 | ]]>
237 | Wed, 28 Jun 2023 22:44:00 GMT 238 | https://github.com/nodejs/caritat/releases/tag/v1.0.0 239 | https://github.com/nodejs/caritat/releases/tag/v1.0.0 240 |
241 | 242 | Uvwasi team update on 2023-06-07 18:05:55 243 | Node.js main branch updated to include v0.0.18 version os uvwasi

244 | ]]>
245 | Wed, 07 Jun 2023 18:05:00 GMT 246 | https://github.com/nodejs/uvwasi/issues/201#issuecomment-1581283377 247 | https://github.com/nodejs/uvwasi/issues/201#issuecomment-1581283377 248 |
249 | 250 | Node-API and node-addon-api teams update on 2023-06-02 15:09:28 251 | Node-API version 9 has been landed: https://github.com/nodejs/node/pull/48151.

252 | ]]>
253 | Fri, 02 Jun 2023 15:09:00 GMT 254 | https://github.com/nodejs/abi-stable-node/issues/446#issuecomment-1573890828 255 | https://github.com/nodejs/abi-stable-node/issues/446#issuecomment-1573890828 256 |
257 | 258 | Released nodejs/caritat v0.6.2 259 | Released nodejs/caritat v0.6.2 by github-actions[bot]. More details

260 | ]]>
261 | Tue, 13 Jun 2023 16:22:00 GMT 262 | https://github.com/nodejs/caritat/releases/tag/v0.6.2 263 | https://github.com/nodejs/caritat/releases/tag/v0.6.2 264 |
265 | 266 | Released nodejs/caritat v0.6.1 267 | Released nodejs/caritat v0.6.1 by github-actions[bot]. More details

268 | ]]>
269 | Tue, 13 Jun 2023 16:10:00 GMT 270 | https://github.com/nodejs/caritat/releases/tag/v0.6.1 271 | https://github.com/nodejs/caritat/releases/tag/v0.6.1 272 |
273 | 274 | Released nodejs/caritat v0.6.0 275 | Released nodejs/caritat v0.6.0 by github-actions[bot]. More details

276 | ]]>
277 | Tue, 13 Jun 2023 15:38:00 GMT 278 | https://github.com/nodejs/caritat/releases/tag/v0.6.0 279 | https://github.com/nodejs/caritat/releases/tag/v0.6.0 280 |
281 | 282 | Released nodejs/corepack v0.19.0 283 | Released nodejs/corepack v0.19.0 by github-actions[bot]. More details

284 | ]]>
285 | Sat, 24 Jun 2023 16:55:00 GMT 286 | https://github.com/nodejs/corepack/releases/tag/v0.19.0 287 | https://github.com/nodejs/corepack/releases/tag/v0.19.0 288 |
289 | 290 | Released nodejs/corepack v0.18.1 291 | Released nodejs/corepack v0.18.1 by github-actions[bot]. More details

292 | ]]>
293 | Tue, 13 Jun 2023 12:56:00 GMT 294 | https://github.com/nodejs/corepack/releases/tag/v0.18.1 295 | https://github.com/nodejs/corepack/releases/tag/v0.18.1 296 |
297 | 298 | Released nodejs/llhttp release/v8.1.1 299 | Released nodejs/llhttp release/v8.1.1 by ShogunPanda. More details

300 | ]]>
301 | Wed, 21 Jun 2023 08:07:00 GMT 302 | https://github.com/nodejs/llhttp/releases/tag/release/v8.1.1 303 | https://github.com/nodejs/llhttp/releases/tag/release/v8.1.1 304 |
305 | 306 | Released nodejs/llhttp release/v6.0.11 307 | Released nodejs/llhttp release/v6.0.11 by ShogunPanda. More details

308 | ]]>
309 | Wed, 21 Jun 2023 08:45:00 GMT 310 | https://github.com/nodejs/llhttp/releases/tag/release/v6.0.11 311 | https://github.com/nodejs/llhttp/releases/tag/release/v6.0.11 312 |
313 | 314 | Released nodejs/node v20.3.1 315 | Released nodejs/node v20.3.1 by RafaelGSS. More details

316 | ]]>
317 | Tue, 20 Jun 2023 20:15:00 GMT 318 | https://github.com/nodejs/node/releases/tag/v20.3.1 319 | https://github.com/nodejs/node/releases/tag/v20.3.1 320 |
321 | 322 | Released nodejs/node v18.16.1 323 | Released nodejs/node v18.16.1 by RafaelGSS. More details

324 | ]]>
325 | Tue, 20 Jun 2023 20:35:00 GMT 326 | https://github.com/nodejs/node/releases/tag/v18.16.1 327 | https://github.com/nodejs/node/releases/tag/v18.16.1 328 |
329 | 330 | Released nodejs/node v16.20.1 331 | Released nodejs/node v16.20.1 by RafaelGSS. More details

332 | ]]>
333 | Tue, 20 Jun 2023 19:29:00 GMT 334 | https://github.com/nodejs/node/releases/tag/v16.20.1 335 | https://github.com/nodejs/node/releases/tag/v16.20.1 336 |
337 | 338 | Released nodejs/node v20.3.0 339 | Released nodejs/node v20.3.0 by RafaelGSS. More details

340 | ]]>
341 | Thu, 08 Jun 2023 16:34:00 GMT 342 | https://github.com/nodejs/node/releases/tag/v20.3.0 343 | https://github.com/nodejs/node/releases/tag/v20.3.0 344 |
345 | 346 | Released nodejs/node-addon-api v7.0.0 347 | Released nodejs/node-addon-api v7.0.0 by KevinEady. More details

348 | ]]>
349 | Fri, 16 Jun 2023 21:19:00 GMT 350 | https://github.com/nodejs/node-addon-api/releases/tag/v7.0.0 351 | https://github.com/nodejs/node-addon-api/releases/tag/v7.0.0 352 |
353 | 354 | Released nodejs/node-core-utils v3.2.0 355 | Released nodejs/node-core-utils v3.2.0 by github-actions[bot]. More details

356 | ]]>
357 | Mon, 26 Jun 2023 06:12:00 GMT 358 | https://github.com/nodejs/node-core-utils/releases/tag/v3.2.0 359 | https://github.com/nodejs/node-core-utils/releases/tag/v3.2.0 360 |
361 | 362 | Released nodejs/node-core-utils v3.1.0 363 | Released nodejs/node-core-utils v3.1.0 by github-actions[bot]. More details

364 | ]]>
365 | Mon, 12 Jun 2023 06:32:00 GMT 366 | https://github.com/nodejs/node-core-utils/releases/tag/v3.1.0 367 | https://github.com/nodejs/node-core-utils/releases/tag/v3.1.0 368 |
369 | 370 | Released nodejs/node-gyp v9.4.0 371 | Released nodejs/node-gyp v9.4.0 by github-actions[bot]. More details

372 | ]]>
373 | Tue, 13 Jun 2023 04:48:00 GMT 374 | https://github.com/nodejs/node-gyp/releases/tag/v9.4.0 375 | https://github.com/nodejs/node-gyp/releases/tag/v9.4.0 376 |
377 |
378 |
-------------------------------------------------------------------------------- /jest.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'jest-environment-node', 4 | transform: {}, 5 | transformIgnorePatterns: ['/node_modules/'] 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-news-feeder", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "private": true, 7 | "type": "module", 8 | "scripts": { 9 | "collect:releases": "node scripts/collect-releases.js", 10 | "collect:issues": "node scripts/collect-issues.js", 11 | "collect:discussions": "node scripts/collect-discussions.js", 12 | "rss:validate": "node scripts/validate.js", 13 | "rss:build": "node scripts/build.js", 14 | "rss:format": "node scripts/format.js", 15 | "rss:format-check": "node scripts/format-check.js", 16 | "lint": "standard", 17 | "lint:fix": "standard --fix", 18 | "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --detectOpenHandles --forceExit --verbose", 19 | "test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --detectOpenHandles --forceExit --verbose --coverage", 20 | "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --detectOpenHandles --forceExit --verbose --watchAll" 21 | }, 22 | "standard": { 23 | "env": [ 24 | "jest" 25 | ] 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/nodejs/nodejs-news-feeder.git" 30 | }, 31 | "author": "", 32 | "license": "MIT", 33 | "engines": { 34 | "node": ">=18.0.0", 35 | "npm": ">=9.0.0" 36 | }, 37 | "bugs": { 38 | "url": "https://github.com/nodejs/nodejs-news-feeder/issues" 39 | }, 40 | "homepage": "https://github.com/nodejs/nodejs-news-feeder#readme", 41 | "devDependencies": { 42 | "jest": "29.5.0", 43 | "standard": "17.1.0" 44 | }, 45 | "dependencies": { 46 | "@octokit/graphql": "6.0.1", 47 | "gh-got": "10.0.0", 48 | "got": "13.0.0", 49 | "jsdom": "22.1.0", 50 | "remark": "14.0.3", 51 | "remark-html": "15.0.2", 52 | "xml-formatter": "3.4.1" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | import { buildRFC822Date, overwriteFeedContent, getFeedContent, getConfig, overwriteConfig } from '../utils/index.js' 2 | 3 | const xml = getFeedContent() 4 | const now = new Date() 5 | 6 | // Replace lastBuildDate with current date in the feed 7 | const lastBuildDateRegex = /.*<\/lastBuildDate>/g 8 | const [before, after] = xml.split(lastBuildDateRegex) 9 | const updatedXml = `${before}${buildRFC822Date(now.toISOString())}${after}` 10 | 11 | overwriteFeedContent(updatedXml) 12 | 13 | // Overwrite config with new timestamp 14 | const config = getConfig() 15 | overwriteConfig({ ...config, lastCheckTimestamp: now.getTime() }) 16 | -------------------------------------------------------------------------------- /scripts/collect-discussions.js: -------------------------------------------------------------------------------- 1 | import { graphql } from '@octokit/graphql' 2 | import { getConfig, composeFeedItem, buildTitleDate, md2html, buildRFC822Date, getFeedContent, overwriteFeedContent } from '../utils/index.js' 3 | 4 | const { discussionsInScope, breakDelimiter, lastCheckTimestamp } = getConfig() 5 | 6 | const comments = await Promise.all(discussionsInScope.map(async ({ discussionId, team }) => { 7 | const { repository } = await graphql( 8 | ` 9 | { 10 | repository(name: "node", owner: "nodejs") { 11 | discussion(number: ${discussionId}) { 12 | comments(last: 100) { 13 | edges { 14 | node { 15 | body 16 | publishedAt 17 | updatedAt 18 | databaseId 19 | } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | `, 26 | { 27 | headers: { 28 | authorization: `token ${process.env.GITHUB_TOKEN}` 29 | } 30 | } 31 | ) 32 | 33 | return repository.discussion.comments.edges 34 | .filter(comment => new Date(comment.node.publishedAt).getTime() > lastCheckTimestamp) 35 | .map(comment => ({ ...comment.node, team, discussionId })) 36 | })) 37 | 38 | const relevantComments = comments.flat().map(comment => composeFeedItem({ 39 | title: `${comment.team} update on ${buildTitleDate(comment.publishedAt)}`, 40 | description: ``, 41 | pubDate: buildRFC822Date(comment.publishedAt), 42 | link: `https://github.com/orgs/nodejs/discussions/${comment.discussionId}#discussioncomment-${comment.databaseId}`, 43 | guid: `https://github.com/orgs/nodejs/discussions/${comment.discussionId}#discussioncomment-${comment.databaseId}` 44 | })).join('') 45 | 46 | const feedContent = getFeedContent() 47 | const [before, after] = feedContent.split(breakDelimiter) 48 | const updatedFeedContent = `${before}${breakDelimiter}${relevantComments}${after}` 49 | overwriteFeedContent(updatedFeedContent) 50 | -------------------------------------------------------------------------------- /scripts/collect-issues.js: -------------------------------------------------------------------------------- 1 | import ghGot from 'gh-got' 2 | import { md2html, buildTitleDate, buildRFC822Date, composeFeedItem, getFeedContent, overwriteFeedContent, getConfig } from '../utils/index.js' 3 | 4 | const { lastCheckTimestamp, breakDelimiter, issuesInScope, commentsPaginationLimit } = getConfig() 5 | 6 | // Collect all the comments for the issues in scope 7 | const comments = await Promise.all(issuesInScope.map(async ({ issue, team }) => { 8 | const issueComments = await ghGot( 9 | `repos/${issue}/comments`, 10 | { 11 | token: process.env.GITHUB_TOKEN, 12 | pagination: { countLimit: commentsPaginationLimit } 13 | } 14 | ).json() 15 | 16 | // Select only comments that are newer than the last check and add issue context 17 | return issueComments 18 | .filter(comment => new Date(comment.updated_at).getTime() > lastCheckTimestamp) 19 | .map(comment => ({ ...comment, issue, team })) 20 | })) 21 | 22 | const relevantComments = comments.flat().map(comment => composeFeedItem({ 23 | title: `${comment.team} update on ${buildTitleDate(comment.created_at)}`, 24 | description: ``, 25 | pubDate: buildRFC822Date(comment.created_at), 26 | link: comment.html_url, 27 | guid: comment.html_url 28 | })).join('') 29 | 30 | const feedContent = getFeedContent() 31 | const [before, after] = feedContent.split(breakDelimiter) 32 | const updatedFeedContent = `${before}${breakDelimiter}${relevantComments}${after}` 33 | overwriteFeedContent(updatedFeedContent) 34 | -------------------------------------------------------------------------------- /scripts/collect-releases.js: -------------------------------------------------------------------------------- 1 | import ghGot from 'gh-got' 2 | import { md2html, buildRFC822Date, composeFeedItem, getFeedContent, overwriteFeedContent, getConfig } from '../utils/index.js' 3 | 4 | const { lastCheckTimestamp, releasePaginationLimit, reposPaginationLimit, breakDelimiter } = getConfig() 5 | 6 | // Collect Org Repos 7 | const repos = await ghGot.paginate.all( 8 | 'users/nodejs/repos', 9 | { 10 | token: process.env.GITHUB_TOKEN, 11 | pagination: { countLimit: reposPaginationLimit } 12 | } 13 | ) 14 | 15 | // Collect New Releases 16 | const releases = await Promise.all(repos.map(async repo => { 17 | const repoReleases = await ghGot( 18 | `repos/${repo.full_name}/releases`, 19 | { 20 | token: process.env.GITHUB_TOKEN, 21 | pagination: { countLimit: releasePaginationLimit } 22 | } 23 | ).json() 24 | 25 | // Select only releases that are newer than the last check and add the repo name 26 | return repoReleases 27 | .filter(rel => new Date(rel.published_at).getTime() > lastCheckTimestamp) 28 | .map(rel => ({ ...rel, repo: repo.full_name })) 29 | })) 30 | 31 | const relevantReleases = releases.flat().map(rel => composeFeedItem({ 32 | title: `Released ${rel.repo} ${rel.tag_name}`, 33 | description: ``, 34 | pubDate: buildRFC822Date(rel.published_at), 35 | link: rel.html_url, 36 | guid: rel.html_url 37 | })).join('') 38 | 39 | const feedContent = getFeedContent() 40 | const [before, after] = feedContent.split(breakDelimiter) 41 | const updatedFeedContent = `${before}${breakDelimiter}${relevantReleases}${after}` 42 | overwriteFeedContent(updatedFeedContent) 43 | -------------------------------------------------------------------------------- /scripts/format-check.js: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process' 2 | import { getFeedHash } from '../utils/index.js' 3 | 4 | const currentHash = getFeedHash() 5 | execSync('npm run rss:format') 6 | const newHash = getFeedHash() 7 | 8 | if (currentHash !== newHash) { 9 | console.log('The feed.xml file is not formatted.') 10 | console.log('Please run rss:format to format the feed.xml file.') 11 | process.exit(1) 12 | } 13 | -------------------------------------------------------------------------------- /scripts/format.js: -------------------------------------------------------------------------------- 1 | import xmlFormat from 'xml-formatter' 2 | import { getFeedContent, overwriteFeedContent } from '../utils/index.js' 3 | 4 | const xml = getFeedContent() 5 | const formattedXml = xmlFormat(xml, { indentation: ' ', collapseContent: true }) 6 | overwriteFeedContent(formattedXml) 7 | -------------------------------------------------------------------------------- /scripts/validate.js: -------------------------------------------------------------------------------- 1 | import got from 'got' 2 | import jsdom from 'jsdom' 3 | import { getFeedContent } from '../utils/index.js' 4 | 5 | const { JSDOM } = jsdom 6 | const xml = getFeedContent() 7 | 8 | try { 9 | const data = await got.post('https://validator.w3.org/feed/check.cgi', { 10 | form: { 11 | rawdata: xml, 12 | manual: 1 13 | } 14 | }).text() 15 | 16 | // Avoid importing CSS in the document 17 | const dom = new JSDOM(data.replace(/@import.*/gm, '')) 18 | 19 | const title = dom.window.document.querySelector('h2').textContent 20 | const recommendations = dom.window.document.querySelector('ul').textContent 21 | 22 | console.log(recommendations) 23 | 24 | if (title === 'Sorry') { 25 | console.log('🚨 Feed is invalid!') 26 | process.exit(1) 27 | } else { 28 | console.log('✅ Feed is valid!') 29 | } 30 | } catch (error) { 31 | console.log('Service is down') 32 | console.error(error.response.statusCode) 33 | } 34 | -------------------------------------------------------------------------------- /utils/index.js: -------------------------------------------------------------------------------- 1 | import { readFileSync, writeFileSync } from 'fs' 2 | import { join } from 'path' 3 | import { createHash } from 'crypto' 4 | import * as remark from 'remark' 5 | import remarkHtml from 'remark-html' 6 | 7 | const xmlFile = join(process.cwd(), 'feed.xml') 8 | const configFile = join(process.cwd(), 'config.json') 9 | 10 | export function md2html (md) { 11 | return remark.remark().use(remarkHtml).processSync(md).toString() 12 | } 13 | 14 | export function buildTitleDate (timestamp) { 15 | const [date, time] = new Date(timestamp).toISOString().split('T') 16 | // Format: YYYY-MM-DD HH:MM:SS 17 | return `${date} ${time.slice(0, 8)}` 18 | } 19 | 20 | export function getConfig () { 21 | return JSON.parse(readFileSync(configFile, 'utf8')) 22 | } 23 | 24 | export function overwriteConfig (config) { 25 | writeFileSync(configFile, JSON.stringify(config, null, 2)) 26 | } 27 | 28 | export function composeFeedItem ({ title, description, pubDate, link, guid }) { 29 | return ` 30 | 31 | ${title} 32 | ${description} 33 | ${pubDate} 34 | ${link} 35 | ${guid} 36 | 37 | ` 38 | } 39 | 40 | export function getFeedContent () { 41 | return readFileSync(xmlFile, 'utf8') 42 | } 43 | 44 | export function overwriteFeedContent (content) { 45 | writeFileSync(xmlFile, content) 46 | } 47 | 48 | export function getFeedHash () { 49 | const xml = getFeedContent() 50 | return createHash('sha256').update(xml).digest('hex') 51 | } 52 | 53 | // @see: https://whitep4nth3r.com/blog/how-to-format-dates-for-rss-feeds-rfc-822/ 54 | export function addLeadingZero (num) { 55 | num = num.toString() 56 | while (num.length < 2) num = '0' + num 57 | return num 58 | } 59 | 60 | export function buildRFC822Date (dateString) { 61 | const dayStrings = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] 62 | const monthStrings = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] 63 | 64 | const timeStamp = Date.parse(dateString) 65 | const date = new Date(timeStamp) 66 | 67 | const day = dayStrings[date.getDay()] 68 | const dayNumber = addLeadingZero(date.getDate()) 69 | const month = monthStrings[date.getMonth()] 70 | const year = date.getFullYear() 71 | const time = `${addLeadingZero(date.getHours())}:${addLeadingZero(date.getMinutes())}:00` 72 | const timezone = date.getTimezoneOffset() === 0 ? 'GMT' : 'BST' 73 | 74 | // Wed, 02 Oct 2002 13:00:00 GMT 75 | return `${day}, ${dayNumber} ${month} ${year} ${time} ${timezone}` 76 | } 77 | --------------------------------------------------------------------------------