diff --git a/swh/indexer/codemeta.py b/swh/indexer/codemeta.py --- a/swh/indexer/codemeta.py +++ b/swh/indexer/codemeta.py @@ -9,6 +9,7 @@ import json import os.path import re +from typing import Any from pyld import jsonld @@ -33,6 +34,14 @@ FORGEFED_URI = "https://forgefed.org/ns#" ACTIVITYSTREAMS_URI = "https://www.w3.org/ns/activitystreams#" +COMPACT_CONTEXT: Any = [ + CODEMETA_CONTEXT_URL, + { + "as": ACTIVITYSTREAMS_URI, + "forge": FORGEFED_URI, + }, +] + PROPERTY_BLACKLIST = { # CodeMeta properties that we cannot properly represent. @@ -124,7 +133,9 @@ def compact(doc): """Same as `pyld.jsonld.compact`, but in the context of CodeMeta.""" return jsonld.compact( - doc, CODEMETA_CONTEXT_URL, options={"documentLoader": _document_loader} + doc, + COMPACT_CONTEXT, + options={"documentLoader": _document_loader}, ) diff --git a/swh/indexer/tests/metadata_dictionary/test_cff.py b/swh/indexer/tests/metadata_dictionary/test_cff.py --- a/swh/indexer/tests/metadata_dictionary/test_cff.py +++ b/swh/indexer/tests/metadata_dictionary/test_cff.py @@ -3,6 +3,7 @@ # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information +from swh.indexer.codemeta import COMPACT_CONTEXT from swh.indexer.metadata_dictionary import MAPPINGS @@ -45,7 +46,7 @@ ) expected = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "author": [ { @@ -157,7 +158,7 @@ ) expected = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "author": [ { @@ -202,7 +203,7 @@ ) expected = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "author": [ { diff --git a/swh/indexer/tests/metadata_dictionary/test_codemeta.py b/swh/indexer/tests/metadata_dictionary/test_codemeta.py --- a/swh/indexer/tests/metadata_dictionary/test_codemeta.py +++ b/swh/indexer/tests/metadata_dictionary/test_codemeta.py @@ -7,7 +7,7 @@ from hypothesis import HealthCheck, given, settings -from swh.indexer.codemeta import CODEMETA_TERMS +from swh.indexer.codemeta import CODEMETA_TERMS, COMPACT_CONTEXT from swh.indexer.metadata_detector import detect_metadata from swh.indexer.metadata_dictionary import MAPPINGS @@ -67,7 +67,7 @@ "programmingLanguage": "JSON-LD" }""" # noqa expected_result = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "identifier": "CodeMeta", "description": "CodeMeta is a concept vocabulary that can " @@ -129,7 +129,7 @@ "identifier": "CodeMeta" }""" # noqa expected_result = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "identifier": "CodeMeta", } diff --git a/swh/indexer/tests/metadata_dictionary/test_github.py b/swh/indexer/tests/metadata_dictionary/test_github.py --- a/swh/indexer/tests/metadata_dictionary/test_github.py +++ b/swh/indexer/tests/metadata_dictionary/test_github.py @@ -3,6 +3,7 @@ # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information +from swh.indexer.codemeta import COMPACT_CONTEXT from swh.indexer.metadata_dictionary import MAPPINGS @@ -111,11 +112,11 @@ """ result = MAPPINGS["GitHubMapping"]().translate(content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "https://forgefed.org/ns#Repository", - "https://forgefed.org/ns#forks": { - "https://www.w3.org/ns/activitystreams#totalItems": 1, - "type": "https://www.w3.org/ns/activitystreams#OrderedCollection", + "forge:forks": { + "as:totalItems": 1, + "type": "as:OrderedCollection", }, "license": "https://spdx.org/licenses/GPL-3.0", "name": "SoftwareHeritage/swh-indexer", diff --git a/swh/indexer/tests/metadata_dictionary/test_maven.py b/swh/indexer/tests/metadata_dictionary/test_maven.py --- a/swh/indexer/tests/metadata_dictionary/test_maven.py +++ b/swh/indexer/tests/metadata_dictionary/test_maven.py @@ -7,6 +7,7 @@ from hypothesis import HealthCheck, given, settings +from swh.indexer.codemeta import COMPACT_CONTEXT from swh.indexer.metadata_dictionary import MAPPINGS from ..utils import xml_document_strategy @@ -42,7 +43,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "Maven Default Project", "identifier": "com.mycompany.app", @@ -58,7 +59,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", } @@ -70,7 +71,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", } @@ -164,7 +165,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "Maven Default Project", "identifier": "com.mycompany.app", @@ -188,7 +189,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "Maven Default Project", "identifier": "com.mycompany.app", @@ -208,7 +209,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "Maven Default Project", "identifier": "com.mycompany.app", @@ -227,7 +228,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "identifier": "com.mycompany.app", "version": "1.2.3", @@ -248,7 +249,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "Maven Default Project", "identifier": "com.mycompany.app", @@ -265,7 +266,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "version": "1.2.3", } @@ -285,7 +286,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "Maven Default Project", "identifier": "com.mycompany.app", @@ -337,7 +338,7 @@ """ result = MAPPINGS["MavenMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "Maven Default Project", "identifier": "com.mycompany.app", diff --git a/swh/indexer/tests/metadata_dictionary/test_npm.py b/swh/indexer/tests/metadata_dictionary/test_npm.py --- a/swh/indexer/tests/metadata_dictionary/test_npm.py +++ b/swh/indexer/tests/metadata_dictionary/test_npm.py @@ -8,6 +8,7 @@ from hypothesis import HealthCheck, given, settings import pytest +from swh.indexer.codemeta import COMPACT_CONTEXT from swh.indexer.metadata_detector import detect_metadata from swh.indexer.metadata_dictionary import MAPPINGS from swh.indexer.storage.model import ContentMetadataRow @@ -55,7 +56,7 @@ } """ declared_metadata = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "test_metadata", "version": "0.0.2", @@ -86,7 +87,7 @@ } """ declared_metadata = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "test_metadata", "version": "0.0.2", @@ -123,7 +124,7 @@ id=hash_to_bytes("26a9f72a7c87cc9205725cfd879f514ff4f3d8d5"), tool=TRANSLATOR_TOOL, metadata={ - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "codeRepository": "git+https://github.com/moranegg/metadata_test", "description": "Simple package.json test for indexer", @@ -135,7 +136,7 @@ id=hash_to_bytes("d4c647f0fc257591cc9ba1722484229780d1c607"), tool=TRANSLATOR_TOOL, metadata={ - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "issueTracker": "https://github.com/npm/npm/issues", "author": [ @@ -180,7 +181,7 @@ }""" result = MAPPINGS["NpmMapping"]().translate(package_json) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "foo", "issueTracker": "https://github.com/owner/project/issues", "type": "SoftwareSourceCode", @@ -195,7 +196,7 @@ }""" result = MAPPINGS["NpmMapping"]().translate(package_json) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "foo", "type": "SoftwareSourceCode", } @@ -207,7 +208,7 @@ }""" result = MAPPINGS["NpmMapping"]().translate(package_json) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "foo", "issueTracker": "https://github.com/owner/project/issues", "type": "SoftwareSourceCode", @@ -225,7 +226,7 @@ }""" result = MAPPINGS["NpmMapping"]().translate(package_json) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "foo", "codeRepository": "git+https://github.com/npm/cli.git", "type": "SoftwareSourceCode", @@ -240,7 +241,7 @@ }""" result = MAPPINGS["NpmMapping"]().translate(package_json) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "foo", "type": "SoftwareSourceCode", } @@ -252,7 +253,7 @@ }""" result = MAPPINGS["NpmMapping"]().translate(package_json) expected_result = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "foo", "codeRepository": "git+https://github.com/npm/cli.git", "type": "SoftwareSourceCode", @@ -274,7 +275,7 @@ }""" result = MAPPINGS["NpmMapping"]().translate(package_json) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "foo", "codeRepository": "git+https://gitlab.com/user/repo.git", "type": "SoftwareSourceCode", diff --git a/swh/indexer/tests/metadata_dictionary/test_python.py b/swh/indexer/tests/metadata_dictionary/test_python.py --- a/swh/indexer/tests/metadata_dictionary/test_python.py +++ b/swh/indexer/tests/metadata_dictionary/test_python.py @@ -3,6 +3,7 @@ # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information +from swh.indexer.codemeta import COMPACT_CONTEXT from swh.indexer.metadata_dictionary import MAPPINGS @@ -52,7 +53,7 @@ ], result del result["description"] assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "url": "https://forge.softwareheritage.org/diffusion/DCORE/", "name": "swh.core", @@ -77,7 +78,7 @@ """ # noqa result = MAPPINGS["PythonPkginfoMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "snowpyt", "description": "foo\nHydrology N°83", @@ -92,7 +93,7 @@ """ # noqa result = MAPPINGS["PythonPkginfoMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "foo", "keywords": ["foo", "bar", "baz"], @@ -107,7 +108,7 @@ """ # noqa result = MAPPINGS["PythonPkginfoMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "foo", "license": "MIT", diff --git a/swh/indexer/tests/metadata_dictionary/test_ruby.py b/swh/indexer/tests/metadata_dictionary/test_ruby.py --- a/swh/indexer/tests/metadata_dictionary/test_ruby.py +++ b/swh/indexer/tests/metadata_dictionary/test_ruby.py @@ -5,6 +5,7 @@ from hypothesis import HealthCheck, given, settings, strategies +from swh.indexer.codemeta import COMPACT_CONTEXT from swh.indexer.metadata_dictionary import MAPPINGS @@ -28,7 +29,7 @@ "Much longer explanation of the example!", } assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "author": [{"type": "Person", "name": "Ruby Coder"}], "name": "example", @@ -57,7 +58,7 @@ ], ) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", } @@ -69,7 +70,7 @@ end""" result = MAPPINGS["GemspecMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", } raw_content = b""" @@ -78,7 +79,7 @@ end""" result = MAPPINGS["GemspecMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", } raw_content = b""" @@ -87,7 +88,7 @@ end""" result = MAPPINGS["GemspecMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "author": [{"type": "Person", "name": "Ruby Coder1"}], } @@ -104,7 +105,7 @@ """ result = MAPPINGS["GemspecMapping"]().translate(raw_content) assert result == { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "type": "SoftwareSourceCode", "name": "rb-system-with-aliases", "description": "execute system commands with aliases", diff --git a/swh/indexer/tests/test_codemeta.py b/swh/indexer/tests/test_codemeta.py --- a/swh/indexer/tests/test_codemeta.py +++ b/swh/indexer/tests/test_codemeta.py @@ -5,7 +5,12 @@ import pytest -from swh.indexer.codemeta import CROSSWALK_TABLE, merge_documents, merge_values +from swh.indexer.codemeta import ( + COMPACT_CONTEXT, + CROSSWALK_TABLE, + merge_documents, + merge_values, +) def test_crosstable(): @@ -61,21 +66,21 @@ # given metadata_list = [ { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "test_1", "version": "0.0.2", "description": "Simple package.json test for indexer", "codeRepository": "git+https://github.com/moranegg/metadata_test", }, { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "test_0_1", "version": "0.0.2", "description": "Simple package.json test for indexer", "codeRepository": "git+https://github.com/moranegg/metadata_test", }, { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "name": "test_metadata", "version": "0.0.2", "author": { @@ -90,7 +95,7 @@ # then expected_results = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "version": "0.0.2", "description": "Simple package.json test for indexer", "name": ["test_1", "test_0_1", "test_metadata"], @@ -104,12 +109,12 @@ # given metadata_list = [ { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "id": "http://example.org/test1", "name": "test_1", }, { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "id": "http://example.org/test2", "name": "test_2", }, @@ -120,7 +125,7 @@ # then expected_results = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "id": "http://example.org/test1", "schema:sameAs": "http://example.org/test2", "name": ["test_1", "test_2"], @@ -132,17 +137,17 @@ # given metadata_list = [ { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "id": "http://example.org/test1", "name": "test_1", }, { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "id": "http://example.org/test1", "name": "test_1b", }, { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "id": "http://example.org/test2", "name": "test_2", }, @@ -153,7 +158,7 @@ # then expected_results = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "id": "http://example.org/test1", "schema:sameAs": "http://example.org/test2", "name": ["test_1", "test_1b", "test_2"], @@ -166,7 +171,7 @@ # given metadata_list = [ { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": { "@list": [ {"name": "test_1"}, @@ -174,7 +179,7 @@ }, }, { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": { "@list": [ {"name": "test_2"}, @@ -188,7 +193,7 @@ # then expected_results = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": [ {"name": "test_1"}, {"name": "test_2"}, @@ -202,7 +207,7 @@ # given metadata_list = [ { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": { "@list": [ {"name": "test_1"}, @@ -210,7 +215,7 @@ }, }, { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": { "@list": [ {"name": "test_2"}, @@ -225,7 +230,7 @@ # then expected_results = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": [ {"name": "test_1"}, {"name": "test_2"}, @@ -239,11 +244,11 @@ # given metadata_list = [ { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": {"name": "test_1"}, }, { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": { "@list": [ {"name": "test_2"}, @@ -257,7 +262,7 @@ # then expected_results = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": [ {"name": "test_1"}, {"name": "test_2"}, @@ -271,7 +276,7 @@ # given metadata_list = [ { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": { "@list": [ {"name": "test_1"}, @@ -279,7 +284,7 @@ }, }, { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": {"name": "test_2"}, }, ] @@ -289,7 +294,7 @@ # then expected_results = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "author": [ {"name": "test_1"}, {"name": "test_2"}, diff --git a/swh/indexer/tests/test_metadata.py b/swh/indexer/tests/test_metadata.py --- a/swh/indexer/tests/test_metadata.py +++ b/swh/indexer/tests/test_metadata.py @@ -8,6 +8,7 @@ import attr +from swh.indexer.codemeta import COMPACT_CONTEXT from swh.indexer.metadata import ( ContentMetadataIndexer, DirectoryMetadataIndexer, @@ -223,8 +224,8 @@ id="https://example.org/jdoe/myrepo", tool={"id": tool["id"], **TRANSLATOR_TOOL}, metadata={ - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", - "type": "https://forgefed.org/ns#Repository", + "@context": COMPACT_CONTEXT, + "type": "forge:Repository", "name": "test software", }, from_remd_id=REMD.id, diff --git a/swh/indexer/tests/utils.py b/swh/indexer/tests/utils.py --- a/swh/indexer/tests/utils.py +++ b/swh/indexer/tests/utils.py @@ -12,6 +12,7 @@ from hypothesis import strategies from swh.core.api.classes import stream_results +from swh.indexer.codemeta import COMPACT_CONTEXT from swh.indexer.storage import INDEXER_CFG_KEY from swh.model import hashutil from swh.model.hashutil import hash_to_bytes @@ -453,7 +454,7 @@ YARN_PARSER_METADATA = { - "@context": "https://doi.org/10.5063/schema/codemeta-2.0", + "@context": COMPACT_CONTEXT, "url": "https://github.com/librariesio/yarn-parser#readme", "codeRepository": "git+git+https://github.com/librariesio/yarn-parser.git", "author": [{"type": "Person", "name": "Andrew Nesbitt"}],