Skip to content

set inputTransform during initialization and better typing for transformed inputs #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ npm i --save advent-of-code-client

## How to use

Initializing the client:
**Initializing the client:**

```javascript
import { AocClient } from 'advent-of-code-client';
Expand All @@ -22,7 +22,7 @@ const client = new AocClient({
});
```

Fetching the puzzle input:
**Fetching the puzzle input:**

```javascript
const input = await client.getInput();
Expand Down Expand Up @@ -51,26 +51,31 @@ const part2 = (input) => {
await client.run([part1, part2], true);
```

Transforming inputs before they are returned from `.getInput()`. This can be especially useful if you are running your puzzle parts automatically. When using the `.setInputTransform(transform)` method, the input to each part function will be the transformed / parsed data.
**Transforming inputs before they are returned from `.getInput()`:**

This can be especially useful if you are running your puzzle parts automatically. When using the `inputTransform` option when creating the client, the input passed to each part function will be the transformed / parsed data.

For convenience there are a couple of pre-defined transform functions for commonly used transformations (i.e. splitting data by lines). The pre-defined transform functions are exported as `transforms`:

```javascript
import { transforms } from 'advent-of-code-client';

client.setInputTransform(transforms.lines);
const client = new AocClient({
... // other options
inputTransform: transforms.lines // automatically split the input by lines
});
```

You can also specify your own transform function:

```javascript

const myTransform = rawData => {
... // transform data
return transformedData;
}

client.setInputTransform(myTransform);
const client = new AocClient({
... // other options
inputTransform: (rawData) => {
... // transform data
return transformedData;
}
});
```

## Authentication
Expand Down
38 changes: 24 additions & 14 deletions src/AocClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,33 @@ import type {
Config,
PartFn,
Result,
TransformFn
TransformFn,
ClientOptions
} from './AocClient.types';

const getCacheKey = ({ year, day, token, part }: CacheKeyParams) =>
`${year}:${day}:${token}:${part}`;

const noopTransform = (input: string) => input;
/**
* A class that handles fetching input from and submitting answers to Advent Of Code.
* Each instance of the class corresponds to a puzzle for a specific day and year based on the configuration.
*/
class AocClient {
class AocClient<TransformedInput extends any = string> {
private config: Config;
private cache: Cache;
private transform: TransformFn;
private transform: TransformFn<TransformedInput>;
/**
* @param {object} config
* @param {object} options
*/
constructor({ year, day, token, useCache = true, debug = false }: Config) {
constructor({
year,
day,
token,
useCache = true,
debug = false,
inputTransform = noopTransform as TransformFn<TransformedInput>
}: ClientOptions<TransformedInput>) {
if (
!year ||
Number.isNaN(year) ||
Expand Down Expand Up @@ -64,7 +73,12 @@ class AocClient {
globalThis.aocDebug = true;
}
this.cache = new CacheConf();
this.transform = null;
if (typeof inputTransform !== 'function') {
throw new Error(
'Invalid inputTransform option, inputTransform must be a function'
);
}
this.transform = inputTransform;
}

private _hasCompletedPart(part: number) {
Expand All @@ -85,7 +99,7 @@ class AocClient {
logger.log('Fetching input...');
const input = await getInput(this.config, this.cache);
const trimmedInput = input.trim();
return this.transform ? this.transform(trimmedInput) : trimmedInput;
return this.transform(trimmedInput);
}

/**
Expand Down Expand Up @@ -139,7 +153,9 @@ class AocClient {
* @param {boolean} autoSubmit - when true the answers for each part will be submitted to Advent Of Code automatically, otherwise each answer will require confirmation before it will be submitted.
*/
async run(
parts: [part1: PartFn] | [part1: PartFn, part2: PartFn],
parts:
| [part1: PartFn<TransformedInput>]
| [part1: PartFn<TransformedInput>, part2: PartFn<TransformedInput>],
autoSubmit = false
) {
if (!parts || !parts.length || parts.length > 2) {
Expand Down Expand Up @@ -215,12 +231,6 @@ class AocClient {
}
return Promise.resolve();
}

setInputTransform(transform: TransformFn) {
if (typeof transform !== 'function')
throw new Error('transform must be a function');
this.transform = transform;
}
}

export default AocClient;
8 changes: 6 additions & 2 deletions src/AocClient.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export type Config = {
debug?: boolean;
};

export type ClientOptions<TransformedInput = string> = Config & {
inputTransform?: TransformFn<TransformedInput>;
};

export type Cache = {
get: (key: string, options?: { ignoreMaxAge?: boolean }) => any;
set: (
Expand All @@ -36,8 +40,8 @@ export type Cache = {
isExpired: (key: string) => boolean;
};

export type TransformFn = (input: string) => any;
export type TransformFn<T> = (input: string) => T;

export type Result = number | string;

export type PartFn = (input: any) => Result;
export type PartFn<T> = (input: T) => Result;