Compare commits

..

1 commit

Author SHA1 Message Date
e56faa2082 Update dependency ts-jest to v29.2.3
All checks were successful
Test / build (push) Successful in 7s
2024-07-21 23:03:09 +00:00
22 changed files with 696 additions and 627 deletions

1
.eslintignore Normal file
View file

@ -0,0 +1 @@
dist/

50
.eslintrc Normal file
View file

@ -0,0 +1,50 @@
{
"parserOptions": {
"ecmaVersion": 6
},
"extends": [
"eslint:recommended"
],
"rules": {
"camelcase": "error",
"brace-style": [
"error",
"1tbs"
],
"comma-dangle": [
"error",
"never"
],
"comma-spacing": [
"error",
{
"before": false,
"after": true
}
],
"comma-style": [
"error",
"last"
],
"arrow-body-style": [
"error",
"as-needed"
],
"arrow-parens": [
"error",
"as-needed"
],
"arrow-spacing": "error",
"no-var": "error",
"prefer-template": "error",
"prefer-const": "error"
},
"globals": {
"exports": "writable",
"module": "writable",
"require": "writable",
"process": "writable",
"console": "writable",
"jest": "writable"
}
}

View file

@ -13,7 +13,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v3
with: with:
node-version: 20.x node-version: 20.x
- run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile
@ -26,7 +26,7 @@ jobs:
runs-on: node runs-on: node
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v3
with: with:
node-version: 20.x node-version: 20.x
- run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile

View file

@ -17,7 +17,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v3
with: with:
node-version: 20.x node-version: 20.x
- run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile

View file

@ -4,7 +4,7 @@ Since Version 2.2, Random Bunny contains a command line interface (CLI).
## Downloads ## Downloads
The project can be downloaded as a binary for your system via the [GitHub Releases](https://github.com/Vylpes/random-bunny/releases) or [Forgejo Releases](https://git.vylpes.xyz/RabbitLabs/random-bunny/releases) page. The project can be downloaded as a binary for your system via the [GitHub Releases](https://github.com/Vylpes/random-bunny/releases) or [Gitea Releases](https://gitea.vylpes.xyz/RabbitLabs/random-bunny/releases) page.
We currently support: We currently support:
- Linux (x64) - Linux (x64)
@ -13,8 +13,6 @@ We currently support:
The git repository can also be cloned and ran via `yarn build` and `yarn start`. The git repository can also be cloned and ran via `yarn build` and `yarn start`.
You can produce the binary using the `yarn package` command. This creates the binaries in the `./bin` folder.
> **NOTE:** We are aware of a bug in the macOS Arm64 builds failing to execute. For now you're still able to use the x64 builds under Rosetta fine. This will hopefully be fixed in a future release. > **NOTE:** We are aware of a bug in the macOS Arm64 builds failing to execute. For now you're still able to use the x64 builds under Rosetta fine. This will hopefully be fixed in a future release.
## Default Output ## Default Output
@ -22,7 +20,7 @@ You can produce the binary using the `yarn package` command. This creates the bi
By default, the command will fetch a random image from `r/rabbits` and return it in a human-readable output. By default, the command will fetch a random image from `r/rabbits` and return it in a human-readable output.
``` ```
$ random-bunny $ randombunny
Archived = false Archived = false
Downvotes = 0 Downvotes = 0
@ -40,11 +38,11 @@ Url = https://i.redd.it/sfz0srdrimjc1.png
The command also includes a help option in case you are stuck. The command also includes a help option in case you are stuck.
``` ```
$ random-bunny --help $ randombunny --help
# or # or
$ random-bunny -h $ randombunny -h
Usage: random-bunny [options] Usage: random-bunny [options]
@ -57,7 +55,6 @@ Options:
-q, --query-metadata Include query metadata in result -q, --query-metadata Include query metadata in result
-o <file> Output to file -o <file> Output to file
--sort <sort> Sort by (choices: "hot", "new", "top", default: "hot") --sort <sort> Sort by (choices: "hot", "new", "top", default: "hot")
--limit <limit> The amount of posts to fetch from the reddit api (default: 100)
-h, --help display help for command -h, --help display help for command
``` ```
@ -66,11 +63,11 @@ Options:
You can also convert the output into JSON, if you need to input it to another program. You can also convert the output into JSON, if you need to input it to another program.
```bash ```bash
$ random-bunny --json $ randombunny --json
# or # or
$ randon-bunny -j $ randonbunny -j
{"Archived":false,"Downs":0,"Hidden":false,"Permalink":"/r/Rabbits/comments/1av1rg9/cute_baby_bun/","Subreddit":"Rabbits","SubredditSubscribers":486085,"Title":"Cute baby bun","Ups":210,"Url":"https://i.redd.it/sfz0srdrimjc1.png"} {"Archived":false,"Downs":0,"Hidden":false,"Permalink":"/r/Rabbits/comments/1av1rg9/cute_baby_bun/","Subreddit":"Rabbits","SubredditSubscribers":486085,"Title":"Cute baby bun","Ups":210,"Url":"https://i.redd.it/sfz0srdrimjc1.png"}
``` ```
@ -82,9 +79,9 @@ You can also choose the sorting option which reddit will use to return the avail
This defaults to "hot". The valid options are "hot", "new", and "top". This defaults to "hot". The valid options are "hot", "new", and "top".
``` ```
$ random-bunny --sort hot $ randombunny --sort hot
$ random-bunny --sort new $ randombunny --sort new
$ random-bunny --sort top $ randomBunny --sort top
``` ```
@ -95,8 +92,8 @@ You can change the subreddit which the command fetches from.
This defaults to "rabbits" This defaults to "rabbits"
``` ```
$ random-bunny --subreddit rabbits $ randombunny --subreddit rabbits
$ random-bunny -s horses $ randombunny -s horses
``` ```
## Output to file ## Output to file
@ -106,17 +103,3 @@ If you'd rather send the output to a file, you can supply the `-o` flag.
``` ```
$ randombunny -o ~/Desktop/output.txt $ randombunny -o ~/Desktop/output.txt
``` ```
## Reddit API Return Limits
You can also limit the amount the posts the script requests from the Reddit API
using the `--limit` option.
This defaults to 100. This accepts any number between 1 and 100.
Please note limiting the calls to less than 100 will give a higher chance of
the script not finding any valid image post to return.
```
$ random-bunny --limit 50
```

View file

@ -1,54 +0,0 @@
import js from "@eslint/js";
import ts from "typescript-eslint";
export default [
{
ignores: [
"**/dist/",
"eslint.config.mjs",
"jest.config.cjs",
"jest.setup.js"
],
},
js.configs.recommended,
...ts.configs.recommended,
{
languageOptions: {
globals: {
exports: "writable",
module: "writable",
require: "writable",
process: "writable",
console: "writable",
jest: "writable",
},
ecmaVersion: 6,
sourceType: "script",
},
files: [
"./src",
"./tests"
],
rules: {
camelcase: "error",
"brace-style": ["error", "1tbs"],
"comma-dangle": ["error", "never"],
"comma-spacing": ["error", {
before: false,
after: true,
}],
"comma-style": ["error", "last"],
"arrow-body-style": ["error", "as-needed"],
"arrow-parens": ["error", "as-needed"],
"arrow-spacing": "error",
"no-var": "error",
"prefer-template": "error",
"prefer-const": "error",
},
}
];

View file

@ -39,22 +39,19 @@
"homepage": "https://gitea.vylpes.xyz/RabbitLabs/random-bunny", "homepage": "https://gitea.vylpes.xyz/RabbitLabs/random-bunny",
"funding": "https://ko-fi.com/vylpes", "funding": "https://ko-fi.com/vylpes",
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.1.0", "@types/eslint": "^8.21.1",
"@eslint/js": "^9.7.0",
"@types/eslint": "^9.6.0",
"@types/jest": "^29.5.8", "@types/jest": "^29.5.8",
"@types/node": "^20.0.0", "@types/node": "^20.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0", "@typescript-eslint/parser": "^7.0.0",
"@yao-pkg/pkg": "^5.12.0", "eslint": "^8.49.0",
"eslint": "^9.7.0",
"jest": "^29.7.0", "jest": "^29.7.0",
"jest-mock-extended": "^3.0.3", "jest-mock-extended": "^3.0.3",
"np": "^10.0.0", "np": "^10.0.0",
"pkg": "^5.8.1",
"ts-jest": "^29.1.1", "ts-jest": "^29.1.1",
"ts-mockito": "^2.6.1", "ts-mockito": "^2.6.1",
"typescript": "^5.0.0", "typescript": "^5.0.0"
"typescript-eslint": "^7.17.0"
}, },
"resolutions": { "resolutions": {
"np/**/got": "^14.0.0", "np/**/got": "^14.0.0",

View file

@ -33,7 +33,7 @@ console.log(result);
### `randomBunny()` ### `randomBunny()`
Returns a `json string` for a random post. Accepts 3 arguments: `subreddit`, `sortby` ('new', 'hot', 'top'), and `limit` (1-100, default 100) Returns a `json string` for a random post. Accepts 2 arguments: `subreddit`, and `sortby` ('new', 'hot', 'top')
The json string which gets returned consists of: The json string which gets returned consists of:
- archived - archived

View file

@ -1,5 +1,4 @@
{ {
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"baseBranches": ["develop"], "baseBranches": ["develop"]
"labels": ["type/dependencies"]
} }

View file

@ -14,12 +14,11 @@ program
.option('-j, --json', 'Output as JSON') .option('-j, --json', 'Output as JSON')
.option('-q, --query-metadata', 'Include query metadata in result') .option('-q, --query-metadata', 'Include query metadata in result')
.option('-o <file>', 'Output to file') .option('-o <file>', 'Output to file')
.addOption(new Option('--sort <sort>', 'Sort by').default('hot').choices(['hot', 'new', 'top'])) .addOption(new Option('--sort <sort>', 'Sort by').default('hot').choices(['hot', 'new', 'top']));
.addOption(new Option('--limit <limit>', 'The amount of posts to fetch from the reddit api').default(100));
program.parse(); program.parse();
const options: ICliOptions = program.opts(); const options: ICliOptions = program.opts();
randomBunny(options.subreddit, options.sort, options.limit) randomBunny(options.subreddit, options.sort)
.then((response) => exit(CliHelper.Endpoint(response, options))); .then((response) => exit(CliHelper.Endpoint(response, options)));

View file

@ -3,5 +3,4 @@ export enum ErrorCode {
FailedToFetchReddit, FailedToFetchReddit,
UnableToParseJSON, UnableToParseJSON,
NoImageResultsFound, NoImageResultsFound,
LimitOutOfRange,
} }

View file

@ -2,5 +2,4 @@ export default class ErrorMessages {
public static readonly FailedToFetchReddit = "Failed to fetch result from Reddit"; public static readonly FailedToFetchReddit = "Failed to fetch result from Reddit";
public static readonly UnableToParseJSON = "Unable to parse the JSON result"; public static readonly UnableToParseJSON = "Unable to parse the JSON result";
public static readonly NoImageResultsFound = "No image results found in response from Reddit"; public static readonly NoImageResultsFound = "No image results found in response from Reddit";
public static readonly LimitOutOfRange = "Limit must be a number between 1 and 100";
} }

View file

@ -3,6 +3,5 @@ export default interface ICliOptions {
json?: boolean, json?: boolean,
sort: "new" | "hot" | "top", sort: "new" | "hot" | "top",
o?: string, o?: string,
limit: number,
queryMetadata?: boolean, queryMetadata?: boolean,
} }

View file

@ -1,5 +1,4 @@
export default interface QueryResult { export default interface QueryResult {
subreddit: string, subreddit: string,
sortBy: string, sortBy: string,
limit: number,
} }

View file

@ -9,7 +9,7 @@ export default class CliHelper {
const output = OutputHelper.GenerateOutput(response, options); const output = OutputHelper.GenerateOutput(response, options);
if (options.o) { if (options.o) {
writeFileSync(options.o, `${output}\n`); writeFileSync(options.o, output);
} else { } else {
console.log(output); console.log(output);
} }

View file

@ -24,7 +24,6 @@ export default class OutputHelper {
if (options.queryMetadata != null) { if (options.queryMetadata != null) {
outputLines.push(`Query.Subreddit = ${response.Query.subreddit}`); outputLines.push(`Query.Subreddit = ${response.Query.subreddit}`);
outputLines.push(`Query.Sort By = ${response.Query.sortBy}`); outputLines.push(`Query.Sort By = ${response.Query.sortBy}`);
outputLines.push(`Query.Limit = ${response.Query.limit}`);
} }
return outputLines.join("\n"); return outputLines.join("\n");

View file

@ -7,23 +7,8 @@ import { ErrorCode } from "./constants/ErrorCode";
import ErrorMessages from "./constants/ErrorMessages"; import ErrorMessages from "./constants/ErrorMessages";
import ImageHelper from "./helpers/imageHelper"; import ImageHelper from "./helpers/imageHelper";
export default async function randomBunny(subreddit: string, sortBy: "new" | "hot" | "top" = 'hot', limit: number = 100): Promise<IReturnResult> { export default async function randomBunny(subreddit: string, sortBy: "new" | "hot" | "top" = 'hot'): Promise<IReturnResult> {
if (limit < 1 || limit > 100) { const result = await fetch(`https://reddit.com/r/${subreddit}/${sortBy}.json?limit=100`)
return {
IsSuccess: false,
Query: {
subreddit: subreddit,
sortBy: sortBy,
limit: limit,
},
Error: {
Code: ErrorCode.LimitOutOfRange,
Message: ErrorMessages.LimitOutOfRange,
}
};
}
const result = await fetch(`https://reddit.com/r/${subreddit}/${sortBy}.json?limit=${limit}`)
.then((res) => { .then((res) => {
return res; return res;
}) })
@ -37,7 +22,6 @@ export default async function randomBunny(subreddit: string, sortBy: "new" | "ho
Query: { Query: {
subreddit: subreddit, subreddit: subreddit,
sortBy: sortBy, sortBy: sortBy,
limit: limit,
}, },
Error: { Error: {
Code: ErrorCode.FailedToFetchReddit, Code: ErrorCode.FailedToFetchReddit,
@ -54,7 +38,6 @@ export default async function randomBunny(subreddit: string, sortBy: "new" | "ho
Query: { Query: {
subreddit: subreddit, subreddit: subreddit,
sortBy: sortBy, sortBy: sortBy,
limit: limit,
}, },
Error: { Error: {
Code: ErrorCode.UnableToParseJSON, Code: ErrorCode.UnableToParseJSON,
@ -77,7 +60,6 @@ export default async function randomBunny(subreddit: string, sortBy: "new" | "ho
Query: { Query: {
subreddit: subreddit, subreddit: subreddit,
sortBy: sortBy, sortBy: sortBy,
limit: limit,
}, },
Error: { Error: {
Code: ErrorCode.NoImageResultsFound, Code: ErrorCode.NoImageResultsFound,
@ -103,7 +85,6 @@ export default async function randomBunny(subreddit: string, sortBy: "new" | "ho
Query: { Query: {
subreddit: subreddit, subreddit: subreddit,
sortBy: sortBy, sortBy: sortBy,
limit: limit,
}, },
Error: { Error: {
Code: ErrorCode.NoImageResultsFound, Code: ErrorCode.NoImageResultsFound,
@ -134,7 +115,6 @@ export default async function randomBunny(subreddit: string, sortBy: "new" | "ho
Query: { Query: {
subreddit: subreddit, subreddit: subreddit,
sortBy: sortBy, sortBy: sortBy,
limit: limit,
}, },
Result: redditResult Result: redditResult
}; };

View file

@ -25,6 +25,5 @@ Title = This is my Ms Bear!
Upvotes = 17 Upvotes = 17
Url = https://preview.redd.it/d5yno653zf7d1.jpg?width=640&crop=smart&auto=webp&s=5064d1caec3c12ac2855eb57ff131d0b313d5e9d Url = https://preview.redd.it/d5yno653zf7d1.jpg?width=640&crop=smart&auto=webp&s=5064d1caec3c12ac2855eb57ff131d0b313d5e9d
Query.Subreddit = rabbits Query.Subreddit = rabbits
Query.Sort By = hot Query.Sort By = hot"
Query.Limit = 100"
`; `;

View file

@ -35,7 +35,7 @@ describe("Endpoint", () => {
expect(OutputHelper.GenerateOutput).toHaveBeenCalledWith(response, options); expect(OutputHelper.GenerateOutput).toHaveBeenCalledWith(response, options);
expect(fs.writeFileSync).toHaveBeenCalledTimes(1); expect(fs.writeFileSync).toHaveBeenCalledTimes(1);
expect(fs.writeFileSync).toHaveBeenCalledWith("file.txt", "test output\n"); expect(fs.writeFileSync).toHaveBeenCalledWith("file.txt", "test output");
expect(console.log).not.toHaveBeenCalled(); expect(console.log).not.toHaveBeenCalled();

View file

@ -10,7 +10,6 @@ describe("GenerateOutput", () => {
Query: { Query: {
subreddit: "rabbits", subreddit: "rabbits",
sortBy: "hot", sortBy: "hot",
limit: 100,
}, },
Result: { Result: {
Archived: false, Archived: false,
@ -41,7 +40,6 @@ describe("GenerateOutput", () => {
Query: { Query: {
subreddit: "rabbits", subreddit: "rabbits",
sortBy: "hot", sortBy: "hot",
limit: 100,
}, },
Result: { Result: {
Archived: false, Archived: false,
@ -74,7 +72,6 @@ describe("GenerateOutput", () => {
Query: { Query: {
subreddit: "rabbits", subreddit: "rabbits",
sortBy: "hot", sortBy: "hot",
limit: 100,
}, },
Result: { Result: {
Archived: false, Archived: false,

View file

@ -7,10 +7,6 @@ import fetch from "got-cjs";
jest.mock('got-cjs'); jest.mock('got-cjs');
const fetchMock = jest.mocked(fetch); const fetchMock = jest.mocked(fetch);
beforeEach(() => {
fetchMock.mockReset();
});
describe('randomBunny', () => { describe('randomBunny', () => {
test('GIVEN subreddit AND sortBy is supplied, EXPECT successful result', async() => { test('GIVEN subreddit AND sortBy is supplied, EXPECT successful result', async() => {
fetchMock.mockResolvedValue({ fetchMock.mockResolvedValue({
@ -126,7 +122,7 @@ describe('randomBunny', () => {
expect(result.Error!.Code).toBe(ErrorCode.NoImageResultsFound); expect(result.Error!.Code).toBe(ErrorCode.NoImageResultsFound);
expect(result.Error!.Message).toBe(ErrorMessages.NoImageResultsFound); expect(result.Error!.Message).toBe(ErrorMessages.NoImageResultsFound);
expect(fetchMock).toHaveBeenCalledWith('https://reddit.com/r/rabbits/new.json?limit=100'); expect(fetchMock).toBeCalledWith('https://reddit.com/r/rabbits/new.json?limit=100');
}); });
test('GIVEN randomSelect does NOT find a valid response, EXPECT failure result', async () => { test('GIVEN randomSelect does NOT find a valid response, EXPECT failure result', async () => {
@ -235,106 +231,4 @@ describe('randomBunny', () => {
expect(result.Error?.Code).toBe(ErrorCode.NoImageResultsFound); expect(result.Error?.Code).toBe(ErrorCode.NoImageResultsFound);
expect(result.Error?.Message).toBe(ErrorMessages.NoImageResultsFound); expect(result.Error?.Message).toBe(ErrorMessages.NoImageResultsFound);
}); });
test("GIVEN limit is supplied, EXPECT limit sent to the API", async () => {
fetchMock.mockResolvedValue({
body: JSON.stringify({
data: {
children: [
{
data: {
archived: false,
downs: 0,
hidden: false,
permalink: '/r/Rabbits/comments/12pa5te/someone_told_pickles_its_monday_internal_fury/',
subreddit: 'Rabbits',
subreddit_subscribers: 298713,
title: 'Someone told pickles its Monday… *internal fury*',
ups: 1208,
url: 'https://i.redd.it/cr8xudsnkgua1.jpg',
},
},
],
}
}),
});
const result = await randomBunny('rabbits', 'new', 50);
expect(result.IsSuccess).toBeTruthy();
expect(result.Result).toBeDefined();
expect(result.Error).toBeUndefined();
expect(fetchMock).toHaveBeenCalledWith('https://reddit.com/r/rabbits/new.json?limit=50');
});
test("GIVEN limit is less than 1, EXPECT error to be returned", async () => {
fetchMock.mockResolvedValue({
body: JSON.stringify({
data: {
children: [
{
data: {
archived: false,
downs: 0,
hidden: false,
permalink: '/r/Rabbits/comments/12pa5te/someone_told_pickles_its_monday_internal_fury/',
subreddit: 'Rabbits',
subreddit_subscribers: 298713,
title: 'Someone told pickles its Monday… *internal fury*',
ups: 1208,
url: 'https://i.redd.it/cr8xudsnkgua1.jpg',
},
},
],
}
}),
});
const result = await randomBunny('rabbits', 'new', 0);
expect(result.IsSuccess).toBeFalsy();
expect(result.Result).toBeUndefined();
expect(result.Error).toBeDefined();
expect(result.Error!.Code).toBe(ErrorCode.LimitOutOfRange);
expect(result.Error!.Message).toBe(ErrorMessages.LimitOutOfRange);
expect(fetchMock).not.toHaveBeenCalled();
});
test("GIVEN limit is greater than 100, EXPECT error to be returned", async () => {
fetchMock.mockResolvedValue({
body: JSON.stringify({
data: {
children: [
{
data: {
archived: false,
downs: 0,
hidden: false,
permalink: '/r/Rabbits/comments/12pa5te/someone_told_pickles_its_monday_internal_fury/',
subreddit: 'Rabbits',
subreddit_subscribers: 298713,
title: 'Someone told pickles its Monday… *internal fury*',
ups: 1208,
url: 'https://i.redd.it/cr8xudsnkgua1.jpg',
},
},
],
}
}),
});
const result = await randomBunny('rabbits', 'new', 101);
expect(result.IsSuccess).toBeFalsy();
expect(result.Result).toBeUndefined();
expect(result.Error).toBeDefined();
expect(result.Error!.Code).toBe(ErrorCode.LimitOutOfRange);
expect(result.Error!.Message).toBe(ErrorMessages.LimitOutOfRange);
expect(fetchMock).not.toHaveBeenCalled();
});
}); });

1005
yarn.lock

File diff suppressed because it is too large Load diff