Skip to content

Commit f6c2bc5

Browse files
committed
Implement import syntax
1 parent a47bd26 commit f6c2bc5

File tree

5 files changed

+313
-184
lines changed

5 files changed

+313
-184
lines changed

eslint.config.mts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ export default tseslint.config(
3939
"@typescript-eslint/only-throw-error": "off",
4040
"@typescript-eslint/consistent-type-definitions": ["error", "type"],
4141
"@typescript-eslint/no-unused-vars": [
42-
"error",
43-
{
44-
"args": "all",
45-
"argsIgnorePattern": "^_",
46-
"caughtErrors": "all",
47-
"caughtErrorsIgnorePattern": "^_",
48-
"destructuredArrayIgnorePattern": "^_",
49-
"varsIgnorePattern": "^_",
50-
"ignoreRestSiblings": true
51-
}
52-
],
42+
"error",
43+
{
44+
args: "all",
45+
argsIgnorePattern: "^_",
46+
caughtErrors: "all",
47+
caughtErrorsIgnorePattern: "^_",
48+
destructuredArrayIgnorePattern: "^_",
49+
varsIgnorePattern: "^_",
50+
ignoreRestSiblings: true,
51+
},
52+
],
5353
"@typescript-eslint/restrict-template-expressions": [
5454
"error",
5555
{ allowNumber: true },

pnpm-lock.yaml

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/dsl.test.ts

Lines changed: 127 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, it } from "vitest";
2-
import { parseSchema } from "./dsl";
2+
import { parseSchema, stringLiteral } from "./dsl";
33

44
// Takes an expression as an argument and throws if that assertion fails.
55
// This primarily exists to provide typescript narrowing in a statement,
@@ -21,7 +21,7 @@ describe("parsing", () => {
2121
const schema = `use expiration`;
2222
const parsed = parseSchema(schema);
2323

24-
expect(parsed?.definitions.length).toEqual(1);
24+
expect(parsed?.definitions).toHaveLength(1);
2525
const useFlag = parsed?.definitions[0];
2626
assert(useFlag);
2727
assert(useFlag.kind === "use");
@@ -39,6 +39,45 @@ definition foo {}
3939
});
4040
});
4141

42+
describe("imports", () => {
43+
it("parses basic import", () => {
44+
const schema = `import "foo/bar/baz.zed"`;
45+
const parsed = parseSchema(schema);
46+
47+
expect(parsed?.definitions).toHaveLength(1);
48+
const imPort = parsed?.definitions[0];
49+
assert(imPort);
50+
assert(imPort.kind === "import");
51+
expect(imPort.path).toEqual("foo/bar/baz.zed");
52+
});
53+
it("parses import and definition", () => {
54+
const schema = `import "foo/bar/baz.zed"
55+
definition user {}
56+
`;
57+
const parsed = parseSchema(schema);
58+
59+
expect(parsed?.definitions).toHaveLength(2);
60+
const imPort = parsed?.definitions[0];
61+
assert(imPort);
62+
assert(imPort.kind === "import");
63+
expect(imPort.path).toEqual("foo/bar/baz.zed");
64+
65+
const definition = parsed.definitions[1];
66+
assert(definition);
67+
assert(definition.kind === "objectDef");
68+
});
69+
it("rejects too many things on line", () => {
70+
const schema = `import "foo/bar/baz.zed" yolo`;
71+
const parsed = parseSchema(schema);
72+
expect(parsed).toBeUndefined();
73+
});
74+
it("rejects malformed import string", () => {
75+
const schema = `import "foo/bar/baz.zed"yolo`;
76+
const parsed = parseSchema(schema);
77+
expect(parsed).toBeUndefined();
78+
});
79+
});
80+
4281
describe("definitions", () => {
4382
it("parses empty definition", () => {
4483
const schema = `definition foo {}`;
@@ -433,7 +472,7 @@ definition foo {}
433472

434473
const definition = parsed?.definitions[0];
435474
assert(definition);
436-
assert(definition.kind === "objectDef")
475+
assert(definition.kind === "objectDef");
437476
expect(definition.name).toEqual("foo");
438477
expect(definition.relations).toHaveLength(0);
439478
expect(definition.permissions).toHaveLength(2);
@@ -458,42 +497,68 @@ definition foo {}
458497

459498
describe("partial syntax", () => {
460499
it("parses a basic partial", () => {
461-
const schema = `partial thing {
500+
const schema = `partial thing {
462501
relation user: user
463502
permission view = user
464-
}`
465-
const parsed = parseSchema(schema)
466-
expect(parsed?.definitions).toHaveLength(1)
503+
}`;
504+
const parsed = parseSchema(schema);
505+
expect(parsed?.definitions).toHaveLength(1);
467506
const partial = parsed?.definitions[0];
468507
assert(partial);
469-
assert(partial.kind === "partial")
470-
expect(partial.name).toEqual("thing")
471-
expect(partial.relations).toHaveLength(1)
472-
expect(partial.permissions).toHaveLength(1)
473-
474-
const relation = partial.relations[0]
475-
assert(relation)
476-
expect(relation.name).toEqual("user")
477-
478-
const permission = partial.permissions[0]
479-
assert(permission)
480-
expect(permission.name).toEqual("view")
481-
})
508+
assert(partial.kind === "partial");
509+
expect(partial.name).toEqual("thing");
510+
expect(partial.relations).toHaveLength(1);
511+
expect(partial.permissions).toHaveLength(1);
512+
513+
const relation = partial.relations[0];
514+
assert(relation);
515+
expect(relation.name).toEqual("user");
516+
517+
const permission = partial.permissions[0];
518+
assert(permission);
519+
expect(permission.name).toEqual("view");
520+
});
482521
it("parses a basic partial reference", () => {
483-
const schema = `definition thing {
522+
const schema = `definition thing {
484523
...some_partial
485-
}`
486-
const parsed = parseSchema(schema)
487-
expect(parsed?.definitions).toHaveLength(1)
524+
}`;
525+
const parsed = parseSchema(schema);
526+
expect(parsed?.definitions).toHaveLength(1);
488527
const definition = parsed?.definitions[0];
489528
assert(definition);
490-
assert(definition.kind === "objectDef")
491-
expect(definition.partialReferences).toHaveLength(1)
492-
assert(definition.partialReferences[0])
493-
expect(definition.partialReferences[0].name).toEqual("some_partial")
494-
})
495-
// TODO: more tests here
496-
})
529+
assert(definition.kind === "objectDef");
530+
expect(definition.partialReferences).toHaveLength(1);
531+
assert(definition.partialReferences[0]);
532+
expect(definition.partialReferences[0].name).toEqual("some_partial");
533+
});
534+
it("fails on a basic partial reference with extra stuff", () => {
535+
const schema = `definition thing {
536+
...some_partial yolo
537+
}`;
538+
const parsed = parseSchema(schema);
539+
expect(parsed).toBeUndefined();
540+
});
541+
it("fails on a basic partial reference with disallowed chars", () => {
542+
const schema = `definition thing {
543+
...some'schtuff
544+
}`;
545+
const parsed = parseSchema(schema);
546+
expect(parsed).toBeUndefined();
547+
});
548+
it("passes on a partial with a partial reference inside", () => {
549+
const schema = `partial thing {
550+
...some_partial
551+
}`;
552+
const parsed = parseSchema(schema);
553+
expect(parsed?.definitions).toHaveLength(1);
554+
const partial = parsed?.definitions[0];
555+
assert(partial);
556+
assert(partial.kind === "partial");
557+
expect(partial.partialReferences).toHaveLength(1);
558+
assert(partial.partialReferences[0]);
559+
expect(partial.partialReferences[0].name).toEqual("some_partial");
560+
});
561+
});
497562

498563
describe("full schemas", () => {
499564
it("full", () => {
@@ -841,3 +906,34 @@ describe("parsing fails when", () => {
841906
expect(parsed).toBeUndefined();
842907
});
843908
});
909+
910+
describe("utils", () => {
911+
describe("stringLiteral", () => {
912+
it("consumes a normal string literal", () => {
913+
const parsed = stringLiteral.parse("'/foo/bar/baz.zed'");
914+
expect(parsed.status).toBeTruthy();
915+
assert(parsed.status);
916+
expect(parsed.value).toEqual("/foo/bar/baz.zed");
917+
});
918+
it("consumes a quoted singlequote", () => {
919+
const parsed = stringLiteral.parse(`"'"`);
920+
expect(parsed.status).toBeTruthy();
921+
assert(parsed.status);
922+
expect(parsed.value).toEqual("'");
923+
});
924+
it("consumes a quoted doublequote", () => {
925+
const parsed = stringLiteral.parse(`'"'`);
926+
expect(parsed.status).toBeTruthy();
927+
assert(parsed.status);
928+
expect(parsed.value).toEqual('"');
929+
});
930+
it("disallows backticks as delimiter", () => {
931+
const parsed = stringLiteral.parse("`something in backticks`");
932+
expect(parsed.status).toBeFalsy();
933+
});
934+
it("fails when contents continue", () => {
935+
const parsed = stringLiteral.parse("'something'thatcontinues");
936+
expect(parsed.status).toBeFalsy();
937+
});
938+
});
939+
});

0 commit comments

Comments
 (0)