@prefix : <https://relay.inferal.com/ontology/typespec/versioning/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

:VersionShape
    a sh:NodeShape ;
    rdfs:label "version shape" ;
    rdfs:comment "Validates TypeSpec version chain links and rejects cycles through previousVersion." ;
    sh:targetClass :Version ;
    sh:property [
        sh:path :previousVersion ;
        sh:class :Version ;
        sh:maxCount 1 ;
        sh:name "previous version" ;
        sh:description "The immediately previous version in the TypeSpec version chain." ;
    ] ;
    sh:sparql [
        sh:message "TypeSpec version chains must not contain cycles through tspv:previousVersion." ;
        sh:select """
            PREFIX tspv: <https://relay.inferal.com/ontology/typespec/versioning/>
            SELECT $this WHERE {
                $this tspv:previousVersion+ $this .
            }
        """ ;
    ] .

:VersionedResourceShape
    a sh:NodeShape ;
    rdfs:label "versioned resource shape" ;
    rdfs:comment "Targets resources annotated with TypeSpec version coverage or change metadata." ;
    sh:targetClass :VersionedResource .

:MergedOntologyShape
    a sh:NodeShape ;
    rdfs:label "merged ontology shape" ;
    rdfs:comment "Validates merged ontology resources that declare covered TypeSpec versions." ;
    sh:targetSubjectsOf :coversVersion ;
    sh:property [
        sh:path :coversVersion ;
        sh:class :Version ;
        sh:minCount 1 ;
        sh:name "covers version" ;
        sh:description "An API version covered by a merged ontology." ;
    ] .

:AddedResourceShape
    a sh:NodeShape ;
    rdfs:label "added resource shape" ;
    rdfs:comment "Validates added-in-version metadata and prevents later change markers from preceding the added version." ;
    sh:targetSubjectsOf :addedInVersion ;
    sh:property [
        sh:path :addedInVersion ;
        sh:class :Version ;
        sh:maxCount 1 ;
        sh:name "added in version" ;
        sh:description "Version when this type, property, operation, or resource was introduced." ;
    ] ;
    sh:sparql [
        sh:message "Version-scoped changes must not occur before tspv:addedInVersion in the tspv:previousVersion chain." ;
        sh:select """
            PREFIX tspv: <https://relay.inferal.com/ontology/typespec/versioning/>
            SELECT $this ?changeProperty ?changeVersion WHERE {
                $this tspv:addedInVersion ?addedVersion ;
                    ?changeProperty ?changeVersion .
                FILTER(?changeProperty IN (
                    tspv:removedInVersion,
                    tspv:renamedInVersion,
                    tspv:madeOptionalInVersion,
                    tspv:madeRequiredInVersion,
                    tspv:typeChangedInVersion,
                    tspv:returnTypeChangedInVersion
                ))
                ?addedVersion tspv:previousVersion+ ?changeVersion .
            }
        """ ;
    ] .

:RemovedResourceShape
    a sh:NodeShape ;
    rdfs:label "removed resource shape" ;
    rdfs:comment "Validates removed-in-version metadata for TypeSpec resources." ;
    sh:targetSubjectsOf :removedInVersion ;
    sh:property [
        sh:path :removedInVersion ;
        sh:class :Version ;
        sh:maxCount 1 ;
        sh:name "removed in version" ;
        sh:description "Version when this type, property, operation, or resource was removed." ;
    ] .

:RenamedResourceShape
    a sh:NodeShape ;
    rdfs:label "renamed resource shape" ;
    rdfs:comment "Validates previous name and version metadata for renamed TypeSpec resources." ;
    sh:targetSubjectsOf :renamedFrom ;
    sh:property [
        sh:path :renamedFrom ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:name "renamed from" ;
        sh:description "Previous name before renaming." ;
    ] ;
    sh:property [
        sh:path :renamedInVersion ;
        sh:class :Version ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:name "renamed in version" ;
        sh:description "Version when renaming occurred." ;
    ] .

:MadeOptionalResourceShape
    a sh:NodeShape ;
    rdfs:label "made optional resource shape" ;
    rdfs:comment "Validates version metadata for TypeSpec resources that became optional." ;
    sh:targetSubjectsOf :madeOptionalInVersion ;
    sh:property [
        sh:path :madeOptionalInVersion ;
        sh:class :Version ;
        sh:maxCount 1 ;
        sh:name "made optional in version" ;
    ] .

:MadeRequiredResourceShape
    a sh:NodeShape ;
    rdfs:label "made required resource shape" ;
    rdfs:comment "Validates version metadata for TypeSpec resources that became required." ;
    sh:targetSubjectsOf :madeRequiredInVersion ;
    sh:property [
        sh:path :madeRequiredInVersion ;
        sh:class :Version ;
        sh:maxCount 1 ;
        sh:name "made required in version" ;
    ] .

:TypeChangedResourceShape
    a sh:NodeShape ;
    rdfs:label "type changed resource shape" ;
    rdfs:comment "Validates previous type text and version metadata for TypeSpec resources whose type changed." ;
    sh:targetSubjectsOf :typeChangedFrom ;
    sh:property [
        sh:path :typeChangedFrom ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:name "type changed from" ;
    ] ;
    sh:property [
        sh:path :typeChangedInVersion ;
        sh:class :Version ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:name "type changed in version" ;
    ] .

:ReturnTypeChangedResourceShape
    a sh:NodeShape ;
    rdfs:label "return type changed resource shape" ;
    rdfs:comment "Validates previous return type text and version metadata for TypeSpec resources whose return type changed." ;
    sh:targetSubjectsOf :returnTypeChangedFrom ;
    sh:property [
        sh:path :returnTypeChangedFrom ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:name "return type changed from" ;
    ] ;
    sh:property [
        sh:path :returnTypeChangedInVersion ;
        sh:class :Version ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:name "return type changed in version" ;
    ] .
