big tings

This commit is contained in:
Max Richter
2025-08-17 15:16:17 +02:00
parent 40b9be887d
commit c687eff53d
958 changed files with 32279 additions and 704 deletions

View File

@@ -4,4 +4,5 @@ use (
./parser ./parser
./registry ./registry
./renderer ./renderer
./template
) )

4
go.work.sum Normal file
View File

@@ -0,0 +1,4 @@
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=

View File

@@ -1,74 +0,0 @@
package parser
import (
"fmt"
"git.max-richter.dev/max/marka/parser/blocks"
)
// ExtractBlocks scans once, emitting:
// - data blocks: inner content between a line that's exactly "{" and a line that's exactly "}"
// - matching blocks: gaps between data blocks (excluding the brace lines themselves)
func ExtractBlocks(template string) ([]blocks.TemplateBlock, error) {
var out []blocks.TemplateBlock
var curlyIndex int
const CLOSING = '}'
const OPENING = '{'
var start int
var blockType blocks.BlockType
if len(template) > 0 && template[0] == OPENING {
curlyIndex = 1
blockType = blocks.DataBlock
} else {
blockType = blocks.MatchingBlock
}
for i, r := range template {
var nextCurlyIndex = curlyIndex
switch r {
case OPENING:
nextCurlyIndex++
case CLOSING:
nextCurlyIndex--
}
var nextChar rune = ' '
if i+1 < len(template) {
nextChar = rune(template[i+1])
}
if curlyIndex == 0 && nextCurlyIndex == 1 {
block, err := blocks.ParseTemplateBlock(template[start:i], blockType)
if err != nil {
return nil, fmt.Errorf("Failed to parse block: %w", err)
}
out = append(out, block)
start = i
blockType = blocks.DataBlock
} else if curlyIndex == 1 && nextCurlyIndex == 0 {
block, err := blocks.ParseTemplateBlock(template[start:i+1], blockType)
if err != nil {
return nil, fmt.Errorf("Failed to parse block: %w", err)
}
out = append(out, block)
if nextChar == OPENING {
start = i + 1
blockType = blocks.DataBlock
} else {
start = i + 1
blockType = blocks.MatchingBlock
}
}
curlyIndex = nextCurlyIndex
}
return out, nil
}

View File

@@ -1,5 +0,0 @@
package blocks
func (b TemplateBlock) ParseListBlock(input string) (key string, value any, error error) {
return "", nil, nil
}

View File

@@ -1,18 +0,0 @@
package blocks
import (
"fmt"
"go.yaml.in/yaml/v4"
)
func (b TemplateBlock) ParseYamlBlock(input string) (key string, value any, error error) {
res := make(map[string]any)
err := yaml.Unmarshal([]byte(input), &res)
if err != nil {
return "", nil, fmt.Errorf("failed to parse yaml: %w", err)
}
return "", nil, nil
}

View File

@@ -1,80 +0,0 @@
package blocks
import (
"strings"
)
// TemplateType represents whether a template is short, long, or invalid.
type TemplateType int
const (
InvalidTemplate TemplateType = iota
ShortTemplate
ExtendedTemplate
)
// DetectTemplateType checks if the template is short or long.
func DetectTemplateType(tmpl string) TemplateType {
trimmed := strings.TrimSpace(tmpl)
// Short type: starts with "{" and ends with "}" on a single line,
// and contains "|" or "," inside for inline definition
// Matchs for example { name | text,required }
if strings.HasPrefix(trimmed, "{") &&
strings.HasSuffix(trimmed, "}") &&
!strings.Contains(trimmed, "\n") {
return ShortTemplate
}
// Long type: multiline and contains keys like "path:" or "codec:" inside
// Matches for example:
// {
// path: name
// codec: text
// required: true
// }
if strings.Contains(trimmed, "\n") &&
(strings.Contains(trimmed, "path:") || strings.Contains(trimmed, "codec:")) {
return ExtendedTemplate
}
return InvalidTemplate
}
type BlockType string
const (
DataBlock BlockType = "data" // content between lines "{" and "}"
MatchingBlock BlockType = "matching" // everything outside data blocks
)
type BlockField struct {
Path string
CodecType CodecType
Required bool
}
type TemplateBlock struct {
Type BlockType
Path string
Codec CodecType
Required bool
Fields []BlockField
content string
}
func (b TemplateBlock) GetContent() string {
return b.content
}
func (p *TemplateBlock) Parse(input string) (key string, value any, err error) {
switch p.Codec {
case CodecText:
return p.Path, input, nil
case CodecYaml:
return p.ParseYamlBlock(input)
case CodecList:
return p.ParseListBlock(input)
}
return p.Path, "", nil
}

View File

@@ -1,141 +0,0 @@
package blocks
import (
"fmt"
"strings"
"go.yaml.in/yaml/v4"
)
func cleanTemplate(input string) string {
s := strings.TrimSpace(input)
s = strings.TrimPrefix(s, "{")
s = strings.TrimSuffix(s, "}")
return s
}
func parseShortTemplate(input string) (TemplateBlock, error) {
var split = strings.Split(cleanTemplate(input), "|")
if len(split) < 1 {
return TemplateBlock{}, fmt.Errorf("Invalid Short Template")
}
block := TemplateBlock{
Type: DataBlock,
Path: strings.TrimSpace(split[0]),
Codec: CodecText,
content: input,
}
if len(split) > 1 {
var optionSplit = strings.Split(split[1], ",")
for _, option := range optionSplit {
switch strings.TrimSpace(option) {
case "required":
block.Required = true
case "number":
block.Codec = CodecNumber
}
}
}
return block, nil
}
type yamlBlock struct {
Path string `yaml:"path"`
Codec string `yaml:"codec"`
Required bool `yaml:"required,omitempty"`
Fields []yamlField `yaml:"fields"`
Item *struct {
Template string `yaml:"template,omitempty"`
} `yaml:"item,omitempty"`
Template string `yaml:"template,omitempty"`
}
type yamlField struct {
Path string `yaml:"path"`
Value any `yaml:"value,omitempty"`
Codec string `yaml:"codec"`
Required bool `yaml:"required"`
}
func parseYamlTemplate(input string) (block TemplateBlock, err error) {
var blk yamlBlock
cleaned := cleanTemplate(input)
dec := yaml.NewDecoder(strings.NewReader(cleaned))
dec.KnownFields(true)
if err := dec.Decode(&blk); err != nil {
return block, err
}
if blk.Path == "" {
return block, fmt.Errorf("missing top-level 'path'")
}
if blk.Codec == "" {
blk.Codec = "text"
}
codec, err := parseCodecType(blk.Codec)
if err != nil {
return block, fmt.Errorf("failed to parse codec: %w", err)
}
var fields []BlockField
for _, field := range blk.Fields {
if field.Path == "" {
return block, fmt.Errorf("failed to parse field: %v", field)
}
if field.Codec == "" {
field.Codec = "text"
}
fieldCodec, err := parseCodecType(field.Codec)
if err != nil {
return block, fmt.Errorf("failed to parse codec: %w", err)
}
fields = append(fields, BlockField{
Path: field.Path,
CodecType: fieldCodec,
Required: field.Required,
})
}
return TemplateBlock{
Type: DataBlock,
Path: blk.Path,
Codec: codec,
Fields: fields,
content: input,
}, nil
}
func ParseTemplateBlock(template string, blockType BlockType) (block TemplateBlock, err error) {
if blockType == MatchingBlock {
return TemplateBlock{
Type: MatchingBlock,
content: template,
}, nil
}
switch DetectTemplateType(template) {
case ShortTemplate:
return parseShortTemplate(template)
case ExtendedTemplate:
return parseYamlTemplate(template)
}
return block, fmt.Errorf("Invalid Template")
}

View File

@@ -1,55 +0,0 @@
package parser_test
import (
"testing"
"git.max-richter.dev/max/marka/parser"
"git.max-richter.dev/max/marka/parser/blocks"
"git.max-richter.dev/max/marka/registry"
)
func TestExtractBlocks(t *testing.T) {
src, err := registry.GetTemplate("recipe")
if err != nil {
t.Errorf("Failed to extract blocks: %s", err.Error())
t.FailNow()
}
templateBlocks, err := parser.ExtractBlocks(src)
if err != nil {
t.Errorf("Failed to extract blocks: %s", err.Error())
t.FailNow()
}
expected := []struct {
Type blocks.BlockType
Content string
}{
{blocks.MatchingBlock, "---\n"},
{blocks.DataBlock, "{\n path: .\n codec: yaml\n fields:\n - path: name\n codec: text\n required: true\n - path: image\n codec: text\n required: true\n - path: author.@type\n codec: const\n value: Person\n - path: author.name\n codec: text\n - path: datePublished\n codec: text\n - path: description\n codec: text\n - path: prepTime\n codec: text\n - path: cookTime\n codec: text\n - path: recipeYield\n codec: text\n}"},
{blocks.MatchingBlock, "\n---\n\n# "},
{blocks.DataBlock, "{ name | text,required }"},
{blocks.MatchingBlock, "\n\n"},
{blocks.DataBlock, "{ description | text }"},
{blocks.MatchingBlock, "\n\n## Ingredients\n"},
{blocks.DataBlock, "{\n path: recipeIngredient\n codec: list\n required: true\n item:\n template: \"- { . }\"\n}"},
{blocks.MatchingBlock, "\n\n## Steps\n"},
{blocks.DataBlock, "{\n path: recipeInstructions\n codec: list\n required: true\n item:\n template: \"{ @index }. { . }\"\n}"},
}
if len(templateBlocks) != len(expected) {
t.Fatalf("expected %d blocks, got %d", len(expected), len(templateBlocks))
}
for i, b := range templateBlocks {
exp := expected[i]
if b.Type != exp.Type {
t.Errorf("Block#%d Type '%s' did not match expected type '%s'", i, b.Type, exp.Type)
}
content := b.GetContent()
if content != exp.Content {
t.Errorf("Block#%d Content '%s' did not match expected Content: '%s'", i, content, exp.Content)
}
}
}

View File

@@ -0,0 +1,41 @@
// Package decoders contains functions for parsing template.Block to a string.
package decoders
import (
"fmt"
"git.max-richter.dev/max/marka/parser/matcher"
"git.max-richter.dev/max/marka/parser/utils"
"git.max-richter.dev/max/marka/template"
)
func ParseBlock(input string, block template.Block) (any, error) {
switch block.Codec {
case template.CodecText:
return input, nil
case template.CodecYaml:
return Yaml(input, block)
case template.CodecList:
return List(input, block)
}
return nil, fmt.Errorf("unknown codec: %s", block.Codec)
}
func Parse(matches []matcher.Block) (any, error) {
var result any
for _, m := range matches {
if m.Block.Path == "@index" {
continue
}
input := m.GetContent()
value, err := ParseBlock(input, m.Block)
if err != nil {
return nil, fmt.Errorf("failed to parse block(%s): %w", m.Block.Path, err)
}
result = utils.SetPathValue(m.Block.Path, value, result)
}
return result, nil
}

View File

@@ -0,0 +1,56 @@
package decoders_test
import (
"encoding/json"
"fmt"
"testing"
"git.max-richter.dev/max/marka/parser/decoders"
"git.max-richter.dev/max/marka/parser/matcher"
"git.max-richter.dev/max/marka/parser/utils"
"git.max-richter.dev/max/marka/registry"
"git.max-richter.dev/max/marka/template"
)
func TestParseBaguette(t *testing.T) {
recipeMd := utils.ReadTestDataFile(t, "baguette.md")
templateContent, err := registry.GetTemplate("Recipe")
if err != nil {
t.Fatalf("Err: %s", err)
}
blocks, err := template.CompileTemplate(templateContent)
if err != nil {
t.Fatalf("Err: %s", err)
}
matches := matcher.MatchBlocksFuzzy(recipeMd, blocks, 0.3)
parsed, err := decoders.Parse(matches)
if err != nil {
t.Fatalf("Err: %s", err)
}
expected := map[string]any{
"name": "Baguette",
"description": "My favourite baguette recipe",
"recipeIngredient": []string{"Flour", "Water", "Salt"},
"recipeInstructions": []string{
"Mix Flour Water and Salt",
"Bake the bread",
},
}
out, _ := json.MarshalIndent(parsed, "", " ")
fmt.Printf("Parsed: \n%s\n", string(out))
outMap, ok := parsed.(map[string]any)
if !ok {
t.Fatalf("expected parsed to be map[string]any, got %T", parsed)
}
for k, v := range expected {
if fmt.Sprintf("%v", outMap[k]) != fmt.Sprintf("%v", v) {
t.Errorf("Expected %v but got %v", v, outMap[k])
}
}
}

31
parser/decoders/list.go Normal file
View File

@@ -0,0 +1,31 @@
package decoders
import (
"fmt"
"strings"
"git.max-richter.dev/max/marka/parser/matcher"
"git.max-richter.dev/max/marka/template"
)
func List(input string, block template.Block) (value any, error error) {
blocks, err := template.CompileTemplate(block.ListTemplate)
if err != nil {
return nil, fmt.Errorf("cannot extract blocks: %w", err)
}
var out []any
for line := range strings.SplitSeq(strings.TrimSuffix(input, "\n"), "\n") {
matches := matcher.MatchBlocksFuzzy(line, blocks, 0.3)
res, err := Parse(matches)
if err != nil {
return nil, fmt.Errorf("could not match blocks: %w", err)
}
out = append(out, res)
}
return out, nil
}

View File

@@ -0,0 +1,90 @@
package decoders_test
import (
"reflect"
"testing"
"git.max-richter.dev/max/marka/parser/decoders"
"git.max-richter.dev/max/marka/template"
)
func TestDecodeListObject(t *testing.T) {
templateBlock := template.Block{
Path: "ingredients",
Codec: template.CodecList,
ListTemplate: "- { amount } { type }",
}
input := "- 10g flour\n- 1/2cup water\n- 1tsp salt"
parsed, err := decoders.List(input, templateBlock)
if err != nil {
t.Fatalf("Err: %s", err)
}
want := []any{
map[string]any{
"amount": "10g",
"type": "flour",
},
map[string]any{
"amount": "1/2cup",
"type": "water",
},
map[string]any{
"amount": "1tsp",
"type": "salt",
},
}
if !reflect.DeepEqual(parsed, want) {
t.Fatalf("unexpected result.\n got: %#v\nwant: %#v", parsed, want)
}
}
func TestDecodeListString(t *testing.T) {
templateBlock := template.Block{
Path: "ingredients",
Codec: template.CodecList,
ListTemplate: "- { . }",
}
input := "- flour\n- water\n- salt"
parsed, err := decoders.List(input, templateBlock)
if err != nil {
t.Fatalf("Err: %s", err)
}
want := []any{
"flour",
"water",
"salt",
}
if !reflect.DeepEqual(parsed, want) {
t.Fatalf("unexpected result.\n got: %#v\nwant: %#v", parsed, want)
}
}
func TestDecodeNumberedListString(t *testing.T) {
templateBlock := template.Block{
Path: "ingredients",
Codec: template.CodecList,
ListTemplate: "{ @index } { . }",
}
input := "1. Wash and dry the lettuce.\n2. Halve the cherry tomatoes.\n3. Toss with olive oil and salt."
parsed, err := decoders.List(input, templateBlock)
if err != nil {
t.Fatalf("Err: %s", err)
}
want := []any{
"Wash and dry the lettuce.",
"Halve the cherry tomatoes.",
"Toss with olive oil and salt.",
}
if !reflect.DeepEqual(parsed, want) {
t.Fatalf("unexpected result.\n got: %#v\nwant: %#v", parsed, want)
}
}

32
parser/decoders/yaml.go Normal file
View File

@@ -0,0 +1,32 @@
package decoders
import (
"fmt"
"git.max-richter.dev/max/marka/parser/utils"
"git.max-richter.dev/max/marka/template"
"go.yaml.in/yaml/v4"
)
func Yaml(input string, block template.Block) (value any, error error) {
res := make(map[string]any)
err := yaml.Unmarshal([]byte(input), &res)
if err != nil {
return nil, fmt.Errorf("failed to parse yaml '%q': %w", input, err)
}
var out any
for _, f := range block.Fields {
if f.CodecType == template.CodecConst {
if f.Value != nil {
out = utils.SetPathValue(f.Path, f.Value, out)
}
} else {
if value, ok := res[f.Path]; ok {
out = utils.SetPathValue(f.Path, value, out)
}
}
}
return out, nil
}

View File

@@ -4,4 +4,7 @@ go 1.24.3
require github.com/agext/levenshtein v1.2.3 require github.com/agext/levenshtein v1.2.3
require go.yaml.in/yaml/v4 v4.0.0-rc.1 // indirect require (
github.com/google/go-cmp v0.7.0
go.yaml.in/yaml/v4 v4.0.0-rc.1 // indirect
)

View File

@@ -1,4 +1,6 @@
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
go.yaml.in/yaml/v4 v4.0.0-rc.1 h1:4J1+yLKUIPGexM/Si+9d3pij4hdc7aGO04NhrElqXbY= go.yaml.in/yaml/v4 v4.0.0-rc.1 h1:4J1+yLKUIPGexM/Si+9d3pij4hdc7aGO04NhrElqXbY=
go.yaml.in/yaml/v4 v4.0.0-rc.1/go.mod h1:CBdeces52/nUXndfQ5OY8GEQuNR9uEEOJPZj/Xq5IzU= go.yaml.in/yaml/v4 v4.0.0-rc.1/go.mod h1:CBdeces52/nUXndfQ5OY8GEQuNR9uEEOJPZj/Xq5IzU=

View File

@@ -2,16 +2,72 @@
// structured JSON objects that conform to a JSON Schema. // structured JSON objects that conform to a JSON Schema.
package parser package parser
func ParseFile(markdownContent string) (map[string]any, error) { import (
"fmt"
"strings"
// _schema, err := registry.GetTemplate("Recipe") "git.max-richter.dev/max/marka/parser/decoders"
// if err != nil { "git.max-richter.dev/max/marka/parser/matcher"
// return nil, fmt.Errorf("could not get schema: %w", err) "git.max-richter.dev/max/marka/registry"
// } "git.max-richter.dev/max/marka/template"
)
// Idea is to split the template into blocks, either "matching" blocks which are simple strings. func DetectType(markdownContent string) (string, error) {
// Or "data" blocks which match the content. Then i want to soft match the "matching" blocks and "data" blocks to the template. defaultSchemaContent, err := registry.GetTemplate("_default")
// The "matching" blocks should soft match with a levenshtein distance if err != nil {
return "", fmt.Errorf("could not get schema: %w", err)
return map[string]any{}, nil }
defaultSchema, err := template.CompileTemplate(defaultSchemaContent)
if err != nil {
return "", fmt.Errorf("failed to compile template: %w", err)
}
blocks := matcher.MatchBlocksFuzzy(markdownContent, defaultSchema, 0.3)
result, err := decoders.Parse(blocks)
if err != nil {
return "", fmt.Errorf("failed to parse blocks: %w", err)
}
if result, ok := result.(map[string]any); ok {
if contentType, ok := result["@type"]; ok {
return contentType.(string), nil
} else {
return "", fmt.Errorf("frontmatter did not contain '@type'")
}
} else {
return "", fmt.Errorf("could not parse frontmatter")
}
}
func ParseFile(markdownContent string) (any, error) {
markdownContent = strings.TrimSuffix(
strings.ReplaceAll(markdownContent, "@type:", `"@type":`),
"\n",
)
contentType, err := DetectType(markdownContent)
if err != nil {
return nil, fmt.Errorf("could not detect type: %w", err)
}
templateContent, err := registry.GetTemplate(contentType)
if err != nil {
return nil, fmt.Errorf("could not get schema: %w", err)
}
template, err := template.CompileTemplate(templateContent)
if err != nil {
return nil, fmt.Errorf("failed to compile template: %w", err)
}
blocks := matcher.MatchBlocksFuzzy(markdownContent, template, 0.3)
result, err := decoders.Parse(blocks)
if err != nil {
return nil, fmt.Errorf("failed to parse blocks: %w", err)
}
return result, nil
} }

View File

@@ -4,10 +4,10 @@ import (
"encoding/json" "encoding/json"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"testing" "testing"
"git.max-richter.dev/max/marka/parser" "git.max-richter.dev/max/marka/parser"
"github.com/google/go-cmp/cmp"
) )
func TestParseRecipe_Golden(t *testing.T) { func TestParseRecipe_Golden(t *testing.T) {
@@ -34,10 +34,7 @@ func TestParseRecipe_Golden(t *testing.T) {
t.Fatalf("unmarshal expected.json: %v", err) t.Fatalf("unmarshal expected.json: %v", err)
} }
// Deep structural compare if diff := cmp.Diff(want, got); diff != "" {
if !reflect.DeepEqual(want, got) { t.Fatalf("JSON mismatch (-want +got):\n%s", diff)
gb, _ := json.MarshalIndent(got, "", " ")
wb, _ := json.MarshalIndent(want, "", " ")
t.Fatalf("parsed JSON mismatch\n--- got ---\n%s\n--- want ---\n%s", string(gb), string(wb))
} }
} }

View File

@@ -1,19 +1,22 @@
package parser // Package matcher contains functions for matching template.Block to a string.
package matcher
import ( import (
"math" "math"
"git.max-richter.dev/max/marka/parser/blocks" "git.max-richter.dev/max/marka/parser/utils"
"git.max-richter.dev/max/marka/template"
"github.com/agext/levenshtein" "github.com/agext/levenshtein"
) )
type MatchBlock struct { // Block matches a template.Block to a section inside a string
type Block struct {
Start, End int Start, End int
Block blocks.TemplateBlock Block template.Block
src *string src *string
} }
func (m MatchBlock) GetContent() string { func (m Block) GetContent() string {
if m.src == nil || m.Start < 0 || m.End > len(*m.src) || m.Start > m.End { if m.src == nil || m.Start < 0 || m.End > len(*m.src) || m.Start > m.End {
return "" return ""
} }
@@ -23,18 +26,18 @@ func (m MatchBlock) GetContent() string {
// MatchBlocksFuzzy finds anchor positions for all BlockMatching blocks using // MatchBlocksFuzzy finds anchor positions for all BlockMatching blocks using
// Levenshtein distance (tolerant matching), then returns ONLY the BlockData // Levenshtein distance (tolerant matching), then returns ONLY the BlockData
// segments as gaps between those anchors. // segments as gaps between those anchors.
func MatchBlocksFuzzy(markdown string, templateBlocks []blocks.TemplateBlock, maxDist float64) []MatchBlock { func MatchBlocksFuzzy(markdown string, templateBlocks []template.Block, maxDist float64) []Block {
var out []MatchBlock var out []Block
var lastIndex = 0 lastIndex := 0
for i, b := range templateBlocks { for i, b := range templateBlocks {
if b.Type == blocks.MatchingBlock { if b.Type == template.MatchingBlock {
start, end := FuzzyFind(markdown, lastIndex, b.GetContent(), 0.3) start, end := FuzzyFind(markdown, lastIndex, b.GetContent(), 0.3)
if end != -1 { if end != -1 {
if i > 0 { if i > 0 {
previousBlock := templateBlocks[i-1] previousBlock := templateBlocks[i-1]
if previousBlock.Type == blocks.DataBlock { if previousBlock.Type == template.DataBlock {
out = append(out, MatchBlock{ out = append(out, Block{
Start: lastIndex, Start: lastIndex,
End: start, End: start,
Block: previousBlock, Block: previousBlock,
@@ -48,15 +51,17 @@ func MatchBlocksFuzzy(markdown string, templateBlocks []blocks.TemplateBlock, ma
} }
// Handle the last block // Handle the last block
if len(templateBlocks) > 0 {
lastBlock := templateBlocks[len(templateBlocks)-1] lastBlock := templateBlocks[len(templateBlocks)-1]
if lastBlock.Type == blocks.DataBlock { if lastBlock.Type == template.DataBlock {
out = append(out, MatchBlock{ out = append(out, Block{
Start: lastIndex, Start: lastIndex,
End: len(markdown), End: len(markdown),
Block: lastBlock, Block: lastBlock,
src: &markdown, src: &markdown,
}) })
} }
}
return out return out
} }
@@ -72,7 +77,7 @@ func FuzzyFind(haystack string, from int, needle string, maxDist float64) (start
sub := haystack[i : i+windowSize] sub := haystack[i : i+windowSize]
dist := levenshtein.Distance(sub, needle, nil) dist := levenshtein.Distance(sub, needle, nil)
maxLen := max(needleLen, windowSize) maxLen := max(needleLen, windowSize)
norm := float64(dist)/float64(maxLen) + float64(abs(windowSize-needleLen))*0.01/float64(maxLen) norm := float64(dist)/float64(maxLen) + float64(utils.Abs(windowSize-needleLen))*0.01/float64(maxLen)
if norm < bestDist { if norm < bestDist {
bestStart, bestEnd, bestDist = i, i+windowSize, norm bestStart, bestEnd, bestDist = i, i+windowSize, norm
@@ -88,17 +93,3 @@ func FuzzyFind(haystack string, from int, needle string, maxDist float64) (start
} }
return -1, -1 return -1, -1
} }
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
func max(a, b int) int {
if a > b {
return a
}
return b
}

View File

@@ -1,14 +1,17 @@
package parser_test package matcher_test
import ( import (
"fmt"
"testing" "testing"
"git.max-richter.dev/max/marka/parser" "git.max-richter.dev/max/marka/parser/matcher"
"git.max-richter.dev/max/marka/parser/utils"
"git.max-richter.dev/max/marka/registry" "git.max-richter.dev/max/marka/registry"
"git.max-richter.dev/max/marka/template"
) )
func TestFuzzyFindAll(t *testing.T) { func TestFuzzyFindAll(t *testing.T) {
recipeMd := readTestDataFile(t, "baguette.md") recipeMd := utils.ReadTestDataFile(t, "baguette.md")
tests := []struct { tests := []struct {
Needle string Needle string
@@ -25,24 +28,32 @@ func TestFuzzyFindAll(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
start, end := parser.FuzzyFind(recipeMd, test.StartIndex, test.Needle, 0.3) // allow 50% error start, end := matcher.FuzzyFind(recipeMd, test.StartIndex, test.Needle, 0.3) // allow 50% error
if start != test.Start || end != test.End { if start != test.Start || end != test.End {
t.Errorf("Start or end do not match: Needle=%q Start=%d/%d End=%d/%d", test.Needle, test.Start, start, test.End, end) t.Errorf("Start or end do not match: Needle=%q Start=%d/%d End=%d/%d", test.Needle, test.Start, start, test.End, end)
} }
} }
} }
func TestFuzzyBlockMatch(t *testing.T) { func TestFuzzyBlockMatch(t *testing.T) {
recipeMd := readTestDataFile(t, "baguette.md") recipeMd := utils.ReadTestDataFile(t, "baguette.md")
schemaMd, err := registry.GetTemplate("recipe") schemaMd, err := registry.GetTemplate("Recipe")
if err != nil { if err != nil {
t.Errorf("Failed to load template: %s", err.Error()) t.Errorf("Failed to load template: %s", err.Error())
t.FailNow() t.FailNow()
} }
blocks, _ := parser.ExtractBlocks(schemaMd) blocks, err := template.CompileTemplate(schemaMd)
matches := parser.MatchBlocksFuzzy(recipeMd, blocks, 0.3) if err != nil {
t.Errorf("Failed to compile template: %s", err.Error())
t.FailNow()
}
for _, b := range blocks {
fmt.Printf("block: %#v\n", b)
}
matches := matcher.MatchBlocksFuzzy(recipeMd, blocks, 0.3)
expected := []struct { expected := []struct {
value string value string
@@ -73,5 +84,4 @@ func TestFuzzyBlockMatch(t *testing.T) {
t.Errorf("Match %d did not match expected: %q", i, m.GetContent()) t.Errorf("Match %d did not match expected: %q", i, m.GetContent())
} }
} }
} }

View File

@@ -1,15 +0,0 @@
package parser
func Parse(blocks []MatchBlock) map[string]any {
result := make(map[string]any)
for _, b := range blocks {
input := b.GetContent()
key, value, _ := b.Block.Parse(input)
result[key] = value
}
return result
}

View File

@@ -1,42 +0,0 @@
package parser_test
import (
"fmt"
"testing"
"git.max-richter.dev/max/marka/parser"
"git.max-richter.dev/max/marka/registry"
)
func TestParseBaguette(t *testing.T) {
recipeMd := readTestDataFile(t, "baguette.md")
template, err := registry.GetTemplate("recipe")
if err != nil {
t.Fatalf("Err: %s", err)
}
blocks, err := parser.ExtractBlocks(template)
if err != nil {
t.Fatalf("Err: %s", err)
}
matches := parser.MatchBlocksFuzzy(recipeMd, blocks, 0.3)
parsed := parser.Parse(matches)
expected := map[string]any{
"name": "Baguette",
"description": "My favourite baguette recipe",
"recipeIngredient": []string{"Flour", "Water", "Salt"},
// "recipeInstructions": []string{
// "Mix Flour Water and Salt",
// "Bake the bread",
// },
}
for k, v := range expected {
if fmt.Sprintf("%v", parsed[k]) != fmt.Sprintf("%v", v) {
t.Errorf("Expected %v but got %v", v, parsed[k])
}
}
}

View File

@@ -1,8 +1,7 @@
--- ---
@type: Recipe @type: Recipe
image: https://example.com/salad.jpg image: https://example.com/salad.jpg
author: Alex Chef author.name: Alex Chef
datePublished: 2025-08-12
prepTime: PT10M prepTime: PT10M
cookTime: PT0M cookTime: PT0M
recipeYield: 2 servings recipeYield: 2 servings

View File

@@ -1,5 +1,5 @@
{ {
"@context": "https://schema.org/", "@context": "https://schema.org",
"@type": "Recipe", "@type": "Recipe",
"name": "Simple Salad", "name": "Simple Salad",
"image": "https://example.com/salad.jpg", "image": "https://example.com/salad.jpg",
@@ -7,7 +7,6 @@
"@type": "Person", "@type": "Person",
"name": "Alex Chef" "name": "Alex Chef"
}, },
"datePublished": "2025-08-12",
"description": "A quick green salad.", "description": "A quick green salad.",
"prepTime": "PT10M", "prepTime": "PT10M",
"cookTime": "PT0M", "cookTime": "PT0M",

8
parser/utils/math.go Normal file
View File

@@ -0,0 +1,8 @@
package utils
func Abs(x int) int {
if x < 0 {
return -x
}
return x
}

View File

@@ -1,4 +1,4 @@
package parser_test package utils
import ( import (
"os" "os"
@@ -6,8 +6,8 @@ import (
"testing" "testing"
) )
func readTestDataFile(t *testing.T, fileName string) string { func ReadTestDataFile(t *testing.T, fileName string) string {
path := filepath.Join("testdata", fileName) path := filepath.Join("../testdata", fileName)
data, err := os.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
t.Fatalf("failed to read test data file: %v", err) t.Fatalf("failed to read test data file: %v", err)

View File

@@ -0,0 +1,65 @@
// Package utils contains utility functions for the parser package.
package utils
import (
"maps"
"strings"
)
// SetPathValue sets value at a dot-separated path in obj, creating maps as needed.
// If the path is only dots (e.g., "." or ".."):
// - when obj == nil -> returns value directly (e.g., "flour")
// - when obj is a map -> if value is a map[string]any, merge into obj; otherwise obj is unchanged.
// - otherwise -> returns obj unchanged.
func SetPathValue(path string, value any, obj any) any {
// Split and drop empty segments (so ".", "..", "" become no keys)
raw := strings.Split(path, ".")
keys := raw[:0]
for _, k := range raw {
if k != "" {
keys = append(keys, k)
}
}
// Root case: no keys after trimming dots
if len(keys) == 0 {
if obj == nil {
return value
}
if m, ok := obj.(map[string]any); ok {
if mv, ok := value.(map[string]any); ok {
maps.Copy(m, mv)
}
return m
}
return obj
}
// Ensure root is a map
var root map[string]any
if obj == nil {
root = map[string]any{}
} else if m, ok := obj.(map[string]any); ok {
root = m
} else {
// if obj is not a map, just overwrite it with a new map
root = map[string]any{}
}
// Descend/construct maps
curr := root
for i, k := range keys {
if i == len(keys)-1 {
curr[k] = value
break
}
if next, ok := curr[k].(map[string]any); ok {
curr = next
continue
}
n := map[string]any{}
curr[k] = n
curr = n
}
return root
}

View File

@@ -0,0 +1,132 @@
package utils
import (
"fmt"
"reflect"
"testing"
)
func TestSetPathValue_SingleKey(t *testing.T) {
input := map[string]any{}
got := SetPathValue("name", "Max", input)
want := map[string]any{"name": "Max"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected map.\n got: %#v\nwant: %#v", got, want)
}
}
func TestSetPathValue_DotSyntax(t *testing.T) {
input := map[string]any{}
meta := map[string]any{
"name": "Max",
}
got := SetPathValue(".", meta, input)
want := map[string]any{"name": "Max"}
fmt.Printf("%+v\n", got)
if !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected map.\n got: %#v\nwant: %#v", got, want)
}
}
func TestSetPathValue_DotSyntaxString(t *testing.T) {
var input any
meta := "flour"
got := SetPathValue(".", meta, input)
want := "flour"
fmt.Printf("%+v\n", got)
if !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected map.\n got: %#v\nwant: %#v", got, want)
}
}
func TestSetPathValue_NestedKeys_CreateMissingMaps(t *testing.T) {
input := map[string]any{}
got := SetPathValue("user.profile.name", "Max", input)
// Desired behavior: create nested maps and set the value.
// NOTE: If this test fails, your implementation likely isn't descending into nested maps.
want := map[string]any{
"user": map[string]any{
"profile": map[string]any{
"name": "Max",
},
},
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected map for nested keys.\n got: %#v\nwant: %#v", got, want)
}
}
func TestSetPathValue_OverwriteExistingValue(t *testing.T) {
input := map[string]any{"foo": "old"}
got := SetPathValue("foo", "new", input)
want := map[string]any{"foo": "new"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected map after overwrite.\n got: %#v\nwant: %#v", got, want)
}
}
func TestSetPathValue_PartiallyExistingPath(t *testing.T) {
input := map[string]any{
"user": map[string]any{
"profile": map[string]any{},
},
}
got := SetPathValue("user.profile.age", 28, input)
want := map[string]any{
"user": map[string]any{
"profile": map[string]any{
"age": 28,
},
},
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected map with partially existing path.\n got: %#v\nwant: %#v", got, want)
}
}
func TestSetPathValue_EmptySegmentsAreIgnored(t *testing.T) {
input := map[string]any{}
got := SetPathValue("a..b", 1, input)
// Expected behavior (common-sense): treat empty segments as no-op and still set a.b = 1
want := map[string]any{
"a": map[string]any{
"b": 1,
},
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected map with empty segments.\n got: %#v\nwant: %#v", got, want)
}
}
func TestSetPathValue_ComplexValueTypes(t *testing.T) {
input := map[string]any{}
val := []int{1, 2, 3}
got := SetPathValue("nums.list", val, input)
want := map[string]any{
"nums": map[string]any{
"list": []int{1, 2, 3},
},
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected map with complex value types.\n got: %#v\nwant: %#v", got, want)
}
}

View File

@@ -1,3 +1,7 @@
module git.max-richter.dev/max/marka/registry module git.max-richter.dev/max/marka/registry
go 1.24.3 go 1.24.3
require github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
require golang.org/x/text v0.14.0 // indirect

4
registry/go.sum Normal file
View File

@@ -0,0 +1,4 @@
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=

View File

@@ -1,48 +0,0 @@
// Package registry provides functionality for managing and accessing embedded file systems and directories.
package registry
import (
"embed"
"io"
"io/fs"
"os"
)
type Source interface {
Open(name string) (fs.File, error)
ReadFile(name string) ([]byte, error)
ReadDir(name string) ([]fs.DirEntry, error)
}
type src struct{ fsys fs.FS }
func (s src) Open(p string) (fs.File, error) { return s.fsys.Open(p) }
func (s src) ReadFile(p string) ([]byte, error) { return fs.ReadFile(s.fsys, p) }
func (s src) ReadDir(p string) ([]fs.DirEntry, error) { return fs.ReadDir(s.fsys, p) }
func FromDir(path string) Source { return src{fsys: os.DirFS(path)} }
//go:embed templates/*
var templates embed.FS
//go:embed schema-org/*
var schemas embed.FS
func GetTemplates() Source {
return src{fsys: templates}
}
func GetTemplate(name string) (string, error) {
templateFile, err := templates.Open("templates/" + name + ".marka")
if err != nil {
return "", err
}
defer templateFile.Close()
templateBytes, err := io.ReadAll(templateFile)
if err != nil {
return "", err
}
return string(templateBytes), nil
}

View File

@@ -0,0 +1,19 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:3DModel",
"title": "3DModel",
"description": "A 3D model represents some kind of 3D content, which may have [[encoding]]s in one or more [[MediaObject]]s. Many 3D formats are available (e.g. see [Wikipedia](https://en.wikipedia.org/wiki/Category:3D_graphics_file_formats)); specific encoding formats can be represented using the [[encodingFormat]] property applied to the relevant [[MediaObject]]. For the\ncase of a single file published after Zip compression, the convention of appending '+zip' to the [[encodingFormat]] can be used. Geospatial, AR/VR, artistic/animation, gaming, engineering and scientific content can all be represented using [[3DModel]].",
"type": "object",
"allOf": [
{
"description": "A media object, such as an image, video, audio, or text object embedded in a web page or a downloadable dataset i.e. DataDownload. Note that a creative work may have many media objects associated with it on the same web page. For example, a page about a single song (MusicRecording) may have a music video (VideoObject), and a high and low bandwidth audio stream (2 AudioObject's).",
"$ref": "schema:MediaObject"
}
],
"properties": {
"isResizable": {
"description": "Whether the 3DModel allows resizing. For example, room layout applications often do not allow 3DModel elements to be resized to reflect reality.",
"type": "boolean"
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AMRadioChannel",
"title": "AMRadioChannel",
"description": "A radio channel that uses AM.",
"type": "object",
"allOf": [
{
"description": "A unique instance of a radio BroadcastService on a CableOrSatelliteService lineup.",
"$ref": "schema:RadioChannel"
}
]
}

View File

@@ -0,0 +1,44 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:APIReference",
"title": "APIReference",
"description": "Reference documentation for application programming interfaces (APIs).",
"type": "object",
"allOf": [
{
"description": "A technical article - Example: How-to (task) topics, step-by-step, procedural troubleshooting, specifications, etc.",
"$ref": "schema:TechArticle"
}
],
"properties": {
"assembly": {
"description": "Library file name, e.g., mscorlib.dll, system.web.dll.",
"type": "string"
},
"assemblyVersion": {
"description": "Associated product/technology version. E.g., .NET Framework 4.5.",
"type": "string"
},
"executableLibraryName": {
"description": "Library file name, e.g., mscorlib.dll, system.web.dll.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
},
"programmingModel": {
"description": "Indicates whether API is managed or unmanaged.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
},
"targetPlatform": {
"description": "Type of app development: phone, Metro style, desktop, XBox, etc.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AboutPage",
"title": "AboutPage",
"description": "Web page type: About page.",
"type": "object",
"allOf": [
{
"description": "A web page. Every web page is implicitly assumed to be declared to be of type WebPage, so the various properties about that webpage, such as breadcrumb may be used. We recommend explicit declaration if these properties are specified, but if they are found outside of an itemscope, they will be assumed to be about the page.",
"$ref": "schema:WebPage"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AcceptAction",
"title": "AcceptAction",
"description": "The act of committing to/adopting an object.\\n\\nRelated actions:\\n\\n* [[RejectAction]]: The antonym of AcceptAction.",
"type": "object",
"allOf": [
{
"description": "The act of organizing tasks/objects/events by associating resources to it.",
"$ref": "schema:AllocateAction"
}
]
}

View File

@@ -0,0 +1,127 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Accommodation",
"title": "Accommodation",
"description": "An accommodation is a place that can accommodate human beings, e.g. a hotel room, a camping pitch, or a meeting room. Many accommodations are for overnight stays, but this is not a mandatory requirement.\nFor more specific types of accommodations not defined in schema.org, one can use [[additionalType]] with external vocabularies.\n\nSee also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations.\n",
"type": "object",
"allOf": [
{
"description": "Entities that have a somewhat fixed, physical extension.",
"$ref": "schema:Place"
}
],
"properties": {
"accommodationCategory": {
"description": "Category of an [[Accommodation]], following real estate conventions, e.g. RESO (see [PropertySubType](https://ddwiki.reso.org/display/DDW17/PropertySubType+Field), and [PropertyType](https://ddwiki.reso.org/display/DDW17/PropertyType+Field) fields for suggested values).",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
},
"accommodationFloorPlan": {
"description": "A floorplan of some [[Accommodation]].",
"oneOf": [
{ "$ref": "schema:FloorPlan" },
{ "type": "array", "items": { "$ref": "schema:FloorPlan" } }
]
},
"amenityFeature": {
"description": "An amenity feature (e.g. a characteristic or service) of the Accommodation. This generic property does not make a statement about whether the feature is included in an offer for the main accommodation or available at extra costs.",
"oneOf": [
{ "$ref": "schema:LocationFeatureSpecification" },
{
"type": "array",
"items": { "$ref": "schema:LocationFeatureSpecification" }
}
]
},
"bed": {
"description": "The type of bed or beds included in the accommodation. For the single case of just one bed of a certain type, you use bed directly with a text.\n If you want to indicate the quantity of a certain kind of bed, use an instance of BedDetails. For more detailed information, use the amenityFeature property.",
"anyOf": [
{ "type": "string" },
{ "$ref": "schema:BedDetails" },
{ "$ref": "schema:BedType" }
]
},
"floorLevel": {
"description": "The floor level for an [[Accommodation]] in a multi-storey building. Since counting\n systems [vary internationally](https://en.wikipedia.org/wiki/Storey#Consecutive_number_floor_designations), the local system should be used where possible.",
"type": "string"
},
"floorSize": {
"description": "The size of the accommodation, e.g. in square meter or squarefoot.\nTypical unit code(s): MTK for square meter, FTK for square foot, or YDK for square yard.",
"$ref": "schema:QuantitativeValue"
},
"leaseLength": {
"description": "Length of the lease for some [[Accommodation]], either particular to some [[Offer]] or in some cases intrinsic to the property.",
"oneOf": [
{
"anyOf": [
{ "type": "string", "$comment": "https://schema.org/Duration" },
{ "$ref": "schema:QuantitativeValue" }
]
},
{
"type": "array",
"items": {
"anyOf": [
{ "type": "string", "$comment": "https://schema.org/Duration" },
{ "$ref": "schema:QuantitativeValue" }
]
}
}
]
},
"numberOfBathroomsTotal": {
"description": "The total integer number of bathrooms in some [[Accommodation]], following real estate conventions as [documented in RESO](https://ddwiki.reso.org/display/DDW17/BathroomsTotalInteger+Field): \"The simple sum of the number of bathrooms. For example for a property with two Full Bathrooms and one Half Bathroom, the Bathrooms Total Integer will be 3.\". See also [[numberOfRooms]].",
"type": "integer"
},
"numberOfBedrooms": {
"description": "The total integer number of bedrooms in a some [[Accommodation]], [[ApartmentComplex]] or [[FloorPlan]].",
"anyOf": [{ "type": "number" }, { "$ref": "schema:QuantitativeValue" }]
},
"numberOfFullBathrooms": {
"description": "Number of full bathrooms - The total number of full and ¾ bathrooms in an [[Accommodation]]. This corresponds to the [BathroomsFull field in RESO](https://ddwiki.reso.org/display/DDW17/BathroomsFull+Field).",
"oneOf": [
{ "type": "number" },
{ "type": "array", "items": { "type": "number" } }
]
},
"numberOfPartialBathrooms": {
"description": "Number of partial bathrooms - The total number of half and ¼ bathrooms in an [[Accommodation]]. This corresponds to the [BathroomsPartial field in RESO](https://ddwiki.reso.org/display/DDW17/BathroomsPartial+Field). ",
"oneOf": [
{ "type": "number" },
{ "type": "array", "items": { "type": "number" } }
]
},
"numberOfRooms": {
"description": "The number of rooms (excluding bathrooms and closets) of the accommodation or lodging business.\nTypical unit code(s): ROM for room or C62 for no unit. The type of room can be put in the unitText property of the QuantitativeValue.",
"anyOf": [{ "type": "number" }, { "$ref": "schema:QuantitativeValue" }]
},
"occupancy": {
"description": "The allowed total occupancy for the accommodation in persons (including infants etc). For individual accommodations, this is not necessarily the legal maximum but defines the permitted usage as per the contractual agreement (e.g. a double room used by a single person).\nTypical unit code(s): C62 for person.",
"$ref": "schema:QuantitativeValue"
},
"permittedUsage": {
"description": "Indications regarding the permitted usage of the accommodation.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
},
"petsAllowed": {
"description": "Indicates whether pets are allowed to enter the accommodation or lodging business. More detailed information can be put in a text value.",
"anyOf": [{ "type": "boolean" }, { "type": "string" }]
},
"tourBookingPage": {
"description": "A page providing information on how to book a tour of some [[Place]], such as an [[Accommodation]] or [[ApartmentComplex]] in a real estate setting, as well as other kinds of tours as appropriate.",
"oneOf": [
{ "type": "string", "format": "uri" },
{ "type": "array", "items": { "type": "string", "format": "uri" } }
]
},
"yearBuilt": {
"description": "The year an [[Accommodation]] was constructed. This corresponds to the [YearBuilt field in RESO](https://ddwiki.reso.org/display/DDW17/YearBuilt+Field). ",
"type": "number"
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AccountingService",
"title": "AccountingService",
"description": "Accountancy business.\\n\\nAs a [[LocalBusiness]] it can be described as a [[provider]] of one or more [[Service]]\\(s).\n ",
"type": "object",
"allOf": [
{
"description": "Financial services business.",
"$ref": "schema:FinancialService"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AchieveAction",
"title": "AchieveAction",
"description": "The act of accomplishing something via previous efforts. It is an instantaneous action rather than an ongoing process.",
"type": "object",
"allOf": [
{
"description": "An action performed by a direct agent and indirect participants upon a direct object. Optionally happens at a location with the help of an inanimate instrument. The execution of the action may produce a result. Specific action sub-type documentation specifies the exact expectation of each argument/role.\\n\\nSee also [blog post](http://blog.schema.org/2014/04/announcing-schemaorg-actions.html) and [Actions overview document](https://schema.org/docs/actions.html).",
"$ref": "schema:Action"
}
]
}

View File

@@ -0,0 +1,116 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Action",
"title": "Action",
"description": "An action performed by a direct agent and indirect participants upon a direct object. Optionally happens at a location with the help of an inanimate instrument. The execution of the action may produce a result. Specific action sub-type documentation specifies the exact expectation of each argument/role.\\n\\nSee also [blog post](http://blog.schema.org/2014/04/announcing-schemaorg-actions.html) and [Actions overview document](https://schema.org/docs/actions.html).",
"type": "object",
"allOf": [
{ "description": "The most generic type of item.", "$ref": "schema:Thing" }
],
"properties": {
"actionProcess": {
"description": "Description of the process by which the action was performed.",
"oneOf": [
{ "$ref": "schema:HowTo" },
{ "type": "array", "items": { "$ref": "schema:HowTo" } }
]
},
"actionStatus": {
"description": "Indicates the current disposition of the Action.",
"oneOf": [
{ "$ref": "schema:ActionStatusType" },
{ "type": "array", "items": { "$ref": "schema:ActionStatusType" } }
]
},
"agent": {
"description": "The direct performer or driver of the action (animate or inanimate). E.g. *John* wrote a book.",
"anyOf": [{ "$ref": "schema:Organization" }, { "$ref": "schema:Person" }]
},
"endTime": {
"description": "The endTime of something. For a reserved event or service (e.g. FoodEstablishmentReservation), the time that it is expected to end. For actions that span a period of time, when the action was performed. E.g. John wrote a book from January to *December*. For media, including audio and video, it's the time offset of the end of a clip within a larger file.\\n\\nNote that Event uses startDate/endDate instead of startTime/endTime, even when describing dates with times. This situation may be clarified in future revisions.",
"anyOf": [
{ "type": "string", "format": "date-time" },
{ "type": "string", "format": "time" }
]
},
"error": {
"description": "For failed actions, more information on the cause of the failure.",
"oneOf": [
{ "$ref": "schema:Thing" },
{ "type": "array", "items": { "$ref": "schema:Thing" } }
]
},
"instrument": {
"description": "The object that helped the agent perform the action. E.g. John wrote a book with *a pen*.",
"$ref": "schema:Thing"
},
"location": {
"description": "The location of, for example, where an event is happening, where an organization is located, or where an action takes place.",
"anyOf": [
{ "type": "string" },
{ "$ref": "schema:Place" },
{ "$ref": "schema:PostalAddress" },
{ "$ref": "schema:VirtualLocation" }
]
},
"object": {
"description": "The object upon which the action is carried out, whose state is kept intact or changed. Also known as the semantic roles patient, affected or undergoer (which change their state) or theme (which doesn't). E.g. John read *a book*.",
"$ref": "schema:Thing"
},
"participant": {
"description": "Other co-agents that participated in the action indirectly. E.g. John wrote a book with *Steve*.",
"oneOf": [
{
"anyOf": [
{ "$ref": "schema:Organization" },
{ "$ref": "schema:Person" }
]
},
{
"type": "array",
"items": {
"anyOf": [
{ "$ref": "schema:Organization" },
{ "$ref": "schema:Person" }
]
}
}
]
},
"provider": {
"description": "The service provider, service operator, or service performer; the goods producer. Another party (a seller) may offer those services or goods on behalf of the provider. A provider may also serve as the seller.",
"anyOf": [{ "$ref": "schema:Organization" }, { "$ref": "schema:Person" }]
},
"result": {
"description": "The result produced in the action. E.g. John wrote *a book*.",
"$ref": "schema:Thing"
},
"startTime": {
"description": "The startTime of something. For a reserved event or service (e.g. FoodEstablishmentReservation), the time that it is expected to start. For actions that span a period of time, when the action was performed. E.g. John wrote a book from *January* to December. For media, including audio and video, it's the time offset of the start of a clip within a larger file.\\n\\nNote that Event uses startDate/endDate instead of startTime/endTime, even when describing dates with times. This situation may be clarified in future revisions.",
"anyOf": [
{ "type": "string", "format": "date-time" },
{ "type": "string", "format": "time" }
]
},
"target": {
"description": "Indicates a target EntryPoint, or url, for an Action.",
"oneOf": [
{
"anyOf": [
{ "type": "string", "format": "uri" },
{ "$ref": "schema:EntryPoint" }
]
},
{
"type": "array",
"items": {
"anyOf": [
{ "type": "string", "format": "uri" },
{ "$ref": "schema:EntryPoint" }
]
}
}
]
}
}
}

View File

@@ -0,0 +1,84 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ActionAccessSpecification",
"title": "ActionAccessSpecification",
"description": "A set of requirements that must be fulfilled in order to perform an Action.",
"type": "object",
"allOf": [
{
"description": "A utility class that serves as the umbrella for a number of 'intangible' things such as quantities, structured values, etc.",
"$ref": "schema:Intangible"
}
],
"properties": {
"availabilityEnds": {
"description": "The end of the availability of the product or service included in the offer.",
"anyOf": [
{ "type": "string", "format": "date" },
{ "type": "string", "format": "date-time" },
{ "type": "string", "format": "time" }
]
},
"availabilityStarts": {
"description": "The beginning of the availability of the product or service included in the offer.",
"anyOf": [
{ "type": "string", "format": "date" },
{ "type": "string", "format": "date-time" },
{ "type": "string", "format": "time" }
]
},
"category": {
"description": "A category for the item. Greater signs or slashes can be used to informally indicate a category hierarchy.",
"oneOf": [
{
"anyOf": [
{ "type": "string", "format": "uri" },
{ "type": "string" },
{ "$ref": "schema:CategoryCode" },
{ "$ref": "schema:PhysicalActivityCategory" },
{ "$ref": "schema:Thing" }
]
},
{
"type": "array",
"items": {
"anyOf": [
{ "type": "string", "format": "uri" },
{ "type": "string" },
{ "$ref": "schema:CategoryCode" },
{ "$ref": "schema:PhysicalActivityCategory" },
{ "$ref": "schema:Thing" }
]
}
}
]
},
"eligibleRegion": {
"description": "The ISO 3166-1 (ISO 3166-1 alpha-2) or ISO 3166-2 code, the place, or the GeoShape for the geo-political region(s) for which the offer or delivery charge specification is valid.\\n\\nSee also [[ineligibleRegion]].\n ",
"anyOf": [
{ "type": "string" },
{ "$ref": "schema:GeoShape" },
{ "$ref": "schema:Place" }
]
},
"expectsAcceptanceOf": {
"description": "An Offer which must be accepted before the user can perform the Action. For example, the user may need to buy a movie before being able to watch it.",
"oneOf": [
{ "$ref": "schema:Offer" },
{ "type": "array", "items": { "$ref": "schema:Offer" } }
]
},
"ineligibleRegion": {
"description": "The ISO 3166-1 (ISO 3166-1 alpha-2) or ISO 3166-2 code, the place, or the GeoShape for the geo-political region(s) for which the offer or delivery charge specification is not valid, e.g. a region where the transaction is not allowed.\\n\\nSee also [[eligibleRegion]].\n ",
"anyOf": [
{ "type": "string" },
{ "$ref": "schema:GeoShape" },
{ "$ref": "schema:Place" }
]
},
"requiresSubscription": {
"description": "Indicates if use of the media require a subscription (either paid or free). Allowed values are ```true``` or ```false``` (note that an earlier version had 'yes', 'no').",
"anyOf": [{ "type": "boolean" }, { "$ref": "schema:MediaSubscription" }]
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ActionStatusType",
"title": "ActionStatusType",
"description": "The status of an Action.",
"type": "object",
"allOf": [
{
"description": "Lists or enumerations dealing with status types.",
"$ref": "schema:StatusEnumeration"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ActivateAction",
"title": "ActivateAction",
"description": "The act of starting or activating a device or application (e.g. starting a timer or turning on a flashlight).",
"type": "object",
"allOf": [
{
"description": "An agent controls a device or application.",
"$ref": "schema:ControlAction"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AddAction",
"title": "AddAction",
"description": "The act of editing by adding an object to a collection.",
"type": "object",
"allOf": [
{
"description": "The act of managing by changing/editing the state of the object.",
"$ref": "schema:UpdateAction"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AdministrativeArea",
"title": "AdministrativeArea",
"description": "A geographical region, typically under the jurisdiction of a particular government.",
"type": "object",
"allOf": [
{
"description": "Entities that have a somewhat fixed, physical extension.",
"$ref": "schema:Place"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AdultEntertainment",
"title": "AdultEntertainment",
"description": "An adult entertainment establishment.",
"type": "object",
"allOf": [
{
"description": "A business providing entertainment.",
"$ref": "schema:EntertainmentBusiness"
}
]
}

View File

@@ -0,0 +1,49 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AdultOrientedEnumeration",
"title": "AdultOrientedEnumeration",
"description": "Enumeration of considerations that make a product relevant or potentially restricted for adults only.",
"type": "string",
"oneOf": [
{
"description": "Item contains alcohol or promotes alcohol consumption.",
"const": "AlcoholConsideration"
},
{
"description": "The item is dangerous and requires careful handling and/or special training of the user. See also the [UN Model Classification](https://unece.org/DAM/trans/danger/publi/unrec/rev17/English/02EREv17_Part2.pdf) defining the 9 classes of dangerous goods such as explosives, gases, flammables, and more.",
"const": "DangerousGoodConsideration"
},
{
"description": "Item is a pharmaceutical (e.g., a prescription or OTC drug) or a restricted medical device.",
"const": "HealthcareConsideration"
},
{
"description": "Item is a narcotic as defined by the [1961 UN convention](https://www.incb.org/incb/en/narcotic-drugs/Yellowlist/yellow-list.html), for example marijuana or heroin.",
"const": "NarcoticConsideration"
},
{
"description": "A general code for cases where relevance to children is reduced, e.g. adult education, mortgages, retirement-related products, etc.",
"const": "ReducedRelevanceForChildrenConsideration"
},
{
"description": "The item contains sexually oriented content such as nudity, suggestive or explicit material, or related online services, or is intended to enhance sexual activity. Examples: Erotic videos or magazine, sexual enhancement devices, sex toys.",
"const": "SexualContentConsideration"
},
{
"description": "Item contains tobacco and/or nicotine, for example cigars, cigarettes, chewing tobacco, e-cigarettes, or hookahs.",
"const": "TobaccoNicotineConsideration"
},
{
"description": "The item is suitable only for adults, without indicating why. Due to widespread use of \"adult\" as a euphemism for \"sexual\", many such items are likely suited also for the SexualContentConsideration code.",
"const": "UnclassifiedAdultConsideration"
},
{
"description": "Item shows or promotes violence.",
"const": "ViolenceConsideration"
},
{
"description": "The item is intended to induce bodily harm, for example guns, mace, combat knives, brass knuckles, nail or other bombs, and spears.",
"const": "WeaponConsideration"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AdvertiserContentArticle",
"title": "AdvertiserContentArticle",
"description": "An [[Article]] that an external entity has paid to place or to produce to its specifications. Includes [advertorials](https://en.wikipedia.org/wiki/Advertorial), sponsored content, native advertising and other paid content.",
"type": "object",
"allOf": [
{
"description": "An article, such as a news article or piece of investigative report. Newspapers and magazines have articles of many different types and this is intended to cover them all.\\n\\nSee also [blog post](http://blog.schema.org/2014/09/schemaorg-support-for-bibliographic_2.html).",
"$ref": "schema:Article"
}
]
}

View File

@@ -0,0 +1,39 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AggregateOffer",
"title": "AggregateOffer",
"description": "When a single product is associated with multiple offers (for example, the same pair of shoes is offered by different merchants), then AggregateOffer can be used.\\n\\nNote: AggregateOffers are normally expected to associate multiple offers that all share the same defined [[businessFunction]] value, or default to http://purl.org/goodrelations/v1#Sell if businessFunction is not explicitly defined.",
"type": "object",
"allOf": [
{
"description": "An offer to transfer some rights to an item or to provide a service — for example, an offer to sell tickets to an event, to rent the DVD of a movie, to stream a TV show over the internet, to repair a motorcycle, or to loan a book.\\n\\nNote: As the [[businessFunction]] property, which identifies the form of offer (e.g. sell, lease, repair, dispose), defaults to http://purl.org/goodrelations/v1#Sell; an Offer without a defined businessFunction value can be assumed to be an offer to sell.\\n\\nFor [GTIN](http://www.gs1.org/barcodes/technical/idkeys/gtin)-related fields, see [Check Digit calculator](http://www.gs1.org/barcodes/support/check_digit_calculator) and [validation guide](http://www.gs1us.org/resources/standards/gtin-validation-guide) from [GS1](http://www.gs1.org/).",
"$ref": "schema:Offer"
}
],
"properties": {
"highPrice": {
"description": "The highest price of all offers available.\\n\\nUsage guidelines:\\n\\n* Use values from 0123456789 (Unicode 'DIGIT ZERO' (U+0030) to 'DIGIT NINE' (U+0039)) rather than superficially similar Unicode symbols.\\n* Use '.' (Unicode 'FULL STOP' (U+002E)) rather than ',' to indicate a decimal point. Avoid using these symbols as a readability separator.",
"anyOf": [{ "type": "number" }, { "type": "string" }]
},
"lowPrice": {
"description": "The lowest price of all offers available.\\n\\nUsage guidelines:\\n\\n* Use values from 0123456789 (Unicode 'DIGIT ZERO' (U+0030) to 'DIGIT NINE' (U+0039)) rather than superficially similar Unicode symbols.\\n* Use '.' (Unicode 'FULL STOP' (U+002E)) rather than ',' to indicate a decimal point. Avoid using these symbols as a readability separator.",
"anyOf": [{ "type": "number" }, { "type": "string" }]
},
"offerCount": {
"description": "The number of offers for the product.",
"type": "integer"
},
"offers": {
"description": "An offer to provide this item—for example, an offer to sell a product, rent the DVD of a movie, perform a service, or give away tickets to an event. Use [[businessFunction]] to indicate the kind of transaction offered, i.e. sell, lease, etc. This property can also be used to describe a [[Demand]]. While this property is listed as expected on a number of common types, it can be used in others. In that case, using a second type, such as Product or a subtype of Product, can clarify the nature of the offer.\n ",
"oneOf": [
{ "anyOf": [{ "$ref": "schema:Demand" }, { "$ref": "schema:Offer" }] },
{
"type": "array",
"items": {
"anyOf": [{ "$ref": "schema:Demand" }, { "$ref": "schema:Offer" }]
}
}
]
}
}
}

View File

@@ -0,0 +1,27 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AggregateRating",
"title": "AggregateRating",
"description": "The average rating based on multiple ratings or reviews.",
"type": "object",
"allOf": [
{
"description": "A rating is an evaluation on a numeric scale, such as 1 to 5 stars.",
"$ref": "schema:Rating"
}
],
"properties": {
"itemReviewed": {
"description": "The item that is being reviewed/rated.",
"$ref": "schema:Thing"
},
"ratingCount": {
"description": "The count of total number of ratings.",
"type": "integer"
},
"reviewCount": {
"description": "The count of total number of reviews.",
"type": "integer"
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AgreeAction",
"title": "AgreeAction",
"description": "The act of expressing a consistency of opinion with the object. An agent agrees to/about an object (a proposition, topic or theme) with participants.",
"type": "object",
"allOf": [
{
"description": "The act of responding instinctively and emotionally to an object, expressing a sentiment.",
"$ref": "schema:ReactAction"
}
]
}

View File

@@ -0,0 +1,26 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Airline",
"title": "Airline",
"description": "An organization that provides flights for passengers.",
"type": "object",
"allOf": [
{
"description": "An organization such as a school, NGO, corporation, club, etc.",
"$ref": "schema:Organization"
}
],
"properties": {
"boardingPolicy": {
"description": "The type of boarding policy used by the airline (e.g. zone-based or group-based).",
"$ref": "schema:BoardingPolicyType"
},
"iataCode": {
"description": "IATA identifier for an airline or airport.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
}
}
}

View File

@@ -0,0 +1,29 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Airport",
"title": "Airport",
"description": "An airport.",
"type": "object",
"allOf": [
{
"description": "A public structure, such as a town hall or concert hall.",
"$ref": "schema:CivicStructure"
}
],
"properties": {
"iataCode": {
"description": "IATA identifier for an airline or airport.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
},
"icaoCode": {
"description": "ICAO identifier for an airport.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
}
}
}

View File

@@ -0,0 +1,39 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AlignmentObject",
"title": "AlignmentObject",
"description": "An intangible item that describes an alignment between a learning resource and a node in an educational framework.\n\nShould not be used where the nature of the alignment can be described using a simple property, for example to express that a resource [[teaches]] or [[assesses]] a competency.",
"type": "object",
"allOf": [
{
"description": "A utility class that serves as the umbrella for a number of 'intangible' things such as quantities, structured values, etc.",
"$ref": "schema:Intangible"
}
],
"properties": {
"alignmentType": {
"description": "A category of alignment between the learning resource and the framework node. Recommended values include: 'requires', 'textComplexity', 'readingLevel', and 'educationalSubject'.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
},
"educationalFramework": {
"description": "The framework to which the resource being described is aligned.",
"type": "string"
},
"targetDescription": {
"description": "The description of a node in an established educational framework.",
"type": "string"
},
"targetName": {
"description": "The name of a node in an established educational framework.",
"type": "string"
},
"targetUrl": {
"description": "The URL of a node in an established educational framework.",
"type": "string",
"format": "uri"
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AllocateAction",
"title": "AllocateAction",
"description": "The act of organizing tasks/objects/events by associating resources to it.",
"type": "object",
"allOf": [
{
"description": "The act of manipulating/administering/supervising/controlling one or more objects.",
"$ref": "schema:OrganizeAction"
}
]
}

View File

@@ -0,0 +1,17 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AmpStory",
"title": "AmpStory",
"description": "A creative work with a visual storytelling format intended to be viewed online, particularly on mobile devices.",
"type": "object",
"allOf": [
{
"description": "The most generic kind of creative work, including books, movies, photographs, software programs, etc.",
"$ref": "schema:CreativeWork"
},
{
"description": "A media object, such as an image, video, audio, or text object embedded in a web page or a downloadable dataset i.e. DataDownload. Note that a creative work may have many media objects associated with it on the same web page. For example, a page about a single song (MusicRecording) may have a music video (VideoObject), and a high and low bandwidth audio stream (2 AudioObject's).",
"$ref": "schema:MediaObject"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AmusementPark",
"title": "AmusementPark",
"description": "An amusement park.",
"type": "object",
"allOf": [
{
"description": "A business providing entertainment.",
"$ref": "schema:EntertainmentBusiness"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AnalysisNewsArticle",
"title": "AnalysisNewsArticle",
"description": "An AnalysisNewsArticle is a [[NewsArticle]] that, while based on factual reporting, incorporates the expertise of the author/producer, offering interpretations and conclusions.",
"type": "object",
"allOf": [
{
"description": "A NewsArticle is an article whose content reports news, or provides background context and supporting materials for understanding the news.\n\nA more detailed overview of [schema.org News markup](/docs/news.html) is also available.\n",
"$ref": "schema:NewsArticle"
}
]
}

View File

@@ -0,0 +1,62 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AnatomicalStructure",
"title": "AnatomicalStructure",
"description": "Any part of the human body, typically a component of an anatomical system. Organs, tissues, and cells are all anatomical structures.",
"type": "object",
"allOf": [
{
"description": "The most generic type of entity related to health and the practice of medicine.",
"$ref": "schema:MedicalEntity"
}
],
"properties": {
"associatedPathophysiology": {
"description": "If applicable, a description of the pathophysiology associated with the anatomical system, including potential abnormal changes in the mechanical, physical, and biochemical functions of the system.",
"type": "string"
},
"bodyLocation": {
"description": "Location in the body of the anatomical structure.",
"type": "string"
},
"connectedTo": {
"description": "Other anatomical structures to which this structure is connected.",
"oneOf": [
{ "$ref": "schema:AnatomicalStructure" },
{ "type": "array", "items": { "$ref": "schema:AnatomicalStructure" } }
]
},
"diagram": {
"description": "An image containing a diagram that illustrates the structure and/or its component substructures and/or connections with other structures.",
"oneOf": [
{ "$ref": "schema:ImageObject" },
{ "type": "array", "items": { "$ref": "schema:ImageObject" } }
]
},
"partOfSystem": {
"description": "The anatomical or organ system that this structure is part of.",
"$ref": "schema:AnatomicalSystem"
},
"relatedCondition": {
"description": "A medical condition associated with this anatomy.",
"oneOf": [
{ "$ref": "schema:MedicalCondition" },
{ "type": "array", "items": { "$ref": "schema:MedicalCondition" } }
]
},
"relatedTherapy": {
"description": "A medical therapy related to this anatomy.",
"oneOf": [
{ "$ref": "schema:MedicalTherapy" },
{ "type": "array", "items": { "$ref": "schema:MedicalTherapy" } }
]
},
"subStructure": {
"description": "Component (sub-)structure(s) that comprise this anatomical structure.",
"oneOf": [
{ "$ref": "schema:AnatomicalStructure" },
{ "type": "array", "items": { "$ref": "schema:AnatomicalStructure" } }
]
}
}
}

View File

@@ -0,0 +1,47 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AnatomicalSystem",
"title": "AnatomicalSystem",
"description": "An anatomical system is a group of anatomical structures that work together to perform a certain task. Anatomical systems, such as organ systems, are one organizing principle of anatomy, and can include circulatory, digestive, endocrine, integumentary, immune, lymphatic, muscular, nervous, reproductive, respiratory, skeletal, urinary, vestibular, and other systems.",
"type": "object",
"allOf": [
{
"description": "The most generic type of entity related to health and the practice of medicine.",
"$ref": "schema:MedicalEntity"
}
],
"properties": {
"associatedPathophysiology": {
"description": "If applicable, a description of the pathophysiology associated with the anatomical system, including potential abnormal changes in the mechanical, physical, and biochemical functions of the system.",
"type": "string"
},
"comprisedOf": {
"description": "Specifying something physically contained by something else. Typically used here for the underlying anatomical structures, such as organs, that comprise the anatomical system.",
"anyOf": [
{ "$ref": "schema:AnatomicalStructure" },
{ "$ref": "schema:AnatomicalSystem" }
]
},
"relatedCondition": {
"description": "A medical condition associated with this anatomy.",
"oneOf": [
{ "$ref": "schema:MedicalCondition" },
{ "type": "array", "items": { "$ref": "schema:MedicalCondition" } }
]
},
"relatedStructure": {
"description": "Related anatomical structure(s) that are not part of the system but relate or connect to it, such as vascular bundles associated with an organ system.",
"oneOf": [
{ "$ref": "schema:AnatomicalStructure" },
{ "type": "array", "items": { "$ref": "schema:AnatomicalStructure" } }
]
},
"relatedTherapy": {
"description": "A medical therapy related to this anatomy.",
"oneOf": [
{ "$ref": "schema:MedicalTherapy" },
{ "type": "array", "items": { "$ref": "schema:MedicalTherapy" } }
]
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AnimalShelter",
"title": "AnimalShelter",
"description": "Animal shelter.",
"type": "object",
"allOf": [
{
"description": "A particular physical business or branch of an organization. Examples of LocalBusiness include a restaurant, a particular branch of a restaurant chain, a branch of a bank, a medical practice, a club, a bowling alley, etc.",
"$ref": "schema:LocalBusiness"
}
]
}

View File

@@ -0,0 +1,39 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Answer",
"title": "Answer",
"description": "An answer offered to a question; perhaps correct, perhaps opinionated or wrong.",
"type": "object",
"allOf": [
{
"description": "A comment on an item - for example, a comment on a blog post. The comment's content is expressed via the [[text]] property, and its topic via [[about]], properties shared with all CreativeWorks.",
"$ref": "schema:Comment"
}
],
"properties": {
"answerExplanation": {
"description": "A step-by-step or full explanation about Answer. Can outline how this Answer was achieved or contain more broad clarification or statement about it. ",
"oneOf": [
{
"anyOf": [
{ "$ref": "schema:Comment" },
{ "$ref": "schema:WebContent" }
]
},
{
"type": "array",
"items": {
"anyOf": [
{ "$ref": "schema:Comment" },
{ "$ref": "schema:WebContent" }
]
}
}
]
},
"parentItem": {
"description": "The parent of a question, answer or item in general. Typically used for Q/A discussion threads e.g. a chain of comments with the first comment being an [[Article]] or other [[CreativeWork]]. See also [[comment]] which points from something to a comment about it.",
"anyOf": [{ "$ref": "schema:Comment" }, { "$ref": "schema:CreativeWork" }]
}
}
}

View File

@@ -0,0 +1,23 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Apartment",
"title": "Apartment",
"description": "An apartment (in American English) or flat (in British English) is a self-contained housing unit (a type of residential real estate) that occupies only part of a building (source: Wikipedia, the free encyclopedia, see http://en.wikipedia.org/wiki/Apartment).",
"type": "object",
"allOf": [
{
"description": "An accommodation is a place that can accommodate human beings, e.g. a hotel room, a camping pitch, or a meeting room. Many accommodations are for overnight stays, but this is not a mandatory requirement.\nFor more specific types of accommodations not defined in schema.org, one can use [[additionalType]] with external vocabularies.\n\nSee also the dedicated document on the use of schema.org for marking up hotels and other forms of accommodations.\n",
"$ref": "schema:Accommodation"
}
],
"properties": {
"numberOfRooms": {
"description": "The number of rooms (excluding bathrooms and closets) of the accommodation or lodging business.\nTypical unit code(s): ROM for room or C62 for no unit. The type of room can be put in the unitText property of the QuantitativeValue.",
"anyOf": [{ "type": "number" }, { "$ref": "schema:QuantitativeValue" }]
},
"occupancy": {
"description": "The allowed total occupancy for the accommodation in persons (including infants etc). For individual accommodations, this is not necessarily the legal maximum but defines the permitted usage as per the contractual agreement (e.g. a double room used by a single person).\nTypical unit code(s): C62 for person.",
"$ref": "schema:QuantitativeValue"
}
}
}

View File

@@ -0,0 +1,44 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ApartmentComplex",
"title": "ApartmentComplex",
"description": "Residence type: Apartment complex.",
"type": "object",
"allOf": [
{
"description": "The place where a person lives.",
"$ref": "schema:Residence"
}
],
"properties": {
"numberOfAccommodationUnits": {
"description": "Indicates the total (available plus unavailable) number of accommodation units in an [[ApartmentComplex]], or the number of accommodation units for a specific [[FloorPlan]] (within its specific [[ApartmentComplex]]). See also [[numberOfAvailableAccommodationUnits]].",
"oneOf": [
{ "$ref": "schema:QuantitativeValue" },
{ "type": "array", "items": { "$ref": "schema:QuantitativeValue" } }
]
},
"numberOfAvailableAccommodationUnits": {
"description": "Indicates the number of available accommodation units in an [[ApartmentComplex]], or the number of accommodation units for a specific [[FloorPlan]] (within its specific [[ApartmentComplex]]). See also [[numberOfAccommodationUnits]].",
"oneOf": [
{ "$ref": "schema:QuantitativeValue" },
{ "type": "array", "items": { "$ref": "schema:QuantitativeValue" } }
]
},
"numberOfBedrooms": {
"description": "The total integer number of bedrooms in a some [[Accommodation]], [[ApartmentComplex]] or [[FloorPlan]].",
"anyOf": [{ "type": "number" }, { "$ref": "schema:QuantitativeValue" }]
},
"petsAllowed": {
"description": "Indicates whether pets are allowed to enter the accommodation or lodging business. More detailed information can be put in a text value.",
"anyOf": [{ "type": "boolean" }, { "type": "string" }]
},
"tourBookingPage": {
"description": "A page providing information on how to book a tour of some [[Place]], such as an [[Accommodation]] or [[ApartmentComplex]] in a real estate setting, as well as other kinds of tours as appropriate.",
"oneOf": [
{ "type": "string", "format": "uri" },
{ "type": "array", "items": { "type": "string", "format": "uri" } }
]
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AppendAction",
"title": "AppendAction",
"description": "The act of inserting at the end if an ordered collection.",
"type": "object",
"allOf": [
{
"description": "The act of adding at a specific location in an ordered collection.",
"$ref": "schema:InsertAction"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ApplyAction",
"title": "ApplyAction",
"description": "The act of registering to an organization/service without the guarantee to receive it.\\n\\nRelated actions:\\n\\n* [[RegisterAction]]: Unlike RegisterAction, ApplyAction has no guarantees that the application will be accepted.",
"type": "object",
"allOf": [
{
"description": "The act of manipulating/administering/supervising/controlling one or more objects.",
"$ref": "schema:OrganizeAction"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ApprovedIndication",
"title": "ApprovedIndication",
"description": "An indication for a medical therapy that has been formally specified or approved by a regulatory body that regulates use of the therapy; for example, the US FDA approves indications for most drugs in the US.",
"type": "object",
"allOf": [
{
"description": "A condition or factor that indicates use of a medical therapy, including signs, symptoms, risk factors, anatomical states, etc.",
"$ref": "schema:MedicalIndication"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Aquarium",
"title": "Aquarium",
"description": "Aquarium.",
"type": "object",
"allOf": [
{
"description": "A public structure, such as a town hall or concert hall.",
"$ref": "schema:CivicStructure"
}
]
}

View File

@@ -0,0 +1,22 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ArchiveComponent",
"title": "ArchiveComponent",
"description": "",
"type": "object",
"allOf": [
{
"description": "The most generic kind of creative work, including books, movies, photographs, software programs, etc.",
"$ref": "schema:CreativeWork"
}
],
"properties": {
"[object Object]": {
"description": "",
"oneOf": [
{ "$ref": "schema:ArchiveOrganization" },
{ "type": "array", "items": { "$ref": "schema:ArchiveOrganization" } }
]
}
}
}

View File

@@ -0,0 +1,22 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ArchiveOrganization",
"title": "ArchiveOrganization",
"description": "",
"type": "object",
"allOf": [
{
"description": "A particular physical business or branch of an organization. Examples of LocalBusiness include a restaurant, a particular branch of a restaurant chain, a branch of a bank, a medical practice, a club, a bowling alley, etc.",
"$ref": "schema:LocalBusiness"
}
],
"properties": {
"[object Object]": {
"description": "",
"oneOf": [
{ "$ref": "schema:ArchiveComponent" },
{ "type": "array", "items": { "$ref": "schema:ArchiveComponent" } }
]
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ArriveAction",
"title": "ArriveAction",
"description": "The act of arriving at a place. An agent arrives at a destination from a fromLocation, optionally with participants.",
"type": "object",
"allOf": [
{
"description": "The act of an agent relocating to a place.\\n\\nRelated actions:\\n\\n* [[TransferAction]]: Unlike TransferAction, the subject of the move is a living Person or Organization rather than an inanimate object.",
"$ref": "schema:MoveAction"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ArtGallery",
"title": "ArtGallery",
"description": "An art gallery.",
"type": "object",
"allOf": [
{
"description": "A business providing entertainment.",
"$ref": "schema:EntertainmentBusiness"
}
]
}

View File

@@ -0,0 +1,23 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Artery",
"title": "Artery",
"description": "A type of blood vessel that specifically carries blood away from the heart.",
"type": "object",
"allOf": [
{
"description": "A component of the human body circulatory system comprised of an intricate network of hollow tubes that transport blood throughout the entire body.",
"$ref": "schema:Vessel"
}
],
"properties": {
"arterialBranch": {
"description": "The branches that comprise the arterial structure.",
"$ref": "schema:AnatomicalStructure"
},
"supplyTo": {
"description": "The area to which the artery supplies blood.",
"$ref": "schema:AnatomicalStructure"
}
}
}

View File

@@ -0,0 +1,77 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Article",
"title": "Article",
"description": "An article, such as a news article or piece of investigative report. Newspapers and magazines have articles of many different types and this is intended to cover them all.\\n\\nSee also [blog post](http://blog.schema.org/2014/09/schemaorg-support-for-bibliographic_2.html).",
"type": "object",
"allOf": [
{
"description": "The most generic kind of creative work, including books, movies, photographs, software programs, etc.",
"$ref": "schema:CreativeWork"
}
],
"properties": {
"articleBody": {
"description": "The actual body of the article.",
"type": "string"
},
"articleSection": {
"description": "Articles may belong to one or more 'sections' in a magazine or newspaper, such as Sports, Lifestyle, etc.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
},
"backstory": {
"description": "For an [[Article]], typically a [[NewsArticle]], the backstory property provides a textual summary giving a brief explanation of why and how an article was created. In a journalistic setting this could include information about reporting process, methods, interviews, data sources, etc.",
"oneOf": [
{ "anyOf": [{ "type": "string" }, { "$ref": "schema:CreativeWork" }] },
{
"type": "array",
"items": {
"anyOf": [{ "type": "string" }, { "$ref": "schema:CreativeWork" }]
}
}
]
},
"pageEnd": {
"description": "The page on which the work ends; for example \"138\" or \"xvi\".",
"anyOf": [{ "type": "integer" }, { "type": "string" }]
},
"pageStart": {
"description": "The page on which the work starts; for example \"135\" or \"xiii\".",
"anyOf": [{ "type": "integer" }, { "type": "string" }]
},
"pagination": {
"description": "Any description of pages that is not separated into pageStart and pageEnd; for example, \"1-6, 9, 55\" or \"10-12, 46-49\".",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
},
"speakable": {
"description": "Indicates sections of a Web page that are particularly 'speakable' in the sense of being highlighted as being especially appropriate for text-to-speech conversion. Other sections of a page may also be usefully spoken in particular circumstances; the 'speakable' property serves to indicate the parts most likely to be generally useful for speech.\n\nThe *speakable* property can be repeated an arbitrary number of times, with three kinds of possible 'content-locator' values:\n\n1.) *id-value* URL references - uses *id-value* of an element in the page being annotated. The simplest use of *speakable* has (potentially relative) URL values, referencing identified sections of the document concerned.\n\n2.) CSS Selectors - addresses content in the annotated page, e.g. via class attribute. Use the [[cssSelector]] property.\n\n3.) XPaths - addresses content via XPaths (assuming an XML view of the content). Use the [[xpath]] property.\n\n\nFor more sophisticated markup of speakable sections beyond simple ID references, either CSS selectors or XPath expressions to pick out document section(s) as speakable. For this\nwe define a supporting type, [[SpeakableSpecification]] which is defined to be a possible value of the *speakable* property.\n ",
"oneOf": [
{
"anyOf": [
{ "type": "string", "format": "uri" },
{ "$ref": "schema:SpeakableSpecification" }
]
},
{
"type": "array",
"items": {
"anyOf": [
{ "type": "string", "format": "uri" },
{ "$ref": "schema:SpeakableSpecification" }
]
}
}
]
},
"wordCount": {
"description": "The number of words in the text of the CreativeWork such as an Article, Book, etc.",
"type": "integer"
}
}
}

View File

@@ -0,0 +1,22 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AskAction",
"title": "AskAction",
"description": "The act of posing a question / favor to someone.\\n\\nRelated actions:\\n\\n* [[ReplyAction]]: Appears generally as a response to AskAction.",
"type": "object",
"allOf": [
{
"description": "The act of conveying information to another person via a communication medium (instrument) such as speech, email, or telephone conversation.",
"$ref": "schema:CommunicateAction"
}
],
"properties": {
"question": {
"description": "A sub property of object. A question.",
"oneOf": [
{ "$ref": "schema:Question" },
{ "type": "array", "items": { "$ref": "schema:Question" } }
]
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AskPublicNewsArticle",
"title": "AskPublicNewsArticle",
"description": "A [[NewsArticle]] expressing an open call by a [[NewsMediaOrganization]] asking the public for input, insights, clarifications, anecdotes, documentation, etc., on an issue, for reporting purposes.",
"type": "object",
"allOf": [
{
"description": "A NewsArticle is an article whose content reports news, or provides background context and supporting materials for understanding the news.\n\nA more detailed overview of [schema.org News markup](/docs/news.html) is also available.\n",
"$ref": "schema:NewsArticle"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AssessAction",
"title": "AssessAction",
"description": "The act of forming one's opinion, reaction or sentiment.",
"type": "object",
"allOf": [
{
"description": "An action performed by a direct agent and indirect participants upon a direct object. Optionally happens at a location with the help of an inanimate instrument. The execution of the action may produce a result. Specific action sub-type documentation specifies the exact expectation of each argument/role.\\n\\nSee also [blog post](http://blog.schema.org/2014/04/announcing-schemaorg-actions.html) and [Actions overview document](https://schema.org/docs/actions.html).",
"$ref": "schema:Action"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AssignAction",
"title": "AssignAction",
"description": "The act of allocating an action/event/task to some destination (someone or something).",
"type": "object",
"allOf": [
{
"description": "The act of organizing tasks/objects/events by associating resources to it.",
"$ref": "schema:AllocateAction"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Atlas",
"title": "Atlas",
"description": "A collection or bound volume of maps, charts, plates or tables, physical or in media form illustrating any subject.",
"type": "object",
"allOf": [
{
"description": "The most generic kind of creative work, including books, movies, photographs, software programs, etc.",
"$ref": "schema:CreativeWork"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Attorney",
"title": "Attorney",
"description": "Professional service: Attorney. \\n\\nThis type is deprecated - [[LegalService]] is more inclusive and less ambiguous.",
"type": "object",
"allOf": [
{
"description": "A LegalService is a business that provides legally-oriented services, advice and representation, e.g. law firms.\\n\\nAs a [[LocalBusiness]] it can be described as a [[provider]] of one or more [[Service]]\\(s).",
"$ref": "schema:LegalService"
}
]
}

View File

@@ -0,0 +1,23 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Audience",
"title": "Audience",
"description": "Intended audience for an item, i.e. the group for whom the item was created.",
"type": "object",
"allOf": [
{
"description": "A utility class that serves as the umbrella for a number of 'intangible' things such as quantities, structured values, etc.",
"$ref": "schema:Intangible"
}
],
"properties": {
"audienceType": {
"description": "The target group associated with a given audience (e.g. veterans, car owners, musicians, etc.).",
"type": "string"
},
"geographicArea": {
"description": "The geographic area associated with the audience.",
"$ref": "schema:AdministrativeArea"
}
}
}

View File

@@ -0,0 +1,30 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AudioObject",
"title": "AudioObject",
"description": "An audio file.",
"type": "object",
"allOf": [
{
"description": "A media object, such as an image, video, audio, or text object embedded in a web page or a downloadable dataset i.e. DataDownload. Note that a creative work may have many media objects associated with it on the same web page. For example, a page about a single song (MusicRecording) may have a music video (VideoObject), and a high and low bandwidth audio stream (2 AudioObject's).",
"$ref": "schema:MediaObject"
}
],
"properties": {
"caption": {
"description": "The caption for this object. For downloadable machine formats (closed caption, subtitles etc.) use MediaObject and indicate the [[encodingFormat]].",
"anyOf": [{ "type": "string" }, { "$ref": "schema:MediaObject" }]
},
"embeddedTextCaption": {
"description": "Represents textual captioning from a [[MediaObject]], e.g. text of a 'meme'.",
"oneOf": [
{ "type": "string" },
{ "type": "array", "items": { "type": "string" } }
]
},
"transcript": {
"description": "If this MediaObject is an AudioObject or VideoObject, the transcript of that object.",
"type": "string"
}
}
}

View File

@@ -0,0 +1,8 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AudioObjectSnapshot",
"title": "AudioObjectSnapshot",
"description": "A specific and exact (byte-for-byte) version of an [[AudioObject]]. Two byte-for-byte identical files, for the purposes of this type, considered identical. If they have different embedded metadata the files will differ. Different external facts about the files, e.g. creator or dateCreated that aren't represented in their actual content, do not affect this notion of identity.",
"type": "object",
"allOf": [{ "description": "An audio file.", "$ref": "schema:AudioObject" }]
}

View File

@@ -0,0 +1,27 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Audiobook",
"title": "Audiobook",
"description": "An audiobook.",
"type": "object",
"allOf": [
{ "description": "An audio file.", "$ref": "schema:AudioObject" },
{ "description": "A book.", "$ref": "schema:Book" }
],
"properties": {
"duration": {
"description": "The duration of the item (movie, audio recording, event, etc.) in [ISO 8601 duration format](http://en.wikipedia.org/wiki/ISO_8601).",
"anyOf": [
{ "type": "string", "$comment": "https://schema.org/Duration" },
{ "$ref": "schema:QuantitativeValue" }
]
},
"readBy": {
"description": "A person who reads (performs) the audiobook.",
"oneOf": [
{ "$ref": "schema:Person" },
{ "type": "array", "items": { "$ref": "schema:Person" } }
]
}
}
}

View File

@@ -0,0 +1,39 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AuthorizeAction",
"title": "AuthorizeAction",
"description": "The act of granting permission to an object.",
"type": "object",
"allOf": [
{
"description": "The act of organizing tasks/objects/events by associating resources to it.",
"$ref": "schema:AllocateAction"
}
],
"properties": {
"recipient": {
"description": "A sub property of participant. The participant who is at the receiving end of the action.",
"oneOf": [
{
"anyOf": [
{ "$ref": "schema:Audience" },
{ "$ref": "schema:ContactPoint" },
{ "$ref": "schema:Organization" },
{ "$ref": "schema:Person" }
]
},
{
"type": "array",
"items": {
"anyOf": [
{ "$ref": "schema:Audience" },
{ "$ref": "schema:ContactPoint" },
{ "$ref": "schema:Organization" },
{ "$ref": "schema:Person" }
]
}
}
]
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AutoBodyShop",
"title": "AutoBodyShop",
"description": "Auto body shop.",
"type": "object",
"allOf": [
{
"description": "Car repair, sales, or parts.",
"$ref": "schema:AutomotiveBusiness"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AutoDealer",
"title": "AutoDealer",
"description": "An car dealership.",
"type": "object",
"allOf": [
{
"description": "Car repair, sales, or parts.",
"$ref": "schema:AutomotiveBusiness"
}
]
}

View File

@@ -0,0 +1,14 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AutoPartsStore",
"title": "AutoPartsStore",
"description": "An auto parts store.",
"type": "object",
"allOf": [
{
"description": "Car repair, sales, or parts.",
"$ref": "schema:AutomotiveBusiness"
},
{ "description": "A retail good store.", "$ref": "schema:Store" }
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AutoRental",
"title": "AutoRental",
"description": "A car rental business.",
"type": "object",
"allOf": [
{
"description": "Car repair, sales, or parts.",
"$ref": "schema:AutomotiveBusiness"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AutoRepair",
"title": "AutoRepair",
"description": "Car repair business.",
"type": "object",
"allOf": [
{
"description": "Car repair, sales, or parts.",
"$ref": "schema:AutomotiveBusiness"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AutoWash",
"title": "AutoWash",
"description": "A car wash business.",
"type": "object",
"allOf": [
{
"description": "Car repair, sales, or parts.",
"$ref": "schema:AutomotiveBusiness"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AutomatedTeller",
"title": "AutomatedTeller",
"description": "ATM/cash machine.",
"type": "object",
"allOf": [
{
"description": "Financial services business.",
"$ref": "schema:FinancialService"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:AutomotiveBusiness",
"title": "AutomotiveBusiness",
"description": "Car repair, sales, or parts.",
"type": "object",
"allOf": [
{
"description": "A particular physical business or branch of an organization. Examples of LocalBusiness include a restaurant, a particular branch of a restaurant chain, a branch of a bank, a medical practice, a club, a bowling alley, etc.",
"$ref": "schema:LocalBusiness"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:BackgroundNewsArticle",
"title": "BackgroundNewsArticle",
"description": "A [[NewsArticle]] providing historical context, definition and detail on a specific topic (aka \"explainer\" or \"backgrounder\"). For example, an in-depth article or frequently-asked-questions ([FAQ](https://en.wikipedia.org/wiki/FAQ)) document on topics such as Climate Change or the European Union. Other kinds of background material from a non-news setting are often described using [[Book]] or [[Article]], in particular [[ScholarlyArticle]]. See also [[NewsArticle]] for related vocabulary from a learning/education perspective.",
"type": "object",
"allOf": [
{
"description": "A NewsArticle is an article whose content reports news, or provides background context and supporting materials for understanding the news.\n\nA more detailed overview of [schema.org News markup](/docs/news.html) is also available.\n",
"$ref": "schema:NewsArticle"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Bakery",
"title": "Bakery",
"description": "A bakery.",
"type": "object",
"allOf": [
{
"description": "A food-related business.",
"$ref": "schema:FoodEstablishment"
}
]
}

View File

@@ -0,0 +1,33 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:BankAccount",
"title": "BankAccount",
"description": "A product or service offered by a bank whereby one may deposit, withdraw or transfer money and in some cases be paid interest.",
"type": "object",
"allOf": [
{
"description": "A product provided to consumers and businesses by financial institutions such as banks, insurance companies, brokerage firms, consumer finance companies, and investment companies which comprise the financial services industry.",
"$ref": "schema:FinancialProduct"
}
],
"properties": {
"accountMinimumInflow": {
"description": "A minimum amount that has to be paid in every month.",
"oneOf": [
{ "$ref": "schema:MonetaryAmount" },
{ "type": "array", "items": { "$ref": "schema:MonetaryAmount" } }
]
},
"accountOverdraftLimit": {
"description": "An overdraft is an extension of credit from a lending institution when an account reaches zero. An overdraft allows the individual to continue withdrawing money even if the account has no funds in it. Basically the bank allows people to borrow a set amount of money.",
"oneOf": [
{ "$ref": "schema:MonetaryAmount" },
{ "type": "array", "items": { "$ref": "schema:MonetaryAmount" } }
]
},
"bankAccountType": {
"description": "The type of a bank account.",
"anyOf": [{ "type": "string", "format": "uri" }, { "type": "string" }]
}
}
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:BankOrCreditUnion",
"title": "BankOrCreditUnion",
"description": "Bank or credit union.",
"type": "object",
"allOf": [
{
"description": "Financial services business.",
"$ref": "schema:FinancialService"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:BarOrPub",
"title": "BarOrPub",
"description": "A bar or pub.",
"type": "object",
"allOf": [
{
"description": "A food-related business.",
"$ref": "schema:FoodEstablishment"
}
]
}

View File

@@ -0,0 +1,8 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Barcode",
"title": "Barcode",
"description": "An image of a visual machine-readable code such as a barcode or QR code.",
"type": "object",
"allOf": [{ "description": "An image file.", "$ref": "schema:ImageObject" }]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:Beach",
"title": "Beach",
"description": "Beach.",
"type": "object",
"allOf": [
{
"description": "A public structure, such as a town hall or concert hall.",
"$ref": "schema:CivicStructure"
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:BeautySalon",
"title": "BeautySalon",
"description": "Beauty salon.",
"type": "object",
"allOf": [
{
"description": "Health and beauty.",
"$ref": "schema:HealthAndBeautyBusiness"
}
]
}

Some files were not shown because too many files have changed in this diff Show More