From dcccd326fc071a88c6fe94e862404c82ffd0021b Mon Sep 17 00:00:00 2001 From: Tierney Cyren Date: Fri, 8 Nov 2024 22:20:37 +0000 Subject: [PATCH 1/5] feat: first pass at @nodevu/opt Signed-off-by: Tierney Cyren --- opt/LICENSE | 21 ++++++++++++++ opt/README.md | 34 ++++++++++++++++++++++ opt/biome.json | 17 +++++++++++ opt/index.js | 44 ++++++++++++++++++++++++++++ opt/package.json | 32 +++++++++++++++++++++ opt/test/test.js | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- 7 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 opt/LICENSE create mode 100644 opt/README.md create mode 100644 opt/biome.json create mode 100644 opt/index.js create mode 100644 opt/package.json create mode 100644 opt/test/test.js diff --git a/opt/LICENSE b/opt/LICENSE new file mode 100644 index 00000000..b8e356ab --- /dev/null +++ b/opt/LICENSE @@ -0,0 +1,21 @@ +MIT License Copyright (c) 2022 Tierney Cyren + +Permission is hereby granted, free +of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice +(including the next paragraph) shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/opt/README.md b/opt/README.md new file mode 100644 index 00000000..bf53c3cd --- /dev/null +++ b/opt/README.md @@ -0,0 +1,34 @@ +# @nodevu/optionsparser + +A tool that fetches the /dist/index.json file from the Node.js website. + +## Usage + +```js +const opt = require('@nodevu/opt') + +const parsedOptions = await parser(); // returns a huge JSON object +``` + +```js +const opt = require('@nodevu/opt') + +const options = { + fetch: globalThis.fetch, // use your own fetch if you want! + urls: { + index: 'https://nodejs.org/dist/index.json', + }, +}; + +const parsedOptions = await parser(options); // returns a huge JSON object +``` + +## API +- `opt(options)` + - `options` (object): Options object. + - `fetch` (function): Fetch function. Default: `globalThis.fetch`. + - `urls` (object): URLs object. + - `index` (string): URL to fetch the index.json file from. Default: `'https://nodejs.org/dist/index.json'`. + - `schedule` (string): URL to fetch the schedule.json file from. Default: `'https://raw.githubusercontent.com/nodejs/Release/master/schedule.json'`. + - `accept` (array): Array of strings that represent the accepted versions. Default: `['lts', 'current']`. + - Returns: Promise that resolves with the fetched `index.json` object. \ No newline at end of file diff --git a/opt/biome.json b/opt/biome.json new file mode 100644 index 00000000..3a7b021c --- /dev/null +++ b/opt/biome.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.6.1/schema.json", + "organizeImports": { + "enabled": true + }, + "javascript": { + "formatter": { + "quoteStyle": "single" + } + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + } +} diff --git a/opt/index.js b/opt/index.js new file mode 100644 index 00000000..a72426f3 --- /dev/null +++ b/opt/index.js @@ -0,0 +1,44 @@ +const { DateTime } = require('luxon'); + +// this function allows us to parse user-passed options. +// +// this is particularly useful for tests so we can reduce variables +// and ensure that our test suite is able to be consistent. +function opt(inputOptions) { + // set up our defaults + const result = { + fetch: globalThis.fetch, + now: DateTime.now(), + urls: { + index: 'https://nodejs.org/dist/index.json', + schedule: + 'https://raw.githubusercontent.com/nodejs/Release/master/schedule.json', + }, + }; + + if (typeof inputOptions === 'undefined') { + return result + } + + // allow the end-user to replace our fetch implementation with another one they prefer. + if (inputOptions?.fetch) { + result.fetch = inputOptions.fetch; + } + + // allow the end-user to provide a custom DateTime. This is particularly useful for tests. + if (inputOptions?.now) { + result.now = inputOptions.now; + } + + if (inputOptions?.urls?.index) { + result.urls.index = inputOptions.urls.index; + } + + if (inputOptions?.urls?.schedule) { + result.urls.schedule = inputOptions.urls.schedule; + } + + return result; +} + +module.exports = opt; diff --git a/opt/package.json b/opt/package.json new file mode 100644 index 00000000..aaaa803e --- /dev/null +++ b/opt/package.json @@ -0,0 +1,32 @@ +{ + "name": "@nodevu/opt", + "version": "0.1.0", + "description": "internal options parser for @nodevu packages.", + "main": "index.js", + "files": ["index.js", "LICENSE"], + "scripts": { + "lint": "biome check ./", + "lint:write": "biome check ./ --write", + "test": "node --test", + "coverage": "c8 node --test", + "updates:check": "npx npm-check-updates", + "updates:update": "npx npm-check-updates -u" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/cutenode/nodevu.git" + }, + "keywords": ["node.js", "versions"], + "author": "Tierney Cyren (https://bnb.im/)", + "license": "MIT", + "bugs": { + "url": "https://github.com/cutenode/nodevu/issues" + }, + "homepage": "https://github.com/cutenode/nodevu#readme", + "devDependencies": { + "@biomejs/biome": "1.9.4", + "c8": "^10.1.2", + "luxon": "^3.5.0", + "undici": "^6.20.1" + } +} diff --git a/opt/test/test.js b/opt/test/test.js new file mode 100644 index 00000000..faf82564 --- /dev/null +++ b/opt/test/test.js @@ -0,0 +1,74 @@ +const { deepStrictEqual } = require('node:assert'); +const { describe, it, beforeEach } = require('node:test'); +const { fetch: undiciFetch } = require('undici'); +const { DateTime } = require('luxon'); +const nodevu = require('@nodevu/core'); +const opt = require('../index'); + +describe('the parseOptions module should return all correct defaults', async () => { + it('should return the default date', async () => { + const now = DateTime.now(); + const defaultParsedOptions = opt(); + deepStrictEqual(defaultParsedOptions.now.day, now.day); + deepStrictEqual(defaultParsedOptions.now.hour, now.hour); + deepStrictEqual(defaultParsedOptions.now.minute, now.minute); + deepStrictEqual(defaultParsedOptions.now.month, now.month); + }); + + it('should return the default date, when options is an empty object', async () => { + const now = DateTime.now(); + const defaultParsedOptions = opt({}); + deepStrictEqual(defaultParsedOptions.now.day, now.day); + deepStrictEqual(defaultParsedOptions.now.hour, now.hour); + deepStrictEqual(defaultParsedOptions.now.minute, now.minute); + deepStrictEqual(defaultParsedOptions.now.month, now.month); + }); + + it('defaultParsedOptions.fetch should be globalThis.fetch when no options are passed', async () => { + const defaultParsedOptions = opt(); + deepStrictEqual(defaultParsedOptions.fetch, globalThis.fetch); + }); + + it('should return the origin index.json for url.index', async () => { + const defaultParsedOptions = opt(); + deepStrictEqual( + defaultParsedOptions.urls.index, + 'https://nodejs.org/dist/index.json', + ); + }); + + it('should return the origin schedule.json for url.schedule', async () => { + const defaultParsedOptions = opt(); + deepStrictEqual( + defaultParsedOptions.urls.schedule, + 'https://raw.githubusercontent.com/nodejs/Release/master/schedule.json', + ); + }); +}); + +describe('the parseOptions module should still work when defaults are changed', async () => { + it('should still work when a custom date is passed', async () => { + const currentNow = DateTime.now(); + const defaultParsedOptions = opt({ now: currentNow }); + deepStrictEqual(defaultParsedOptions.now, currentNow); + }); + + it('defaultParsedOptions.fetch should be globalThis.fetch when no options are passed', async () => { + const defaultParsedOptions = opt({ fetch: undiciFetch }); + deepStrictEqual(defaultParsedOptions.fetch, undiciFetch); + }); + + it('should return the origin index.json for url.index', async () => { + const defaultParsedOptions = opt({ + urls: { index: 'https://example.com' }, + }); + deepStrictEqual(defaultParsedOptions.urls.index, 'https://example.com'); + }); + + it('should return the origin schedule.json for url.schedule', async () => { + const defaultParsedOptions = opt({ + urls: { schedule: 'https://example.com' }, + }); + deepStrictEqual(defaultParsedOptions.urls.schedule, 'https://example.com'); + }); +}); diff --git a/package.json b/package.json index 2998c23b..ec795610 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "ranges", "aliases", "translate", - "fetchindex" + "fetchindex", + "opt" ] } From 006f853a16869ac2511f99ef11a6d28b851a89e2 Mon Sep 17 00:00:00 2001 From: Tierney Cyren Date: Tue, 19 Nov 2024 11:51:48 -0500 Subject: [PATCH 2/5] fix: linter issue in @nodevu/opt Signed-off-by: Tierney Cyren --- opt/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opt/index.js b/opt/index.js index a72426f3..a28c0d03 100644 --- a/opt/index.js +++ b/opt/index.js @@ -17,7 +17,7 @@ function opt(inputOptions) { }; if (typeof inputOptions === 'undefined') { - return result + return result; } // allow the end-user to replace our fetch implementation with another one they prefer. From 7f200053fcfe7cdc0bbf8a3f02f0eafa064a9819 Mon Sep 17 00:00:00 2001 From: Tierney Cyren Date: Tue, 19 Nov 2024 11:53:57 -0500 Subject: [PATCH 3/5] ci: add linter and tests for opt Signed-off-by: Tierney Cyren --- .github/workflows/lint-opt.yml | 27 +++++++++++++++++++++++ .github/workflows/tests-core copy.yml | 31 +++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 .github/workflows/lint-opt.yml create mode 100644 .github/workflows/tests-core copy.yml diff --git a/.github/workflows/lint-opt.yml b/.github/workflows/lint-opt.yml new file mode 100644 index 00000000..eb453a45 --- /dev/null +++ b/.github/workflows/lint-opt.yml @@ -0,0 +1,27 @@ +name: "Test Suite: Linter (@nodevu/opt)" + +on: + push: + pull_request: + paths: + - 'opt/**' + branches: + - main + workflow_dispatch: + workflow_call: + +jobs: + tests: + if: github.repository == 'cutenode/nodevu' + runs-on: ubuntu-latest + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: current + - name: Run npm install -w opt + run: npm install -w opt + - name: Run npm run lint -w opt + run: npm run lint -w opt diff --git a/.github/workflows/tests-core copy.yml b/.github/workflows/tests-core copy.yml new file mode 100644 index 00000000..57866120 --- /dev/null +++ b/.github/workflows/tests-core copy.yml @@ -0,0 +1,31 @@ +name: "Test Suite: @nodevu/opt" + +on: + pull_request: + paths: + - 'opt/**' + branches: + - main + workflow_dispatch: + workflow_call: + +jobs: + tests: + if: github.repository == 'cutenode/nodevu' + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [current, lts/*, lts/-1] + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + - name: Install most recent npm + run: npm install -g npm + - name: Run npm install -w opt + run: npm install -w opt + - name: Run npm test -w opt + run: npm test -w opt From 17547246768beabbd7cbdfbb008012bd78f6f8c8 Mon Sep 17 00:00:00 2001 From: Tierney Cyren Date: Tue, 19 Nov 2024 11:57:00 -0500 Subject: [PATCH 4/5] test: remove unnecessary requires from @nodevu/opt Signed-off-by: Tierney Cyren --- opt/test/test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/opt/test/test.js b/opt/test/test.js index faf82564..0b975153 100644 --- a/opt/test/test.js +++ b/opt/test/test.js @@ -1,8 +1,7 @@ const { deepStrictEqual } = require('node:assert'); -const { describe, it, beforeEach } = require('node:test'); +const { describe, it } = require('node:test'); const { fetch: undiciFetch } = require('undici'); const { DateTime } = require('luxon'); -const nodevu = require('@nodevu/core'); const opt = require('../index'); describe('the parseOptions module should return all correct defaults', async () => { From 6adc62a25bd2dac556ffdfba1af92e4c03f39361 Mon Sep 17 00:00:00 2001 From: Tierney Cyren Date: Tue, 19 Nov 2024 12:01:30 -0500 Subject: [PATCH 5/5] doc: update @nodevu/opt README Signed-off-by: Tierney Cyren --- opt/README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/opt/README.md b/opt/README.md index bf53c3cd..9e491f57 100644 --- a/opt/README.md +++ b/opt/README.md @@ -7,7 +7,7 @@ A tool that fetches the /dist/index.json file from the Node.js website. ```js const opt = require('@nodevu/opt') -const parsedOptions = await parser(); // returns a huge JSON object +const parsedOptions = await opt(); // returns a default set of options ``` ```js @@ -25,10 +25,9 @@ const parsedOptions = await parser(options); // returns a huge JSON object ## API - `opt(options)` - - `options` (object): Options object. - - `fetch` (function): Fetch function. Default: `globalThis.fetch`. - - `urls` (object): URLs object. - - `index` (string): URL to fetch the index.json file from. Default: `'https://nodejs.org/dist/index.json'`. - - `schedule` (string): URL to fetch the schedule.json file from. Default: `'https://raw.githubusercontent.com/nodejs/Release/master/schedule.json'`. - - `accept` (array): Array of strings that represent the accepted versions. Default: `['lts', 'current']`. - - Returns: Promise that resolves with the fetched `index.json` object. \ No newline at end of file + - `options` (`Object`, optional): Options object. + - `fetch` (`Function`, optional): Fetch function. Default: `globalThis.fetch`. + - `urls` (`Object`, optional): URLs object. + - `index` (`String`, optional): URL to fetch the index.json file from. Default: `'https://nodejs.org/dist/index.json'`. + - `schedule` (`String`, optional): URL to fetch the schedule.json file from. Default: `'https://raw.githubusercontent.com/nodejs/Release/master/schedule.json'`. + - Returns: `Object` with a set of default options in the structure required by `@nodevu/core`. \ No newline at end of file