-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
48bcc46
commit a3a7e1b
Showing
3 changed files
with
293 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import { SugarSyntax } from "../parser/Sugar"; | ||
import { Cardinality } from "./Cardinality"; | ||
import { | ||
ArgDefinition, | ||
BlockDefinition, | ||
BodyPropDefinitions, | ||
InlineDefinition, | ||
RootDefinition, | ||
SchemaDefinition | ||
} from "./SchemaDefinition"; | ||
import * as SchemaSchema from "./schemaSchemaInterface"; | ||
|
||
export function readSchema(root: SchemaSchema.Root): SchemaDefinition { | ||
return { | ||
root: convertRoot(root.root), | ||
blocks: Object.fromEntries( | ||
root.blocks.map(block => [block.name.join(""), convertBlock(block)]) | ||
), | ||
inline: Object.fromEntries(root.inline.map(inline => [inline.name, convertInline(inline)])) | ||
}; | ||
} | ||
|
||
function convertRoot(root: SchemaSchema.BlockRoot): RootDefinition { | ||
const res: RootDefinition = { | ||
rawBody: false, | ||
props: { | ||
body: convertBody(root.body) | ||
} | ||
}; | ||
if (root.defaultTag) res.defaultTag = root.defaultTag.name.join(""); | ||
return res; | ||
} | ||
|
||
function convertBlock(block: SchemaSchema.BlockBlock): BlockDefinition { | ||
const res: BlockDefinition = { | ||
rawBody: false, | ||
props: {} | ||
}; | ||
if (block.head) res.props.head = convertHead(block.head); | ||
if (block.body) res.props.body = convertBody(block.body); | ||
if (block.defaultTag) res.defaultTag = block.defaultTag.name.join(""); | ||
return res; | ||
} | ||
|
||
function convertHead(head: SchemaSchema.BlockHead): ArgDefinition { | ||
// TODO Temporary until we have a more powerful schema: | ||
if (head.type.length === 0) throw new Error("Head should have at least one type"); | ||
if (head.type.length > 1) throw new Error("Head should have at most one type"); | ||
|
||
const type = head.type[0]; | ||
const name = type.propName.join(""); | ||
|
||
if (type.$tag === "hashml") { | ||
return { | ||
raw: false, | ||
name, | ||
content: convertItems(type.content) | ||
}; | ||
} else { | ||
return { | ||
raw: true, | ||
name, | ||
type: type.$tag | ||
}; | ||
} | ||
} | ||
|
||
function convertBody(body: SchemaSchema.BlockBody): BodyPropDefinitions { | ||
return Object.fromEntries( | ||
body.props.map(prop => [prop.name, convertPropContent(prop.content)]) | ||
); | ||
} | ||
|
||
function convertItems(items: SchemaSchema.BlockItem[]): string[] { | ||
return items.map(item => item.target.join("")); | ||
} | ||
|
||
function convertPropContent( | ||
propContent: SchemaSchema.BlockProp["content"] | ||
): { [tag: string]: Cardinality } { | ||
return Object.fromEntries( | ||
propContent.map(content => [content.target.join(""), convertCardinality(content)]) | ||
); | ||
} | ||
|
||
function convertCardinality( | ||
cardinality: | ||
| SchemaSchema.BlockOne | ||
| SchemaSchema.BlockOneOrMore | ||
| SchemaSchema.BlockOptional | ||
| SchemaSchema.BlockZeroOrMore | ||
): Cardinality { | ||
switch (cardinality.$tag) { | ||
case "one": | ||
return { min: 1, max: 1 }; | ||
case "oneOrMore": | ||
return { min: 1, max: Infinity }; | ||
case "optional": | ||
return { min: 0, max: 1 }; | ||
case "zeroOrMore": | ||
return { min: 0, max: Infinity }; | ||
} | ||
} | ||
|
||
function convertInline(inline: SchemaSchema.BlockInline): InlineDefinition { | ||
const res: InlineDefinition = { | ||
args: convertArgs(inline.args) | ||
}; | ||
if (inline.sugar) res.sugar = convertSugar(inline.sugar); | ||
return res; | ||
} | ||
|
||
function convertArgs(args: SchemaSchema.BlockArgs): ArgDefinition[] { | ||
return args.args.map(arg => { | ||
const name = arg.propName.join(""); | ||
if (arg.$tag === "hashml") { | ||
return { raw: false, name, content: convertItems(arg.content) }; | ||
} else { | ||
return { raw: true, name, type: arg.$tag }; | ||
} | ||
}); | ||
} | ||
|
||
function convertSugar(sugar: SchemaSchema.BlockSugar): SugarSyntax { | ||
const res: SugarSyntax = { | ||
start: sugar.start.token, | ||
end: sugar.end.token | ||
}; | ||
if (sugar.separator) res.separator = sugar.separator.token; | ||
return res; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
#root | ||
#body | ||
#prop root | ||
#one root | ||
#prop blocks | ||
#zeroOrMore block | ||
#prop inline | ||
#zeroOrMore inline | ||
|
||
#block root | ||
#body | ||
#prop defaultTag | ||
#optional default | ||
#prop body | ||
#one body | ||
|
||
#block block | ||
#head | ||
#hashml name | ||
#body | ||
#prop defaultTag | ||
#optional default | ||
#prop head | ||
#optional head | ||
#prop body | ||
#optional body | ||
|
||
#block default | ||
#head | ||
#hashml name | ||
|
||
#block head | ||
#body | ||
#prop type | ||
#optional hashml | ||
#optional string | ||
#optional date | ||
#optional url | ||
|
||
#block body | ||
#body | ||
#prop props | ||
#zeroOrMore prop | ||
|
||
#block prop | ||
#default item | ||
#head | ||
#hashml name | ||
#body | ||
#prop content | ||
#zeroOrMore optional | ||
#zeroOrMore one | ||
#zeroOrMore oneOrMore | ||
#zeroOrMore zeroOrMore | ||
|
||
#block optional | ||
#head | ||
#hashml target | ||
|
||
#block one | ||
#head | ||
#hashml target | ||
|
||
#block oneOrMore | ||
#head | ||
#hashml target | ||
|
||
#block zeroOrMore | ||
#head | ||
#hashml target | ||
|
||
#block inline | ||
#head | ||
#hashml name | ||
#body | ||
#prop args | ||
#one args | ||
#prop sugar | ||
#optional sugar | ||
|
||
#block args | ||
#body | ||
#prop args | ||
#zeroOrMore hashml | ||
#zeroOrMore string | ||
#zeroOrMore date | ||
#zeroOrMore url | ||
|
||
#block hashml | ||
#default item | ||
#head | ||
#hashml propName | ||
#body | ||
#prop content | ||
#zeroOrMore item | ||
|
||
#block item | ||
#head | ||
#hashml target | ||
|
||
#block string | ||
#head | ||
#hashml propName | ||
|
||
#block date | ||
#head | ||
#hashml propName | ||
|
||
#block url | ||
#head | ||
#hashml propName | ||
|
||
#block sugar | ||
#body | ||
#prop start | ||
#one start | ||
#prop separator | ||
#optional separator | ||
#prop end | ||
#one end | ||
|
||
#block start | ||
#head | ||
#string token | ||
|
||
#block separator | ||
#head | ||
#string token | ||
|
||
#block end | ||
#head | ||
#string token |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { assert } from "chai"; | ||
import { Schema, schemaSchema } from "../../src"; | ||
import { readSchema } from "../../src/schema/readSchema"; | ||
import * as SchemaSchema from "../../src/schema/schemaSchemaInterface"; | ||
import { File, makeTestParser, resourceFile } from "../utils"; | ||
|
||
function parseSchemaFile(file: File): SchemaSchema.Root { | ||
const parse = makeTestParser(schemaSchema); | ||
const [errors, tree] = parse(file.read()); | ||
assert.isEmpty(errors, errors.join()); | ||
return (tree as unknown) as SchemaSchema.Root; | ||
} | ||
|
||
describe("readSchema()", () => { | ||
describe("schema_schema.hm", () => { | ||
const schemaSchemaFile = resourceFile("input", "schema_schema.hm"); | ||
|
||
it("produces a valid Schema", () => { | ||
const root = parseSchemaFile(schemaSchemaFile); | ||
const schemaDef = readSchema(root); | ||
assert.doesNotThrow(() => new Schema(schemaDef)); | ||
}); | ||
|
||
it("reproduces schemaSchema exactly", () => { | ||
const root = parseSchemaFile(schemaSchemaFile); | ||
const schemaDef = readSchema(root); | ||
assert.deepStrictEqual(schemaDef, schemaSchema); | ||
}); | ||
}); | ||
}); |