@@ -1599,3 +1599,385 @@ test("Resource parameters can be retrieved", async () => {
15991599 } ,
16001600 ] ) ;
16011601} ) ;
1602+
1603+ test ( "parse a Hydra documentation with enum/read-only resources (rdfs:range direct @id)" , async ( ) => {
1604+ const enumEntrypoint = {
1605+ "@context" : {
1606+ "@vocab" : "http://localhost/docs.jsonld#" ,
1607+ hydra : "http://www.w3.org/ns/hydra/core#" ,
1608+ book : {
1609+ "@id" : "Entrypoint/book" ,
1610+ "@type" : "@id" ,
1611+ } ,
1612+ bookCondition : {
1613+ "@id" : "Entrypoint/bookCondition" ,
1614+ "@type" : "@id" ,
1615+ } ,
1616+ } ,
1617+ "@id" : "/" ,
1618+ "@type" : "Entrypoint" ,
1619+ book : "/books" ,
1620+ bookCondition : "/book_conditions" ,
1621+ } ;
1622+
1623+ const enumDocs = {
1624+ "@context" : {
1625+ "@vocab" : "http://localhost/docs.jsonld#" ,
1626+ hydra : "http://www.w3.org/ns/hydra/core#" ,
1627+ rdf : "http://www.w3.org/1999/02/22-rdf-syntax-ns#" ,
1628+ rdfs : "http://www.w3.org/2000/01/rdf-schema#" ,
1629+ xmls : "http://www.w3.org/2001/XMLSchema#" ,
1630+ owl : "http://www.w3.org/2002/07/owl#" ,
1631+ domain : {
1632+ "@id" : "rdfs:domain" ,
1633+ "@type" : "@id" ,
1634+ } ,
1635+ range : {
1636+ "@id" : "rdfs:range" ,
1637+ "@type" : "@id" ,
1638+ } ,
1639+ subClassOf : {
1640+ "@id" : "rdfs:subClassOf" ,
1641+ "@type" : "@id" ,
1642+ } ,
1643+ expects : {
1644+ "@id" : "hydra:expects" ,
1645+ "@type" : "@id" ,
1646+ } ,
1647+ returns : {
1648+ "@id" : "hydra:returns" ,
1649+ "@type" : "@id" ,
1650+ } ,
1651+ } ,
1652+ "@id" : "/docs.jsonld" ,
1653+ "hydra:title" : "API with enums" ,
1654+ "hydra:description" : "An API that exposes enum resources" ,
1655+ "hydra:entrypoint" : "/" ,
1656+ "hydra:supportedClass" : [
1657+ {
1658+ "@id" : "http://schema.org/Book" ,
1659+ "@type" : "hydra:Class" ,
1660+ "rdfs:label" : "Book" ,
1661+ "hydra:title" : "Book" ,
1662+ "hydra:supportedProperty" : [
1663+ {
1664+ "@type" : "hydra:SupportedProperty" ,
1665+ "hydra:property" : {
1666+ "@id" : "http://schema.org/name" ,
1667+ "@type" : "rdf:Property" ,
1668+ "rdfs:label" : "name" ,
1669+ domain : "http://schema.org/Book" ,
1670+ range : "xmls:string" ,
1671+ } ,
1672+ "hydra:title" : "name" ,
1673+ "hydra:required" : true ,
1674+ "hydra:readable" : true ,
1675+ "hydra:writeable" : true ,
1676+ } ,
1677+ ] ,
1678+ "hydra:supportedOperation" : [
1679+ {
1680+ "@type" : "hydra:Operation" ,
1681+ "hydra:method" : "GET" ,
1682+ "hydra:title" : "Retrieves Book resource." ,
1683+ "rdfs:label" : "Retrieves Book resource." ,
1684+ returns : "http://schema.org/Book" ,
1685+ } ,
1686+ ] ,
1687+ } ,
1688+ {
1689+ "@id" : "#BookCondition" ,
1690+ "@type" : "hydra:Class" ,
1691+ "rdfs:label" : "BookCondition" ,
1692+ "hydra:title" : "BookCondition" ,
1693+ "hydra:description" : "The condition of a book (new, used, damaged)." ,
1694+ "hydra:supportedProperty" : [
1695+ {
1696+ "@type" : "hydra:SupportedProperty" ,
1697+ "hydra:property" : {
1698+ "@id" : "#BookCondition/value" ,
1699+ "@type" : "rdf:Property" ,
1700+ "rdfs:label" : "value" ,
1701+ domain : "#BookCondition" ,
1702+ range : "xmls:string" ,
1703+ } ,
1704+ "hydra:title" : "value" ,
1705+ "hydra:required" : true ,
1706+ "hydra:readable" : true ,
1707+ "hydra:writeable" : false ,
1708+ } ,
1709+ ] ,
1710+ "hydra:supportedOperation" : [
1711+ {
1712+ "@type" : "hydra:Operation" ,
1713+ "hydra:method" : "GET" ,
1714+ "hydra:title" : "Retrieves BookCondition resource." ,
1715+ "rdfs:label" : "Retrieves BookCondition resource." ,
1716+ returns : "#BookCondition" ,
1717+ } ,
1718+ ] ,
1719+ } ,
1720+ {
1721+ "@id" : "#Entrypoint" ,
1722+ "@type" : "hydra:Class" ,
1723+ "hydra:title" : "The API entrypoint" ,
1724+ "hydra:supportedProperty" : [
1725+ {
1726+ "@type" : "hydra:SupportedProperty" ,
1727+ "hydra:property" : {
1728+ "@id" : "#Entrypoint/book" ,
1729+ "@type" : "hydra:Link" ,
1730+ domain : "#Entrypoint" ,
1731+ "rdfs:label" : "The collection of Book resources" ,
1732+ "rdfs:range" : [
1733+ { "@id" : "hydra:PagedCollection" } ,
1734+ {
1735+ "owl:equivalentClass" : {
1736+ "owl:onProperty" : { "@id" : "hydra:member" } ,
1737+ "owl:allValuesFrom" : {
1738+ "@id" : "http://schema.org/Book" ,
1739+ } ,
1740+ } ,
1741+ } ,
1742+ ] ,
1743+ } ,
1744+ "hydra:title" : "The collection of Book resources" ,
1745+ "hydra:readable" : true ,
1746+ "hydra:writeable" : false ,
1747+ } ,
1748+ {
1749+ "@type" : "hydra:SupportedProperty" ,
1750+ "hydra:property" : {
1751+ "@id" : "#Entrypoint/bookCondition" ,
1752+ "@type" : "hydra:Link" ,
1753+ domain : "#Entrypoint" ,
1754+ "rdfs:label" : "The collection of BookCondition resources" ,
1755+ "rdfs:range" : [ { "@id" : "#BookCondition" } ] ,
1756+ } ,
1757+ "hydra:title" : "The collection of BookCondition resources" ,
1758+ "hydra:readable" : true ,
1759+ "hydra:writeable" : false ,
1760+ } ,
1761+ ] ,
1762+ "hydra:supportedOperation" : {
1763+ "@type" : "hydra:Operation" ,
1764+ "hydra:method" : "GET" ,
1765+ "rdfs:label" : "The API entrypoint." ,
1766+ returns : "#EntryPoint" ,
1767+ } ,
1768+ } ,
1769+ {
1770+ "@id" : "#ConstraintViolation" ,
1771+ "@type" : "hydra:Class" ,
1772+ "hydra:title" : "A constraint violation" ,
1773+ "hydra:supportedProperty" : [ ] ,
1774+ } ,
1775+ {
1776+ "@id" : "#ConstraintViolationList" ,
1777+ "@type" : "hydra:Class" ,
1778+ subClassOf : "hydra:Error" ,
1779+ "hydra:title" : "A constraint violation list" ,
1780+ "hydra:supportedProperty" : [ ] ,
1781+ } ,
1782+ ] ,
1783+ } ;
1784+
1785+ server . use (
1786+ http . get ( "http://localhost" , ( ) => Response . json ( enumEntrypoint , init ) ) ,
1787+ http . get ( "http://localhost/docs.jsonld" , ( ) =>
1788+ Response . json ( enumDocs , init ) ,
1789+ ) ,
1790+ ) ;
1791+
1792+ const data = await parseHydraDocumentation ( "http://localhost" ) ;
1793+ expect ( data . status ) . toBe ( 200 ) ;
1794+
1795+ const bookConditionResource = data . api . resources ?. find (
1796+ ( r ) => r . id === "http://localhost/docs.jsonld#BookCondition" ,
1797+ ) ;
1798+
1799+ expect ( bookConditionResource ) . toBeDefined ( ) ;
1800+ assert ( bookConditionResource !== undefined ) ;
1801+
1802+ expect ( bookConditionResource . name ) . toBe ( "book_conditions" ) ;
1803+ expect ( bookConditionResource . title ) . toBe ( "BookCondition" ) ;
1804+ expect ( bookConditionResource . url ) . toBe ( "http://localhost/book_conditions" ) ;
1805+
1806+ // Verify the field was parsed correctly
1807+ assert ( bookConditionResource . fields !== null ) ;
1808+ assert ( bookConditionResource . fields !== undefined ) ;
1809+ expect ( bookConditionResource . fields ) . toHaveLength ( 1 ) ;
1810+ expect ( bookConditionResource . fields [ 0 ] ?. name ) . toBe ( "value" ) ;
1811+ expect ( bookConditionResource . fields [ 0 ] ?. range ) . toBe (
1812+ "http://www.w3.org/2001/XMLSchema#string" ,
1813+ ) ;
1814+ expect ( bookConditionResource . fields [ 0 ] ?. required ) . toBe ( true ) ;
1815+
1816+ // Readable but not writable (read-only enum)
1817+ expect ( bookConditionResource . readableFields ) . toHaveLength ( 1 ) ;
1818+ expect ( bookConditionResource . writableFields ) . toHaveLength ( 0 ) ;
1819+
1820+ // Verify operations - only GET (item operation from supportedOperation)
1821+ assert ( bookConditionResource . operations !== null ) ;
1822+ assert ( bookConditionResource . operations !== undefined ) ;
1823+ expect ( bookConditionResource . operations ) . toHaveLength ( 1 ) ;
1824+ expect ( bookConditionResource . operations [ 0 ] ?. method ) . toBe ( "GET" ) ;
1825+
1826+ // Also verify the book resource still works (Strategy 1 still functions)
1827+ const bookResource = data . api . resources ?. find (
1828+ ( r ) => r . id === "http://schema.org/Book" ,
1829+ ) ;
1830+ expect ( bookResource ) . toBeDefined ( ) ;
1831+ expect ( bookResource ?. name ) . toBe ( "books" ) ;
1832+ } ) ;
1833+
1834+ test ( "parse a Hydra documentation with owl:equivalentClass without onProperty hydra:member" , async ( ) => {
1835+ const enumEntrypoint = {
1836+ "@context" : {
1837+ "@vocab" : "http://localhost/docs.jsonld#" ,
1838+ hydra : "http://www.w3.org/ns/hydra/core#" ,
1839+ bookCondition : {
1840+ "@id" : "Entrypoint/bookCondition" ,
1841+ "@type" : "@id" ,
1842+ } ,
1843+ } ,
1844+ "@id" : "/" ,
1845+ "@type" : "Entrypoint" ,
1846+ bookCondition : "/book_conditions" ,
1847+ } ;
1848+
1849+ const enumDocs = {
1850+ "@context" : {
1851+ "@vocab" : "http://localhost/docs.jsonld#" ,
1852+ hydra : "http://www.w3.org/ns/hydra/core#" ,
1853+ rdf : "http://www.w3.org/1999/02/22-rdf-syntax-ns#" ,
1854+ rdfs : "http://www.w3.org/2000/01/rdf-schema#" ,
1855+ xmls : "http://www.w3.org/2001/XMLSchema#" ,
1856+ owl : "http://www.w3.org/2002/07/owl#" ,
1857+ domain : {
1858+ "@id" : "rdfs:domain" ,
1859+ "@type" : "@id" ,
1860+ } ,
1861+ range : {
1862+ "@id" : "rdfs:range" ,
1863+ "@type" : "@id" ,
1864+ } ,
1865+ subClassOf : {
1866+ "@id" : "rdfs:subClassOf" ,
1867+ "@type" : "@id" ,
1868+ } ,
1869+ expects : {
1870+ "@id" : "hydra:expects" ,
1871+ "@type" : "@id" ,
1872+ } ,
1873+ returns : {
1874+ "@id" : "hydra:returns" ,
1875+ "@type" : "@id" ,
1876+ } ,
1877+ } ,
1878+ "@id" : "/docs.jsonld" ,
1879+ "hydra:title" : "API with enums" ,
1880+ "hydra:description" : "An API that exposes enum resources" ,
1881+ "hydra:entrypoint" : "/" ,
1882+ "hydra:supportedClass" : [
1883+ {
1884+ "@id" : "#BookCondition" ,
1885+ "@type" : "hydra:Class" ,
1886+ "rdfs:label" : "BookCondition" ,
1887+ "hydra:title" : "BookCondition" ,
1888+ "hydra:supportedProperty" : [
1889+ {
1890+ "@type" : "hydra:SupportedProperty" ,
1891+ "hydra:property" : {
1892+ "@id" : "#BookCondition/value" ,
1893+ "@type" : "rdf:Property" ,
1894+ "rdfs:label" : "value" ,
1895+ domain : "#BookCondition" ,
1896+ range : "xmls:string" ,
1897+ } ,
1898+ "hydra:title" : "value" ,
1899+ "hydra:required" : true ,
1900+ "hydra:readable" : true ,
1901+ "hydra:writeable" : false ,
1902+ } ,
1903+ ] ,
1904+ "hydra:supportedOperation" : [
1905+ {
1906+ "@type" : "hydra:Operation" ,
1907+ "hydra:method" : "GET" ,
1908+ "hydra:title" : "Retrieves BookCondition resource." ,
1909+ "rdfs:label" : "Retrieves BookCondition resource." ,
1910+ returns : "#BookCondition" ,
1911+ } ,
1912+ ] ,
1913+ } ,
1914+ {
1915+ "@id" : "#Entrypoint" ,
1916+ "@type" : "hydra:Class" ,
1917+ "hydra:title" : "The API entrypoint" ,
1918+ "hydra:supportedProperty" : [
1919+ {
1920+ "@type" : "hydra:SupportedProperty" ,
1921+ "hydra:property" : {
1922+ "@id" : "#Entrypoint/bookCondition" ,
1923+ "@type" : "hydra:Link" ,
1924+ domain : "#Entrypoint" ,
1925+ "rdfs:label" : "The collection of BookCondition resources" ,
1926+ "rdfs:range" : [
1927+ { "@id" : "hydra:Collection" } ,
1928+ {
1929+ "owl:equivalentClass" : {
1930+ "owl:allValuesFrom" : {
1931+ "@id" : "#BookCondition" ,
1932+ } ,
1933+ } ,
1934+ } ,
1935+ ] ,
1936+ } ,
1937+ "hydra:title" : "The collection of BookCondition resources" ,
1938+ "hydra:readable" : true ,
1939+ "hydra:writeable" : false ,
1940+ } ,
1941+ ] ,
1942+ "hydra:supportedOperation" : {
1943+ "@type" : "hydra:Operation" ,
1944+ "hydra:method" : "GET" ,
1945+ "rdfs:label" : "The API entrypoint." ,
1946+ returns : "#EntryPoint" ,
1947+ } ,
1948+ } ,
1949+ {
1950+ "@id" : "#ConstraintViolation" ,
1951+ "@type" : "hydra:Class" ,
1952+ "hydra:title" : "A constraint violation" ,
1953+ "hydra:supportedProperty" : [ ] ,
1954+ } ,
1955+ {
1956+ "@id" : "#ConstraintViolationList" ,
1957+ "@type" : "hydra:Class" ,
1958+ subClassOf : "hydra:Error" ,
1959+ "hydra:title" : "A constraint violation list" ,
1960+ "hydra:supportedProperty" : [ ] ,
1961+ } ,
1962+ ] ,
1963+ } ;
1964+
1965+ server . use (
1966+ http . get ( "http://localhost" , ( ) => Response . json ( enumEntrypoint , init ) ) ,
1967+ http . get ( "http://localhost/docs.jsonld" , ( ) =>
1968+ Response . json ( enumDocs , init ) ,
1969+ ) ,
1970+ ) ;
1971+
1972+ const data = await parseHydraDocumentation ( "http://localhost" ) ;
1973+ expect ( data . status ) . toBe ( 200 ) ;
1974+
1975+ const bookConditionResource = data . api . resources ?. find (
1976+ ( r ) => r . id === "http://localhost/docs.jsonld#BookCondition" ,
1977+ ) ;
1978+
1979+ expect ( bookConditionResource ) . toBeDefined ( ) ;
1980+ assert ( bookConditionResource !== undefined ) ;
1981+ expect ( bookConditionResource . name ) . toBe ( "book_conditions" ) ;
1982+ expect ( bookConditionResource . title ) . toBe ( "BookCondition" ) ;
1983+ } ) ;
0 commit comments