Skip to content

Commit

Permalink
New type system, and Deno!
Browse files Browse the repository at this point in the history
Still in progress
  • Loading branch information
RoyalIcing committed Nov 27, 2023
1 parent b00f0f5 commit 68eb074
Show file tree
Hide file tree
Showing 16 changed files with 1,051 additions and 650 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"deno.enable": false
}
71 changes: 42 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,27 @@ npm add yieldparser

## Overview

Yieldparser parses a source chunk-by-chunk. You define a generator function that yields each chunk to be found. This chunk can be a `string`, a `RexExp`, or another generator function. Your generator function receives replies from parsing that chunk, for example a regular expression would receive a reply with the matches that were found. You then use this information to build a result: the value that your generator function returns. This could be a simple value, or it could be an entire AST (abstract syntax tree).
Yieldparser parses a source chunk-by-chunk. You define a generator function that
yields each chunk to be found. This chunk can be a `string`, a `RexExp`, or
another generator function. Your generator function receives replies from
parsing that chunk, for example a regular expression would receive a reply with
the matches that were found. You then use this information to build a result:
the value that your generator function returns. This could be a simple value, or
it could be an entire AST (abstract syntax tree).

If you yield an array of choices, then each choice is tested and the first one that matches is used.
If you yield an array of choices, then each choice is tested and the first one
that matches is used.

If your chunks don’t match the input string, then an error result is returned with the remaining string and the chunk that it failed on. If it succeeds, then a success result is returned with the return value of the generator function, and the remaining string (if there is anything remaining).
If your chunks don’t match the input string, then an error result is returned
with the remaining string and the chunk that it failed on. If it succeeds, then
a success result is returned with the return value of the generator function,
and the remaining string (if there is anything remaining).

Run `parse(input, yourGeneratorIterable)` to take an input string and parse into a result.
Run `parse(input, yourGeneratorIterable)` to take an input string and parse into
a result.

Run `invert(output, yourGeneratorIterable)` to take an expected result and map it back to a source string.
Run `invert(output, yourGeneratorIterable)` to take an expected result and map
it back to a source string.

## Examples

Expand All @@ -41,12 +53,13 @@ Run `invert(output, yourGeneratorIterable)` to take an expected result and map i

### Routes parser

Define a generator function for each route you have, and then define a top level `Routes` generator function. Then parse your path using `parse()`.
Define a generator function for each route you have, and then define a top level
`Routes` generator function. Then parse your path using `parse()`.

You can also map from a route object back to a path string using `invert()`.

```typescript
import { parse, mustEnd, invert } from "yieldparser";
import { invert, mustEnd, parse } from "yieldparser";

type Route =
| { type: "home" }
Expand Down Expand Up @@ -99,23 +112,23 @@ function* Routes() {
return yield [Home, About, Terms, BlogRoutes];
}

parse("/", Routes()) // result: { type: "home" }, success: true, remaining: "" }
parse("/about", Routes()) // result: { type: "about" }, success: true, remaining: "" }
parse("/legal/terms", Routes()) // result: { type: "terms" }, success: true, remaining: "" }
parse("/blog", Routes()) // result: { type: "blog" }, success: true, remaining: "" }
parse("/blog/happy-new-year", Routes()) // result: { type: "blogArticle", slug: "happy-new-year" }, success: true, remaining: "" }

invert({ type: "home" }, Routes()) // "/"
invert({ type: "about" }, Routes()) // "/about"
invert({ type: "terms" }, Routes()) // "/legal/terms"
invert({ type: "blog" }, Routes()) // "/blog"
invert({ type: "blogArticle", slug: "happy-new-year" }, Routes()) // "/blog/happy-new-year"
parse("/", Routes()); // result: { type: "home" }, success: true, remaining: "" }
parse("/about", Routes()); // result: { type: "about" }, success: true, remaining: "" }
parse("/legal/terms", Routes()); // result: { type: "terms" }, success: true, remaining: "" }
parse("/blog", Routes()); // result: { type: "blog" }, success: true, remaining: "" }
parse("/blog/happy-new-year", Routes()); // result: { type: "blogArticle", slug: "happy-new-year" }, success: true, remaining: "" }

invert({ type: "home" }, Routes()); // "/"
invert({ type: "about" }, Routes()); // "/about"
invert({ type: "terms" }, Routes()); // "/legal/terms"
invert({ type: "blog" }, Routes()); // "/blog"
invert({ type: "blogArticle", slug: "happy-new-year" }, Routes()); // "/blog/happy-new-year"
```

### IP Address parser

```typescript
import { parse, mustEnd } from 'yieldparser';
import { mustEnd, parse } from "yieldparser";

function* Digit() {
const [digit]: [string] = yield /^\d+/;
Expand All @@ -128,17 +141,17 @@ function* Digit() {

function* IPAddress() {
const first = yield Digit;
yield '.';
yield ".";
const second = yield Digit;
yield '.';
yield ".";
const third = yield Digit;
yield '.';
yield ".";
const fourth = yield Digit;
yield mustEnd;
return [first, second, third, fourth];
}

parse('1.2.3.4', IPAddress());
parse("1.2.3.4", IPAddress());
/*
{
success: true,
Expand All @@ -147,7 +160,7 @@ parse('1.2.3.4', IPAddress());
}
*/

parse('1.2.3.256', IPAddress());
parse("1.2.3.256", IPAddress());
/*
{
success: false,
Expand All @@ -166,7 +179,7 @@ parse('1.2.3.256', IPAddress());
### Basic CSS parser

```typescript
import { parse, hasMore, has } from 'yieldparser';
import { has, hasMore, parse } from "yieldparser";

type Selector = string;
interface Declaraction {
Expand All @@ -193,11 +206,11 @@ function* ValueParser() {
function* DeclarationParser() {
const name = yield PropertyParser;
yield whitespaceMay;
yield ':';
yield ":";
yield whitespaceMay;
const rawValue = yield ValueParser;
yield whitespaceMay;
yield ';';
yield ";";
return { name, rawValue };
}

Expand All @@ -207,9 +220,9 @@ function* RuleParser() {
const [selector]: [string] = yield /(:root|[*]|[a-z][\w]*)/;

yield whitespaceMay;
yield '{';
yield "{";
yield whitespaceMay;
while ((yield has('}')) === false) {
while ((yield has("}")) === false) {
yield whitespaceMay;
declarations.push(yield DeclarationParser);
yield whitespaceMay;
Expand Down
8 changes: 8 additions & 0 deletions deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"imports": {
"std/": "https://deno.land/[email protected]/"
},
"tasks": {
"dev": "deno run --watch main.ts"
}
}
17 changes: 17 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions examples/deno.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// import { parse, mustEnd } from 'https://unpkg.com/[email protected]?module';
import { parse, mustEnd } from '../src/index.ts';
import { mustEnd, parse } from "../src/index.ts";

function* Digit() {
const [digit]: [string] = yield /^\d+/;
Expand All @@ -12,15 +12,15 @@ function* Digit() {

function* IPAddress() {
const first = yield Digit;
yield '.';
yield ".";
const second = yield Digit;
yield '.';
yield ".";
const third = yield Digit;
yield '.';
yield ".";
const fourth = yield Digit;
yield mustEnd;
return [first, second, third, fourth];
}

console.log(parse('1.2.3.4', IPAddress()));
console.log(parse('1.2.3.256', IPAddress()));
console.log(parse("1.2.3.4", IPAddress()));
console.log(parse("1.2.3.256", IPAddress()));
4 changes: 2 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
testEnvironment: 'node',
testEnvironment: "node",
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest',
"^.+\\.(t|j)sx?$": "@swc/jest",
},
};
Loading

0 comments on commit 68eb074

Please sign in to comment.