$base: "https://w3id.org/cwl/salad#"

$namespaces:
  sld:  "https://w3id.org/cwl/salad#"
  dct:  "http://purl.org/dc/terms/"
  rdf:  "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  rdfs: "http://www.w3.org/2000/01/rdf-schema#"
  xsd:  "http://www.w3.org/2001/XMLSchema#"

$graph:

- name: "Semantic_Annotations_for_Linked_Avro_Data"
  type: documentation
  doc:
    - $include: salad.md
    - $import: field_name.yml
    - $import: ident_res.yml
    - $import: link_res.yml
    - $import: vocab_res.yml
    - $include: import_include.md
    - $import: map_res.yml
    - $import: typedsl_res.yml
    - $import: sfdsl_res.yml

- name: "Link_Validation"
  type: documentation
  doc: |
    # Link validation

    Once a document has been preprocessed, an implementation may validate
    links.  The link validation traversal may visit fields which the schema
    designates as link fields and check that each URI references an existing
    object in the current document, an imported document, file system, or
    network resource.  Failure to validate links may be a fatal error.  Link
    validation behavior for individual fields may be modified by `identity` and
    `noLinkCheck` in the `jsonldPredicate` section of the field schema.


- name: "Schema_Validation"
  type: documentation
  doc: |
    # Validating a document against a schema

    To validate a document against the schema, first [apply
    preprocessing](#Document_preprocessing), then, use the following
    algorithm.

    1. The document root must be an object or a list.  If the document root is an
       object containing the field `$graph` (which must be a list of
       objects), then validation applies to each object in the list.
    2. For each object, attempt to validate as one of the record types
       flagged with `documentRoot: true`.
    3. To validate a record, go through `fields` and recursively
       validate each field of the object.
    4. For fields with a list of types (type union), go through each
       type in the list and recursively validate the type.  For the
       field to be valid, at least one type in the union must be valid.
    5. Missing fields are considered `null`.  To validate, the allowed types
       for the field must include `null`
    6. Primitive types are null, boolean, int, long, float, double,
       string.  To validate, the value in the document must have one
       of these type.  For numerics, the value appearing in the
       document must fit into the specified type.
    7. To validate an array, the value in the document must be a list,
       and each item in the list must recursively validate as a type
       in `items`.
    8. To validate an enum, the value in the document be a string, and
       the value must be equal to the short name of one of the values
       listed in `symbols`.
    9. As a special case, a field with the `Expression` type validates string values
      which contain a CWL parameter reference or expression in the form
      `$(...)` or `${...}`

# - name: "JSON_LD_Context"
#   type: documentation
#   doc: |
#     # Generating JSON-LD Context

#     How to generate the json-ld context...


- $import: metaschema_base.yml

- name: JsonldPredicate
  type: record
  doc: |
    Attached to a record field to define how the parent record field is handled for
    URI resolution and JSON-LD context generation.
  fields:
    - name: _id
      type: string?
      jsonldPredicate:
        _id: sld:_id
        _type: "@id"
        identity: true
      doc: |
        The predicate URI that this field corresponds to.
        Corresponds to JSON-LD `@id` directive.
    - name: _type
      type: string?
      doc: |
        The context type hint, corresponds to JSON-LD `@type` directive.

        * If the value of this field is `@id` and `identity` is false or
        unspecified, the parent field must be resolved using the link
        resolution rules.  If `identity` is true, the parent field must be
        resolved using the identifier expansion rules.

        * If the value of this field is `@vocab`, the parent field must be
          resolved using the vocabulary resolution rules.

    - name: _container
      type: string?
      doc: |
        Structure hint, corresponds to JSON-LD `@container` directive.
    - name: identity
      type: boolean?
      doc: |
        If true and `_type` is `@id` this indicates that the parent field must
        be resolved according to identity resolution rules instead of link
        resolution rules.  In addition, the field value is considered an
        assertion that the linked value exists; absence of an object in the loaded document
        with the URI is not an error.
    - name: noLinkCheck
      type: boolean?
      doc: |
        If true, this indicates that link validation traversal must stop at
        this field.  This field (it is is a URI) or any fields under it (if it
        is an object or array) are not subject to link checking.
    - name: mapSubject
      type: string?
      doc: |
        If the value of the field is a JSON object, it must be transformed
        into an array of JSON objects, where each key-value pair from the
        source JSON object is a list item, the list items must be JSON objects,
        and the key is assigned to the field specified by `mapSubject`.
    - name: mapPredicate
      type: string?
      doc: |
        Only applies if `mapSubject` is also provided.  If the value of the
        field is a JSON object, it is transformed as described in `mapSubject`,
        with the addition that when the value of a map item is not an object,
        the item is transformed to a JSON object with the key assigned to the
        field specified by `mapSubject` and the value assigned to the field
        specified by `mapPredicate`.
    - name: refScope
      type: int?
      doc: |
        If the field contains a relative reference, it must be resolved by
        searching for valid document references in each successive parent scope
        in the document fragment.  For example, a reference of `foo` in the
        context `#foo/bar/baz` will first check for the existence of
        `#foo/bar/baz/foo`, followed by `#foo/bar/foo`, then `#foo/foo` and
        then finally `#foo`.  The first valid URI in the search order shall be
        used as the fully resolved value of the identifier.  The value of the
        refScope field is the specified number of levels from the containing
        identifer scope before starting the search, so if `refScope: 2` then
        "baz" and "bar" must be stripped to get the base `#foo` and search
        `#foo/foo` and the `#foo`.  The last scope searched must be the top
        level scope before determining if the identifier cannot be resolved.
    - name: typeDSL
      type: boolean?
      doc: |
        Field must be expanded based on the the Schema Salad type DSL.
    - name: secondaryFilesDSL
      type: boolean?
      doc: |
        Field must be expanded based on the the Schema Salad secondary file DSL.
    - name: subscope
      type: string?
      doc: |
        Append the subscope to the current scope when performing
        identifier resolution to objects under this field.

- name: SpecializeDef
  type: record
  fields:
    - name: specializeFrom
      type: string
      doc: "The data type to be replaced"
      jsonldPredicate:
        _id: "sld:specializeFrom"
        _type: "@id"
        refScope: 1

    - name: specializeTo
      type: string
      doc: "The new data type to replace with"
      jsonldPredicate:
        _id: "sld:specializeTo"
        _type: "@id"
        refScope: 1


- name: NamedType
  type: record
  abstract: true
  docParent: "#Schema"
  fields:
    - name: name
      type: string
      jsonldPredicate: "@id"
      doc: "The identifier for this type"
    - name: inVocab
      type: boolean?
      default: true
      doc: |
        If "true" (the default), include the short name of this type
        in the vocabulary.  The vocabulary are all the symbols (field
        names and other identifiers, such as classes and enum values)
        which can be used in the document without a namespace prefix.
        These are the keys of the JSON-LD context.  If false, do not
        include the short name in the vocabulary.

        This is useful for specifying schema extensions that will be
        included in validation without introducing ambiguity by
        introducing non-standard terms into the vocabulary.


- name: DocType
  type: record
  extends: Documented
  abstract: true
  docParent: "#Schema"
  fields:
    - name: docParent
      type: string?
      doc: |
        Hint to indicate that during documentation generation, documentation
        for this type should appear in a subsection under `docParent`.
      jsonldPredicate:
        _id: "sld:docParent"
        _type: "@id"

    - name: docChild
      type:
        - string?
        - string[]?
      doc: |
        Hint to indicate that during documentation generation, documentation
        for `docChild` should appear in a subsection under this type.
      jsonldPredicate:
        _id: "sld:docChild"
        _type: "@id"

    - name: docAfter
      type: string?
      doc: |
        Hint to indicate that during documentation generation, documentation
        for this type should appear after the `docAfter` section at the same
        level.
      jsonldPredicate:
        _id: "sld:docAfter"
        _type: "@id"


- name: SchemaDefinedType
  type: record
  extends: DocType
  doc: |
    Abstract base for schema-defined types.
  abstract: true
  fields:
    - name: jsonldPredicate
      type:
        - string?
        - JsonldPredicate?
      doc: |
        Annotate this type with linked data context.
      jsonldPredicate: sld:jsonldPredicate

    - name: documentRoot
      type: boolean?
      doc: |
        If true, indicates that the type is a valid at the document root.  At
        least one type in a schema must be tagged with `documentRoot: true`.


- name: SaladRecordField
  type: record
  extends: RecordField
  doc: "A field of a record."
  fields:
    - name: jsonldPredicate
      type:
        - string?
        - JsonldPredicate?
      doc: |
        Annotate this type with linked data context.
      jsonldPredicate: "sld:jsonldPredicate"
    - name: default
      type: Any?
      jsonldPredicate:
        _id: sld:default
        noLinkCheck: true
      doc: |
        The default value to use for this field if the field is missing or "null".


- name: SaladRecordSchema
  docParent: "#Schema"
  type: record
  extends: [NamedType, RecordSchema, SchemaDefinedType]
  documentRoot: true
  specialize:
    RecordField: SaladRecordField
  fields:
    - name: abstract
      type: boolean?
      doc: |
        If true, this record is abstract and may be used as a base for other
        records, but is not valid on its own.

    - name: extends
      type:
        - string?
        - string[]?
      jsonldPredicate:
        _id: "sld:extends"
        _type: "@id"
        refScope: 1
      doc: |
        Indicates that this record inherits fields from one or more base records.

    - name: specialize
      type:
        - SpecializeDef[]?
      doc: |
        Only applies if `extends` is declared.  Apply type specialization using the
        base record as a template.  For each field inherited from the base
        record, replace any instance of the type `specializeFrom` with
        `specializeTo`.
      jsonldPredicate:
        _id: "sld:specialize"
        mapSubject: specializeFrom
        mapPredicate: specializeTo

- name: SaladEnumSchema
  docParent: "#Schema"
  type: record
  extends: [NamedType, EnumSchema, SchemaDefinedType]
  documentRoot: true
  doc: |
    Define an enumerated type.
  fields:
    - name: extends
      type:
        - string?
        - string[]?
      jsonldPredicate:
        _id: "sld:extends"
        _type: "@id"
        refScope: 1
      doc: |
        Indicates that this enum inherits symbols from a base enum.


- name: Documentation
  type: record
  docParent: "#Schema"
  extends: [NamedType, DocType]
  documentRoot: true
  doc: |
    A documentation section.  This type exists to facilitate self-documenting
    schemas but has no role in formal validation.
  fields:
    - name: type
      doc: "Must be `documentation`"
      type:
        type: enum
        symbols:
          - "sld:documentation"
      jsonldPredicate:
        _id: "sld:type"
        _type: "@vocab"
        typeDSL: true
        refScope: 2
