Skip to content
Draft
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
7 changes: 7 additions & 0 deletions .madgerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"detectiveOptions": {
"ts": {
"skipTypeImports": true
}
}
}
25 changes: 25 additions & 0 deletions packages/parjs-vitest-error/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.yarn
1 change: 1 addition & 0 deletions packages/parjs-vitest-error/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20.9.0
1 change: 1 addition & 0 deletions packages/parjs-vitest-error/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
6 changes: 6 additions & 0 deletions packages/parjs-vitest-error/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
To recreate:

- `yarn` in the repo root directory to install packages
- `yarn test` to see test hang forever

The line causing the problem is line 13 in parse.test.ts. Comment it out and restart vitest to see the test pass.
20 changes: 20 additions & 0 deletions packages/parjs-vitest-error/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "perror",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"build": "tsc && vite build",
"dev": "vite",
"preview": "vite preview",
"test": "vitest"
},
"devDependencies": {
"typescript": "5.5.4",
"vite": "5.4.0",
"vitest": "2.0.5"
},
"peerDependencies": {
"parjs": "*"
}
}
17 changes: 17 additions & 0 deletions packages/parjs-vitest-error/src/parse-hangs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { expect, test } from "vitest";

import { float, whitespace } from "parjs";
import { between } from "parjs/combinators";

test("adds 1 + 2 to equal 3", () => {
// this line causes the infinite loop or whatever.
// comment out this line, abort vitest, then re-run vitest to watch the test pass
const parser = float().pipe(between(whitespace()));
const parseResult = parser.parse("1");
expect(parseResult).toMatchInlineSnapshot(`
ParjsSuccess {
"kind": "OK",
"value": 1,
}
`);
});
23 changes: 23 additions & 0 deletions packages/parjs-vitest-error/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
8 changes: 4 additions & 4 deletions packages/parjs/examples/src/ini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
or,
qthen,
stringify,
then,
thenceforth,
thenq
} from "parjs/combinators";

Expand Down Expand Up @@ -88,7 +88,7 @@ export const value = anyCharOf(valueCharacters).pipe(many1(), stringify()).expec
export const definitionLine = token(identifier)
.pipe(
thenq(token(string("="))),
then(value, comment.pipe(maybe())),
thenceforth(value, comment.pipe(maybe())),
thenq(newline().pipe(or(eof()))),
map(([name, val]) => new Property(name.toLowerCase(), val))
)
Expand All @@ -113,7 +113,7 @@ export const sectionHeader = token(
export const section = sectionHeader
.pipe(
thenq(newline()),
then(definitionList),
thenceforth(definitionList),
map(([name, properties]) => new NamedSection(name, properties))
)
.expects("section");
Expand All @@ -126,7 +126,7 @@ export const globalSection = definitionList

export const iniFile = globalSection
.pipe(
then(section.pipe(many())),
thenceforth(section.pipe(many())),
map(([global, sections]) => new IniFile(global, sections))
)
.expects("ini file");
4 changes: 2 additions & 2 deletions packages/parjs/examples/src/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
or,
qthen,
stringify,
then,
thenceforth,
thenq
} from "parjs/combinators";

Expand Down Expand Up @@ -105,7 +105,7 @@ const pArray = pJsonValue.pipe(
// Plus, whitespace around the property
const pObjectProperty = pStr.pipe(
thenq(string(":").pipe(between(whitespace()))),
then(pJsonValue),
thenceforth(pJsonValue),
between(whitespace()),
map(([name, value]) => {
return new JsonObjectProperty(name, value);
Expand Down
8 changes: 4 additions & 4 deletions packages/parjs/examples/src/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import type { Parjser } from "parjs";
import { float, string } from "parjs";
import type { DelayedParjser } from "parjs/combinators";
import { between, later, many, map, or, then, thenq } from "parjs/combinators";
import { between, later, many, map, or, thenceforth, thenq } from "parjs/combinators";

export interface Expression {
calculate(): number;
Expand Down Expand Up @@ -98,7 +98,7 @@ export const value: Parjser<Expression> = t(numberLiteral)

export const unary: Parjser<Expression> = t(string("-"))
.pipe(
then(value),
thenceforth(value),
map(([op, val]) => new UnaryOperation(op, val)),
or(value)
)
Expand All @@ -108,7 +108,7 @@ export function product() {
const operator = t(string("*").pipe(or(string("/"), string("%"))));
return unary
.pipe(
then(operator.pipe(then(unary), many())),
thenceforth(operator.pipe(thenceforth(unary), many())),
map(expressions => {
const [first, rest] = expressions;
return rest.reduce((lhs, [op, rhs]) => new BinaryOperation(lhs, op, rhs), first);
Expand All @@ -121,7 +121,7 @@ export function sum() {
const operator = t(string("+").pipe(or(string("-"))));
return product()
.pipe(
then(operator.pipe(then(product()), many())),
thenceforth(operator.pipe(thenceforth(product()), many())),
map(expressions => {
const [first, rest] = expressions;
return rest.reduce((lhs, [op, rhs]) => new BinaryOperation(lhs, op, rhs), first);
Expand Down
4 changes: 2 additions & 2 deletions packages/parjs/spec/unit/combinators/expects.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fail, nope } from "@lib";
import { reason, then } from "@lib/combinators";
import { reason, thenceforth } from "@lib/combinators";

describe("expects combinator", () => {
const base = nope("deez nuts");
Expand All @@ -13,7 +13,7 @@ describe("expects combinator", () => {
});
it("modifies expecting", () => {
const parser = base.pipe(
then(fail("deez nuts")),
thenceforth(fail("deez nuts")),
reason(x => `${x.reason}! gottem!`)
);
expect(parser.parse("abc")).toMatchObject({
Expand Down
4 changes: 2 additions & 2 deletions packages/parjs/spec/unit/combinators/manySepBy.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ResultKind, fail, result, string } from "@lib";
import { manySepBy, stringify, then, thenq } from "@lib/combinators";
import { manySepBy, stringify, thenceforth, thenq } from "@lib/combinators";
import { getArrayWithSeparators } from "@lib/internal/combinators/many-sep-by";

const prs = string("ab");
Expand Down Expand Up @@ -38,7 +38,7 @@ describe("manySepBy combinator", () => {
});

it("many that fails hard on 2nd iteration", () => {
const manyParser = string("a").pipe(then("b"), stringify(), manySepBy(", "));
const manyParser = string("a").pipe(thenceforth("b"), stringify(), manySepBy(", "));
expect(manyParser.parse("ab, ac")).toBeFailure("Hard");
});

Expand Down
6 changes: 3 additions & 3 deletions packages/parjs/spec/unit/combinators/maybe.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Parjser } from "@lib";
import { fail, ResultKind, string } from "@lib";
import { maybe, qthen, stringify, then } from "@lib/combinators";
import { maybe, qthen, stringify, thenceforth } from "@lib/combinators";

describe("maybe combinator", () => {
it("works", () => {
Expand All @@ -22,9 +22,9 @@ describe("maybe combinator", () => {
});

describe("maybe combinator again", () => {
const parser = string("a").pipe(then("b"), stringify(), maybe("c"));
const parser = string("a").pipe(thenceforth("b"), stringify(), maybe("c"));

const p2: Parjser<[0 | "a", "b"]> = string("a").pipe(maybe(0), then(string("b")));
const p2: Parjser<[0 | "a", "b"]> = string("a").pipe(maybe(0), thenceforth(string("b")));
it("succeeds to parse", () => {
expect(parser.parse("ab")).toBeSuccessful("ab");
});
Expand Down
4 changes: 2 additions & 2 deletions packages/parjs/spec/unit/combinators/must.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ResultKind, eof, string, stringLen } from "@lib";
import { must, mustCapture, or, stringify, then } from "@lib/combinators";
import { must, mustCapture, or, stringify, thenceforth } from "@lib/combinators";

describe("must combinators", () => {
describe("must combinator", () => {
Expand All @@ -24,7 +24,7 @@ describe("must combinators", () => {

describe("mustCapture combinator", () => {
const parser = string("a").pipe(
then("b"),
thenceforth("b"),
stringify(),
or(eof("")),
mustCapture({
Expand Down
6 changes: 3 additions & 3 deletions packages/parjs/spec/unit/combinators/not.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { fail, rest, ResultKind, string } from "@lib";
import { not, stringify, then } from "@lib/combinators";
import { not, stringify, thenceforth } from "@lib/combinators";

describe("not combinator", () => {
const parser = string("a").pipe(then("b"), stringify(), not());
const parser = string("a").pipe(thenceforth("b"), stringify(), not());
it("succeeds on empty input/soft fail", () => {
expect(parser.parse("")).toBeSuccessful(undefined);
});
it("succeeds on hard fail if we take care of the rest", () => {
const parser2 = parser.pipe(then(rest()));
const parser2 = parser.pipe(thenceforth(rest()));
expect(parser2.parse("a")).toBeSuccessful();
});
it("soft fails on passing input", () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/parjs/spec/unit/combinators/recover.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { fail, ResultKind, string } from "@lib";
import { recover, stringify, then } from "@lib/combinators";
import { recover, stringify, thenceforth } from "@lib/combinators";

describe("recover combinator", () => {
const parser = string("a").pipe(
then("b"),
thenceforth("b"),
stringify(),
recover(() => ({ kind: "Soft" }))
);
Expand Down
14 changes: 7 additions & 7 deletions packages/parjs/spec/unit/combinators/recovery.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
reason,
recover,
stringify,
then
thenceforth
} from "@lib/combinators";

describe("maybe combinator", () => {
Expand Down Expand Up @@ -80,9 +80,9 @@ describe("or combinator", () => {
});

describe("or val combinator", () => {
const parser = string("a").pipe(then("b"), stringify(), maybe("c"));
const parser = string("a").pipe(thenceforth("b"), stringify(), maybe("c"));

const p2: Parjser<[0 | "a", "b"]> = string("a").pipe(maybe(0), then(string("b")));
const p2: Parjser<[0 | "a", "b"]> = string("a").pipe(maybe(0), thenceforth(string("b")));
it("succeeds to parse", () => {
expect(parser.parse("ab")).toBeSuccessful("ab");
});
Expand All @@ -102,12 +102,12 @@ describe("or val combinator", () => {
});

describe("not combinator", () => {
const parser = string("a").pipe(then("b"), stringify(), not());
const parser = string("a").pipe(thenceforth("b"), stringify(), not());
it("succeeds on empty input/soft fail", () => {
expect(parser.parse("")).toBeSuccessful(undefined);
});
it("succeeds on hard fail if we take care of the rest", () => {
const parser2 = parser.pipe(then(rest()));
const parser2 = parser.pipe(thenceforth(rest()));
expect(parser2.parse("a")).toBeSuccessful();
});
it("soft fails on passing input", () => {
Expand All @@ -127,7 +127,7 @@ describe("not combinator", () => {

describe("soft combinator", () => {
const parser = string("a").pipe(
then("b"),
thenceforth("b"),
stringify(),
recover(() => ({ kind: "Soft" }))
);
Expand Down Expand Up @@ -161,7 +161,7 @@ describe("expects combinator", () => {
});
it("modifies expecting", () => {
const parser = base.pipe(
then(fail("deez nuts")),
thenceforth(fail("deez nuts")),
reason(x => `${x.reason}! gottem!`)
);
expect(parser.parse("abc")).toMatchObject({
Expand Down
Loading