Skip to content

Commit

Permalink
refactor!: abstract reader implementation
Browse files Browse the repository at this point in the history
Signed-off-by: Lexus Drumgold <[email protected]>
  • Loading branch information
unicornware committed Jun 11, 2024
1 parent a974d58 commit 2a803f4
Show file tree
Hide file tree
Showing 33 changed files with 1,067 additions and 302 deletions.
2 changes: 1 addition & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@ ignore:

profiling:
critical_files_paths:
- src/reader.ts
- src/character.reader.ts
2 changes: 1 addition & 1 deletion .dprint.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
},
{
"command": "node ./dprint/shfmt.mjs {{file_path}}",
"exts": ["sh", "txt", "zsh"],
"exts": ["sh", "zsh"],
"fileNames": [
".editorconfig",
".env",
Expand Down
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
**/*.patch
**/*.sh
**/*.snap
**/*.txt
**/*config.*.timestamp*
**/.DS_Store
**/.temp/
Expand Down
191 changes: 147 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,27 @@
- [Use](#use)
- [API](#api)
- [`Reader(file[, start])`](#readerfile-start)
- [`Reader#char`](#readerchar)
- [`Reader#eof`](#readereof)
- [`Reader#includes(value)`](#readerincludesvalue)
- [`Reader#index`](#readerindex)
- [`Reader#next`](#readernext)
- [`Reader#now()`](#readernow)
- [`Reader#offset([point])`](#readeroffsetpoint)
- [`Reader#output`](#readeroutput)
- [`Reader#peek([k])`](#readerpeekk)
- [`Reader#peekMatch(test)`](#readerpeekmatchtest)
- [`Reader#point([offset])`](#readerpointoffset)
- [`Reader#previous`](#readerprevious)
- [`Reader#read([k])`](#readerreadk)
- [`Reader#reset()`](#readerreset)
- [`Reader#slice(m)`](#readerslicem)
- [`Reader#start`](#readerstart)
- [`CharacterReader(file[, start])`](#characterreaderfile-start)
- [`CharacterReader#peekMatch(test)`](#characterreaderpeekmatchtest)
- [`CharacterMatch`](#charactermatch)
- [`Character`](#character)
- [`ReaderIterator<T>`](#readeriteratort)
- [`ReaderIteratorResult`](#readeriteratorresult)
- [`ReaderValue`](#readervalue)
- [Types](#types)
- [Contribute](#contribute)

Expand Down Expand Up @@ -65,68 +73,101 @@ yarn add @flex-development/vfile-reader
In Deno with [`esm.sh`][esmsh]:

```ts
import { Reader } from 'https://esm.sh/@flex-development/vfile-reader'
import { CharacterReader } from 'https://esm.sh/@flex-development/vfile-reader'
```

In browsers with [`esm.sh`][esmsh]:

```html
<script type="module">
import { Reader } from 'https://esm.sh/@flex-development/vfile-reader'
import { CharacterReader } from 'https://esm.sh/@flex-development/vfile-reader'
</script>
```

## Use

```ts
import { Reader } from '@flex-development/vfile-reader'
import { CharacterReader } from '@flex-development/vfile-reader'
import { read } from 'to-vfile'
import type { VFile } from 'vfile'

const file: VFile = await read('regex.txt')
const reader: Reader = new Reader(file)
const file: VFile = await read('__fixtures__/emojis.txt') // 😍👍🚀❇️

while (!reader.eof) console.dir(reader.read())
const chars: CharacterReader = new CharacterReader(file)

// for (const char of chars) console.dir({ char, now: chars.now() })

while (!chars.eof) console.dir({ char: chars.read(), now: chars.now() })
```

...yields

```sh
'👍'
'🚀'
''
''
'/'
'\n'
null
{ char: '😍', now: { column: 1, line: 1, offset: 0 } }
{ char: '👍', now: { column: 2, line: 1, offset: 1 } }
{ char: '🚀', now: { column: 3, line: 1, offset: 2 } }
{ char: '', now: { column: 4, line: 1, offset: 3 } }
{ char: '', now: { column: 5, line: 1, offset: 4 } }
{ char: '\n', now: { column: 6, line: 1, offset: 5 } }
```
## API
This package exports the identifier [`Reader`](#readerfile-start). There is no default export.
This package exports the following identifiers:
- [`CharacterReader`](#characterreaderfile-start)
- [`Reader`](#readerfile-start)
There is no default export.
### `Reader(file[, start])`
Create a new character reader.
> **extends**: [`Location`][location]\
> **implements**: [`ReaderIterator<T>`](#readeriteratort)
Create a new input reader.
Pass a `start` point to make reader locations relative to a specific place. Any point or offset accessed will be
relative to the given point.
**Note**: This is an abstract class and must be extended.
- `file` ([`Value`][vfile-value] | [`VFile`][vfile-api]) &mdash; file to read
- `start` ([`Point`][point] | `null` | `undefined`) &mdash; point before first character in `file`
- `start` ([`Point`][point] | `null` | `undefined`) &mdash; point before first reader value
#### `Reader#char`
#### <small>Type Parameters</small>
([`Character`](#character)) Current character or `null`, with `null` denoting end of file. Equivalent to
[`reader.peek(0)`](#readerpeekk).
- `T` ([`ReaderValue`](#readervalue)) &mdash; reader output value
#### `Reader#eof`
(`boolean`) Boolean indicating if reader has reached the end of file, with `true` denoting end of file.
#### `Reader#includes(value)`
Check if the file contains the given search `value`, relative to the current reader position.
##### `Parameters`
- `value` (`string`) &mdash; value to search for in file
##### `Returns`
(`boolean`) `true` if file contains search `value`.
#### `Reader#index`
([`Offset`][offset]) Index of current character.
([`Offset`][offset]) Index of current reader value.
#### `Reader#next()`
Get the next reader result.
Unlike [`peek`](#readerpeekk), this method changes the position of the reader.
##### `Returns`
([`ReaderIteratorResult<T>`](#readeriteratorresult)) Next reader result.
#### `Reader#now()`
Expand All @@ -140,76 +181,137 @@ Get the current point in the file.
See [`Location#offset([point])`][locationoffset-point].
#### `Reader#output`
(`T`) Current reader value or `null`, with `null` denoting end of file. Equivalent to
[`reader.peek(0)`](#readerpeekk).
#### `Reader#peek([k])`
Get the next `k`-th character from the file without changing the position of the reader, with `null` denoting end of
Get the next `k`-th reader value from the file without changing the position of the reader, with `null` denoting end of
file.
##### `Parameters`
- `k` (`number | undefined`) &mdash; difference between index of next `k`-th character and index of current character
- `k` (`number | undefined`) &mdash; difference between index of next `k`-th reader value and index of current value
- **default**: `1`
##### `Returns`
([`Character`](#character)) Peeked character or `null`.

#### `Reader#peekMatch(test)`

Get the next match from the file without changing the position of the reader, with `null` denoting no match.

##### `Parameters`

- `test` (`RegExp`) &mdash; character test

##### `Returns`

([`CharacterMatch`](#charactermatch)) Peeked character match or `null`.
(`T`) Peeked reader value or `null`.
#### `Reader#point([offset])`
See [`Location#point([offset])`][locationpoint-offset].
#### `Reader#previous`
([`Character`](#character)) Previous character or `null`, with `null` denoting beginning or end of file. Equivalent to
(`T`) Previous reader value or `null`, with `null` denoting beginning or end of file. Equivalent to
[`reader.peek(-1)`](#readerpeekk).
#### `Reader#read([k])`
Get the next `k`-th character from the file, with `null` denoting end of file.
Get the next `k`-th reader value from the file, with `null` denoting end of file.
Unlike [`peek`](#readerpeekk), this method changes the position of the reader.
##### `Parameters`
- `k` (`number | undefined`) &mdash; difference between index of next `k`-th character and index of current character
- `k` (`number | undefined`) &mdash; difference between index of next `k`-th reader value and index of current value
- **default**: `1`
##### `Returns`
([`Character`](#character)) Next `k`-th character or `null`.
(`T`) Next `k`-th reader value or `null`.
#### `Reader#reset()`
Reset the position of the reader.
##### `Returns`
(`this`) The repositioned reader.
#### `Reader#slice(m)`
Get a slice of the most recent reader values, with the last value being the current reader value, without changing the
position of the reader.
##### `Parameters`
- `m` (`number`) &mdash; maximum number of reader values to include in slice
##### `Returns`
(`NonNullable<T>[]`) Reader values slice.
#### `Reader#start`
([`Point`][point]) Point before first character in file.
([`Point`][point]) Point before first reader value in file.
### `CharacterReader(file[, start])`
> **extends**: [`Reader`](#readerfile-start)
Create a new character reader.
#### `CharacterReader#peekMatch(test)`
Get the next match from the file without changing the position of the reader, with `null` denoting no match.
##### `Parameters`
- `test` (`RegExp`) &mdash; character test
##### `Returns`
([`CharacterMatch`](#charactermatch)) Peeked character match or `null`.
#### `CharacterMatch`
### `CharacterMatch`
Match in a source file, with `null` denoting no match (TypeScript type).
```ts
type CharacterMatch = RegExpExecArray | null
```
#### `Character`
### `Character`
Character in a source file, with `null` denoting the end of file (TypeScript type).
```ts
type Character = string | null
```
### `ReaderIterator<T>`
Input reader iterator API (TypeScript interface).
```ts
interface ReaderIterator<T extends ReaderValue = ReaderValue> {
[Symbol.iterator](): ReaderIterator<T>
next(): ReaderIteratorResult<T>
}
```
### `ReaderIteratorResult`
Union of iterator results (TypeScript type).
```ts
type ReaderIteratorResult<
T extends ReaderValue = ReaderValue
> = IteratorReturnResult<T> | IteratorYieldResult<T>
```
### `ReaderValue`
Union of input reader output values (TypeScript type).
```ts
type ReaderValue = Character
```
## Types
This package is fully typed with [TypeScript][typescript].
Expand All @@ -223,6 +325,7 @@ community you agree to abide by its terms.
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh/
[location]: https://github.com/flex-development/vfile-location#locationfile-start
[locationoffset-point]: https://github.com/flex-development/vfile-location#locationoffsetpoint
[locationpoint-offset]: https://github.com/flex-development/vfile-location#locationpointoffset
[offset]: https://github.com/flex-development/unist-util-types#offset
Expand Down
1 change: 1 addition & 0 deletions __fixtures__/alphabet.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
abcdefghijklmnopqrstuvwxyz
1 change: 1 addition & 0 deletions __fixtures__/emojis.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
😍👍🚀❇️
1 change: 0 additions & 1 deletion __fixtures__/regex.txt

This file was deleted.

6 changes: 6 additions & 0 deletions __tests__/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @file Entry Point - Test Interfaces
* @module tests/interfaces
*/

export type { default as MockInstance } from './mock-instance'
19 changes: 19 additions & 0 deletions __tests__/interfaces/mock-instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @file Test Interfaces - MockInstance
* @module tests/interfaces/MockInstance
*/

import type { Fn } from '@flex-development/tutils'
import type * as vitest from 'vitest'

/**
* {@linkcode vitest.MockInstance} utility.
*
* @template F - Function being mocked
*
* @extends {vitest.Mock<Parameters<F>,ReturnType<F>>}
*/
interface MockInstance<F extends Fn = Fn>
extends vitest.MockInstance<Parameters<F>, ReturnType<F>> {}

export type { MockInstance as default }
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
"trash-cli": "5.0.0",
"ts-dedent": "2.2.0",
"typescript": "5.5.0-beta",
"vite-tsconfig-paths": "4.3.2",
"vitest": "1.6.0",
"yaml-eslint-parser": "1.2.3"
},
Expand Down
Loading

0 comments on commit 2a803f4

Please sign in to comment.