Skip to content

Commit

Permalink
wrote README
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaWise committed Jan 10, 2024
1 parent 2c241a6 commit 06e68f1
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 1 deletion.
203 changes: 203 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,204 @@
# super-sources [![test](https://github.com/WiseLibs/super-sources/actions/workflows/test.yml/badge.svg)](https://github.com/WiseLibs/super-sources/actions/workflows/test.yml)

This package provides classes for representing pieces of source code, and allows you to print beautiful errors/warnings that display the referenced pieces of source code. Unicode is supported, including the [Supplementary Multilingual Plane](https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane).

## Installation

```
npm install super-sources
```

> Requires Node.js v14.x.x or later.
## Usage

```js
const { File, SourceError } = require('super-sources');

const file = new File('example.txt', 'this is a simple file.\nhello worl!\n');
const source = file.at(29, 4); // offset 29, length 4

const error = SourceError.build()
.error('Misspelling detected')
.source(source, 'here')
.note('expected: "world"')
.note(`received: "${source.string()}"`)
.done();

assert(error instanceof Error);
assert(error instanceof SourceError);

console.log(error.print({ colors: false }));
```

Result:

```
Error: Misspelling detected
--> example.txt
|
2 | hello worl!
| ^^^^
* expected: "world"
* received: "worl"
```

# API

## new File(*filename*, *content*)

Creates an object that represents a source file.

```js
const fs = require('fs');

const filename = 'example.txt';
const content = fs.readFileSync(filename, 'utf8');
const file = new File(filename, content);
```

### file.at(*offset*, [*length*]) -> *Source*

Creates a [`Source`](#new-sourcefile-start-end) object, which represents a slice of the source file. The length defaults to `1`.

```js
const source = file.at(0);
```

### file.lineNumberAt(*offset*) -> *number*

Returns the line number at the given offset. The first line is `1`.

```js
const lineNumber = file.lineNumberAt(0);

assert(lineNumber === 1);
```

### File properties

- `file.filename`: The filename that was passed to the `File` constructor.
- `file.content`: The content string that was passed to the `File` constructor.

## new Source(*file*, *start*, *end*)

Creates an object that represents a slice of the given [`File`](#new-filefilename-content). The length of the slice (`end - start`) must be at least `1`.

```js
const fs = require('fs');

const filename = 'example.txt';
const content = fs.readFileSync(filename, 'utf8');
const file = new File(filename, content);
const source = new Source(file, 0, 1);
```

### source.to(*otherSource*) -> *Source*

Creates a [`Source`](#new-sourcefile-start-end) object that spans the range from this source to the given source. A negative or zero-length range will result in a [`RangeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError). Also, both sources must be from the same file.

```js
const source1 = new Source(file, 0, 5);
const source2 = new Source(file, 3, 8);
const result = source1.to(source2);

assert(result.start === 0);
assert(result.end === 8);
```

### source.string() -> *string*

Returns the original source string represented by this object.

```js
const file = new File('example.txt', 'abcdefg');
const source = new Source(2, 4);

assert(source.string() === 'cd');
```

### source.error(*message*, [*helperText*]) -> *ErrorBuilder*

Shorthand for `SourceError.build().error(message).source(source, helperText)`. See the [`ErrorBuilder`](#class-errorbuilder) class for more details.

```js
source.error('Invalid expression').throw();
```

### source.warning(*message*, [*helperText*]) -> *ErrorBuilder*

Shorthand for `SourceError.build().warning(message).source(source, helperText)`. See the [`ErrorBuilder`](#class-errorbuilder) class for more details.

```js
console.warn(source.warning('Invalid expression').done().print());
```

### Source properties

- `source.file`: The [`File`](#new-filefilename-content) that this source came from.
- `source.start`: The offset where this source slice starts (inclusive).
- `source.end`: The offset where this source slice ends (exclusive).

## class SourceError

A subclass of [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Error) that can reference [`Source`](#new-sourcefile-start-end) objects, and is capable of printing beautiful error messages containing the source code.

Instead of constructing them manually, you can use the static `SourceError.build()` method to conveniently create a new [`ErrorBuilder`](#class-errorbuilder).

```js
const error = SourceError.build()
.error('Misspelling detected')
.source(source, 'here')
.note('expected: "world"')
.note(`received: "${source.string()}"`)
.done();
```

### error.print([*options*]) -> *string*

Returns a string containing a beautifully formatted error message, containing any source code that this error references.

The following options are supported:

- `colors` (boolean)
* Whether or not the output should be colored (by [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code)). Default: `true`.
- `filenames` (boolean)
* Whether or not the output should contain the names of the referenced source files. Default: `true`.
- `lineNumbers` (boolean)
* Whether or not the output should contain the line numbers of the referenced source code. Default: `true`.
- `positions` (boolean)
* Whether or not the output should highlight the exact positions of the referenced source code. Default: `true`.
- `maxLines` (number)
* The maximum number of source lines to display (per source snippet) before lines are omitted to save space.

## class ErrorBuilder

A convenient builder class for making customized [`SourceError`](#class-sourceerror) objects.

### builder.error(*message*) -> *this*

Adds an error message to the [`SourceError`](#class-sourceerror) being built. A single [`SourceError`](#class-sourceerror) can contain multiple error messages.

### builder.warning(*message*) -> *this*

Adds a warning message to the [`SourceError`](#class-sourceerror) being built. A single [`SourceError`](#class-sourceerror) can contain multiple warning messages.

### builder.source(*source*, [*helperText*]) -> *this*

Adds a [`Source`](#new-sourcefile-start-end) object to the [`SourceError`](#class-sourceerror) being built. Any number of sources can be added. The added source will be associated with the most recent `.error()` or `.warning()` that was added.

### builder.note(*message*) -> *this*

Adds a note to the [`SourceError`](#class-sourceerror) being built. Any number of notes can be added. The note will be associated with the most recent `.source()` that was added.

### builder.done() -> *SourceError*

Returns a [`SourceError`](#class-sourceerror) containing all errors, warnings, sources, and notes that were added to this [`ErrorBuilder`](#class-errorbuilder).

### builder.throw() -> *throw SourceError*

This is the same as `builder.done()`, but the resulting [`SourceError`](#class-sourceerror) will be immediately thrown.

## License

[MIT](https://github.com/WiseLibs/super-sources/blob/master/LICENSE)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "super-sources",
"version": "1.0.0",
"description": "Beautiful errors for any source code",
"description": "Beautiful error printing for any source code",
"author": "Joshua Wise <joshuathomaswise@gmail.com>",
"homepage": "https://github.com/WiseLibs/super-sources#readme",
"repository": {
Expand Down

0 comments on commit 06e68f1

Please sign in to comment.